mirror of
https://github.com/kaspanet/kaspad.git
synced 2026-02-25 21:01:44 +00:00
Compare commits
9 Commits
v0.8.2-dev
...
v0.8.3-rc1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b510fc08a7 | ||
|
|
dc3ae4d3ac | ||
|
|
1ebda36b17 | ||
|
|
12379bedb6 | ||
|
|
f90d7d796a | ||
|
|
fddda46d4f | ||
|
|
77adb6c99f | ||
|
|
48e1a2c396 | ||
|
|
6926a7ab81 |
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -201,7 +201,7 @@ func (flow *handleRelayInvsFlow) readMsgBlock() (msgBlock *appmessage.MsgBlock,
|
||||
|
||||
func (flow *handleRelayInvsFlow) processBlock(block *externalapi.DomainBlock) ([]*externalapi.DomainHash, error) {
|
||||
blockHash := consensushashing.BlockHash(block)
|
||||
err := flow.Domain().Consensus().ValidateAndInsertBlock(block)
|
||||
_, err := flow.Domain().Consensus().ValidateAndInsertBlock(block)
|
||||
if err != nil {
|
||||
if !errors.As(err, &ruleerrors.RuleError{}) {
|
||||
return nil, errors.Wrapf(err, "failed to process block %s", blockHash)
|
||||
@@ -212,7 +212,6 @@ func (flow *handleRelayInvsFlow) processBlock(block *externalapi.DomainBlock) ([
|
||||
return missingParentsError.MissingParentHashes, nil
|
||||
}
|
||||
log.Warnf("Rejected block %s from %s: %s", blockHash, flow.peer, err)
|
||||
|
||||
return nil, protocolerrors.Wrapf(true, err, "got invalid block %s from relay", blockHash)
|
||||
}
|
||||
return nil, nil
|
||||
|
||||
@@ -35,7 +35,7 @@ func (flow *handleRelayInvsFlow) runIBDIfNotRunning(highHash *externalapi.Domain
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if syncInfo.State == externalapi.SyncStateAwaitingUTXOSet {
|
||||
if syncInfo.IsAwaitingUTXOSet {
|
||||
found, err := flow.fetchMissingUTXOSet(syncInfo.IBDRootUTXOBlockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -178,7 +178,7 @@ func (flow *handleRelayInvsFlow) processHeader(msgBlockHeader *appmessage.MsgBlo
|
||||
log.Debugf("Block header %s is already in the DAG. Skipping...", blockHash)
|
||||
return nil
|
||||
}
|
||||
err = flow.Domain().Consensus().ValidateAndInsertBlock(block)
|
||||
_, err = flow.Domain().Consensus().ValidateAndInsertBlock(block)
|
||||
if err != nil {
|
||||
if !errors.As(err, &ruleerrors.RuleError{}) {
|
||||
return errors.Wrapf(err, "failed to process header %s during IBD", blockHash)
|
||||
@@ -190,8 +190,8 @@ func (flow *handleRelayInvsFlow) processHeader(msgBlockHeader *appmessage.MsgBlo
|
||||
return nil
|
||||
}
|
||||
|
||||
func (flow *handleRelayInvsFlow) fetchMissingUTXOSet(ibdRootHash *externalapi.DomainHash) (bool, error) {
|
||||
err := flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestIBDRootUTXOSetAndBlock(ibdRootHash))
|
||||
func (flow *handleRelayInvsFlow) fetchMissingUTXOSet(ibdRootHash *externalapi.DomainHash) (succeed bool, err error) {
|
||||
err = flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestIBDRootUTXOSetAndBlock(ibdRootHash))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -205,17 +205,23 @@ func (flow *handleRelayInvsFlow) fetchMissingUTXOSet(ibdRootHash *externalapi.Do
|
||||
return false, nil
|
||||
}
|
||||
|
||||
err = flow.Domain().Consensus().ValidateAndInsertBlock(block)
|
||||
if err != nil {
|
||||
blockHash := consensushashing.BlockHash(block)
|
||||
return false, protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "got invalid block %s during IBD", blockHash)
|
||||
}
|
||||
|
||||
err = flow.Domain().Consensus().SetPruningPointUTXOSet(utxoSet)
|
||||
err = flow.Domain().Consensus().ValidateAndInsertPruningPoint(block, utxoSet)
|
||||
if err != nil {
|
||||
return false, protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "error with IBD root UTXO set")
|
||||
}
|
||||
|
||||
syncInfo, err := flow.Domain().Consensus().GetSyncInfo()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// TODO: Find a better way to deal with finality conflicts.
|
||||
if syncInfo.IsAwaitingUTXOSet {
|
||||
log.Warnf("Still awaiting for UTXO set. This can happen only because the given pruning point violates " +
|
||||
"finality. If this keeps happening delete the data directory and restart your node.")
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -277,7 +283,7 @@ func (flow *handleRelayInvsFlow) syncMissingBlockBodies(highHash *externalapi.Do
|
||||
return protocolerrors.Errorf(true, "expected block %s but got %s", expectedHash, blockHash)
|
||||
}
|
||||
|
||||
err = flow.Domain().Consensus().ValidateAndInsertBlock(block)
|
||||
_, err = flow.Domain().Consensus().ValidateAndInsertBlock(block)
|
||||
if err != nil {
|
||||
return protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "invalid block %s", blockHash)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
type consensus struct {
|
||||
lock *sync.Mutex
|
||||
databaseContext model.DBReader
|
||||
databaseContext model.DBManager
|
||||
|
||||
blockProcessor model.BlockProcessor
|
||||
blockBuilder model.BlockBuilder
|
||||
@@ -25,25 +25,25 @@ type consensus struct {
|
||||
dagTraversalManager model.DAGTraversalManager
|
||||
difficultyManager model.DifficultyManager
|
||||
ghostdagManager model.GHOSTDAGManager
|
||||
headerTipsManager model.HeaderTipsManager
|
||||
headerTipsManager model.HeadersSelectedTipManager
|
||||
mergeDepthManager model.MergeDepthManager
|
||||
pruningManager model.PruningManager
|
||||
reachabilityManager model.ReachabilityManager
|
||||
finalityManager model.FinalityManager
|
||||
|
||||
acceptanceDataStore model.AcceptanceDataStore
|
||||
blockStore model.BlockStore
|
||||
blockHeaderStore model.BlockHeaderStore
|
||||
pruningStore model.PruningStore
|
||||
ghostdagDataStore model.GHOSTDAGDataStore
|
||||
blockRelationStore model.BlockRelationStore
|
||||
blockStatusStore model.BlockStatusStore
|
||||
consensusStateStore model.ConsensusStateStore
|
||||
headerTipsStore model.HeaderTipsStore
|
||||
multisetStore model.MultisetStore
|
||||
reachabilityDataStore model.ReachabilityDataStore
|
||||
utxoDiffStore model.UTXODiffStore
|
||||
finalityStore model.FinalityStore
|
||||
acceptanceDataStore model.AcceptanceDataStore
|
||||
blockStore model.BlockStore
|
||||
blockHeaderStore model.BlockHeaderStore
|
||||
pruningStore model.PruningStore
|
||||
ghostdagDataStore model.GHOSTDAGDataStore
|
||||
blockRelationStore model.BlockRelationStore
|
||||
blockStatusStore model.BlockStatusStore
|
||||
consensusStateStore model.ConsensusStateStore
|
||||
headersSelectedTipStore model.HeaderSelectedTipStore
|
||||
multisetStore model.MultisetStore
|
||||
reachabilityDataStore model.ReachabilityDataStore
|
||||
utxoDiffStore model.UTXODiffStore
|
||||
finalityStore model.FinalityStore
|
||||
}
|
||||
|
||||
// BuildBlock builds a block over the current state, with the transactions
|
||||
@@ -59,7 +59,7 @@ func (s *consensus) BuildBlock(coinbaseData *externalapi.DomainCoinbaseData,
|
||||
|
||||
// ValidateAndInsertBlock validates the given block and, if valid, applies it
|
||||
// to the current state
|
||||
func (s *consensus) ValidateAndInsertBlock(block *externalapi.DomainBlock) error {
|
||||
func (s *consensus) ValidateAndInsertBlock(block *externalapi.DomainBlock) (*externalapi.BlockInsertionResult, error) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
@@ -138,12 +138,6 @@ func (s *consensus) GetBlockInfo(blockHash *externalapi.DomainHash) (*externalap
|
||||
|
||||
blockInfo.BlueScore = ghostdagData.BlueScore()
|
||||
|
||||
isBlockInHeaderPruningPointFuture, err := s.syncManager.IsBlockInHeaderPruningPointFuture(blockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockInfo.IsBlockInHeaderPruningPointFuture = isBlockInHeaderPruningPointFuture
|
||||
|
||||
return blockInfo, nil
|
||||
}
|
||||
|
||||
@@ -183,11 +177,11 @@ func (s *consensus) GetPruningPointUTXOSet(expectedPruningPointHash *externalapi
|
||||
return serializedUTXOSet, nil
|
||||
}
|
||||
|
||||
func (s *consensus) SetPruningPointUTXOSet(serializedUTXOSet []byte) error {
|
||||
func (s *consensus) ValidateAndInsertPruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
return s.consensusStateManager.SetPruningPointUTXOSet(serializedUTXOSet)
|
||||
return s.blockProcessor.ValidateAndInsertPruningPoint(newPruningPoint, serializedUTXOSet)
|
||||
}
|
||||
|
||||
func (s *consensus) GetVirtualSelectedParent() (*externalapi.DomainBlock, error) {
|
||||
@@ -201,27 +195,6 @@ func (s *consensus) GetVirtualSelectedParent() (*externalapi.DomainBlock, error)
|
||||
return s.blockStore.Block(s.databaseContext, virtualGHOSTDAGData.SelectedParent())
|
||||
}
|
||||
|
||||
func (s *consensus) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) (externalapi.BlockLocator, error) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
return s.syncManager.CreateBlockLocator(lowHash, highHash, limit)
|
||||
}
|
||||
|
||||
func (s *consensus) FindNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) (lowHash, highHash *externalapi.DomainHash, err error) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
return s.syncManager.FindNextBlockLocatorBoundaries(blockLocator)
|
||||
}
|
||||
|
||||
func (s *consensus) GetSyncInfo() (*externalapi.SyncInfo, error) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
return s.syncManager.GetSyncInfo()
|
||||
}
|
||||
|
||||
func (s *consensus) Tips() ([]*externalapi.DomainHash, error) {
|
||||
return s.consensusStateStore.Tips(s.databaseContext)
|
||||
}
|
||||
@@ -246,3 +219,24 @@ func (s *consensus) GetVirtualInfo() (*externalapi.VirtualInfo, error) {
|
||||
PastMedianTime: pastMedianTime,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *consensus) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) (externalapi.BlockLocator, error) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
return s.syncManager.CreateBlockLocator(lowHash, highHash, limit)
|
||||
}
|
||||
|
||||
func (s *consensus) FindNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) (lowHash, highHash *externalapi.DomainHash, err error) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
return s.syncManager.FindNextBlockLocatorBoundaries(blockLocator)
|
||||
}
|
||||
|
||||
func (s *consensus) GetSyncInfo() (*externalapi.SyncInfo, error) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
return s.syncManager.GetSyncInfo()
|
||||
}
|
||||
|
||||
@@ -19,14 +19,14 @@ func TestConsensus_GetBlockInfo(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown()
|
||||
defer teardown(false)
|
||||
|
||||
invalidBlock, _, err := consensus.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
invalidBlock.Header.TimeInMilliseconds = 0
|
||||
err = consensus.ValidateAndInsertBlock(invalidBlock)
|
||||
_, err = consensus.ValidateAndInsertBlock(invalidBlock)
|
||||
if !errors.Is(err, ruleerrors.ErrTimeTooOld) {
|
||||
t.Fatalf("Expected block to be invalid with err: %v, instead found: %v", ruleerrors.ErrTimeTooOld, err)
|
||||
}
|
||||
@@ -42,9 +42,6 @@ func TestConsensus_GetBlockInfo(t *testing.T) {
|
||||
if info.BlockStatus != externalapi.StatusInvalid {
|
||||
t.Fatalf("Expected block status: %s, instead got: %s", externalapi.StatusInvalid, info.BlockStatus)
|
||||
}
|
||||
if info.IsBlockInHeaderPruningPointFuture != false {
|
||||
t.Fatalf("Expected IsBlockInHeaderPruningPointFuture=false, instead found: %t", info.IsBlockInHeaderPruningPointFuture)
|
||||
}
|
||||
|
||||
emptyCoinbase := externalapi.DomainCoinbaseData{}
|
||||
validBlock, err := consensus.BuildBlock(&emptyCoinbase, nil)
|
||||
@@ -52,7 +49,7 @@ func TestConsensus_GetBlockInfo(t *testing.T) {
|
||||
t.Fatalf("consensus.BuildBlock with an empty coinbase shouldn't fail: %v", err)
|
||||
}
|
||||
|
||||
err = consensus.ValidateAndInsertBlock(validBlock)
|
||||
_, err = consensus.ValidateAndInsertBlock(validBlock)
|
||||
if err != nil {
|
||||
t.Fatalf("consensus.ValidateAndInsertBlock with a block straight from consensus.BuildBlock should not fail: %v", err)
|
||||
}
|
||||
@@ -68,9 +65,6 @@ func TestConsensus_GetBlockInfo(t *testing.T) {
|
||||
if info.BlockStatus != externalapi.StatusValid {
|
||||
t.Fatalf("Expected block status: %s, instead got: %s", externalapi.StatusValid, info.BlockStatus)
|
||||
}
|
||||
if info.IsBlockInHeaderPruningPointFuture != true {
|
||||
t.Fatalf("Expected IsBlockInHeaderPruningPointFuture=true, instead found: %t", info.IsBlockInHeaderPruningPointFuture)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/consensusstatestore"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/finalitystore"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/ghostdagdatastore"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/headertipsstore"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/headersselectedtipstore"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/multisetstore"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/pruningstore"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/reachabilitydatastore"
|
||||
@@ -32,7 +32,7 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/processes/dagtopologymanager"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/processes/difficultymanager"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/processes/headertipsmanager"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/processes/headersselectedtipmanager"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/processes/mergedepthmanager"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/processes/pastmediantimemanager"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/processes/pruningmanager"
|
||||
@@ -47,9 +47,10 @@ import (
|
||||
// Factory instantiates new Consensuses
|
||||
type Factory interface {
|
||||
NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (externalapi.Consensus, error)
|
||||
NewTestConsensus(dagParams *dagconfig.Params, testName string) (tc testapi.TestConsensus, teardown func(), err error)
|
||||
NewTestConsensus(dagParams *dagconfig.Params, testName string) (
|
||||
tc testapi.TestConsensus, teardown func(keepDataDir bool), err error)
|
||||
NewTestConsensusWithDataDir(dagParams *dagconfig.Params, dataDir string) (
|
||||
tc testapi.TestConsensus, teardown func(), err error)
|
||||
tc testapi.TestConsensus, teardown func(keepDataDir bool), err error)
|
||||
}
|
||||
|
||||
type factory struct{}
|
||||
@@ -81,7 +82,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
|
||||
utxoDiffStore := utxodiffstore.New(200)
|
||||
consensusStateStore := consensusstatestore.New()
|
||||
ghostdagDataStore := ghostdagdatastore.New(10_000)
|
||||
headerTipsStore := headertipsstore.New()
|
||||
headersSelectedTipStore := headersselectedtipstore.New()
|
||||
finalityStore := finalitystore.New(200)
|
||||
|
||||
// Processes
|
||||
@@ -139,7 +140,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
|
||||
dagParams.CoinbasePayloadScriptPublicKeyMaxLength,
|
||||
ghostdagDataStore,
|
||||
acceptanceDataStore)
|
||||
headerTipsManager := headertipsmanager.New(dbManager, dagTopologyManager, ghostdagManager, headerTipsStore)
|
||||
headerTipsManager := headersselectedtipmanager.New(dbManager, dagTopologyManager, ghostdagManager, headersSelectedTipStore)
|
||||
genesisHash := dagParams.GenesisHash
|
||||
finalityManager := finalitymanager.New(
|
||||
dbManager,
|
||||
@@ -211,7 +212,8 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
|
||||
blockRelationStore,
|
||||
acceptanceDataStore,
|
||||
blockHeaderStore,
|
||||
headerTipsStore)
|
||||
headersSelectedTipStore,
|
||||
pruningStore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -225,6 +227,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
|
||||
ghostdagDataStore,
|
||||
pruningStore,
|
||||
blockStatusStore,
|
||||
headersSelectedTipStore,
|
||||
multisetStore,
|
||||
acceptanceDataStore,
|
||||
blockStore,
|
||||
@@ -236,17 +239,16 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
|
||||
syncManager := syncmanager.New(
|
||||
dbManager,
|
||||
genesisHash,
|
||||
dagParams.TargetTimePerBlock.Milliseconds(),
|
||||
dagTraversalManager,
|
||||
dagTopologyManager,
|
||||
ghostdagManager,
|
||||
consensusStateManager,
|
||||
pruningManager,
|
||||
|
||||
ghostdagDataStore,
|
||||
blockStatusStore,
|
||||
blockHeaderStore,
|
||||
headerTipsStore,
|
||||
blockStore)
|
||||
blockStore,
|
||||
pruningStore)
|
||||
|
||||
blockBuilder := blockbuilder.New(
|
||||
dbManager,
|
||||
@@ -287,7 +289,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
|
||||
reachabilityDataStore,
|
||||
utxoDiffStore,
|
||||
blockHeaderStore,
|
||||
headerTipsStore,
|
||||
headersSelectedTipStore,
|
||||
finalityStore)
|
||||
|
||||
c := &consensus{
|
||||
@@ -312,19 +314,19 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
|
||||
reachabilityManager: reachabilityManager,
|
||||
finalityManager: finalityManager,
|
||||
|
||||
acceptanceDataStore: acceptanceDataStore,
|
||||
blockStore: blockStore,
|
||||
blockHeaderStore: blockHeaderStore,
|
||||
pruningStore: pruningStore,
|
||||
ghostdagDataStore: ghostdagDataStore,
|
||||
blockStatusStore: blockStatusStore,
|
||||
blockRelationStore: blockRelationStore,
|
||||
consensusStateStore: consensusStateStore,
|
||||
headerTipsStore: headerTipsStore,
|
||||
multisetStore: multisetStore,
|
||||
reachabilityDataStore: reachabilityDataStore,
|
||||
utxoDiffStore: utxoDiffStore,
|
||||
finalityStore: finalityStore,
|
||||
acceptanceDataStore: acceptanceDataStore,
|
||||
blockStore: blockStore,
|
||||
blockHeaderStore: blockHeaderStore,
|
||||
pruningStore: pruningStore,
|
||||
ghostdagDataStore: ghostdagDataStore,
|
||||
blockStatusStore: blockStatusStore,
|
||||
blockRelationStore: blockRelationStore,
|
||||
consensusStateStore: consensusStateStore,
|
||||
headersSelectedTipStore: headersSelectedTipStore,
|
||||
multisetStore: multisetStore,
|
||||
reachabilityDataStore: reachabilityDataStore,
|
||||
utxoDiffStore: utxoDiffStore,
|
||||
finalityStore: finalityStore,
|
||||
}
|
||||
|
||||
genesisInfo, err := c.GetBlockInfo(genesisHash)
|
||||
@@ -333,7 +335,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
|
||||
}
|
||||
|
||||
if !genesisInfo.Exists {
|
||||
err = c.ValidateAndInsertBlock(dagParams.GenesisBlock)
|
||||
_, err = c.ValidateAndInsertBlock(dagParams.GenesisBlock)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -343,7 +345,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
|
||||
}
|
||||
|
||||
func (f *factory) NewTestConsensus(dagParams *dagconfig.Params, testName string) (
|
||||
tc testapi.TestConsensus, teardown func(), err error) {
|
||||
tc testapi.TestConsensus, teardown func(keepDataDir bool), err error) {
|
||||
|
||||
dataDir, err := ioutil.TempDir("", testName)
|
||||
if err != nil {
|
||||
@@ -354,7 +356,7 @@ func (f *factory) NewTestConsensus(dagParams *dagconfig.Params, testName string)
|
||||
}
|
||||
|
||||
func (f *factory) NewTestConsensusWithDataDir(dagParams *dagconfig.Params, dataDir string) (
|
||||
tc testapi.TestConsensus, teardown func(), err error) {
|
||||
tc testapi.TestConsensus, teardown func(keepDataDir bool), err error) {
|
||||
|
||||
db, err := ldb.NewLevelDB(dataDir)
|
||||
if err != nil {
|
||||
@@ -379,9 +381,14 @@ func (f *factory) NewTestConsensusWithDataDir(dagParams *dagconfig.Params, dataD
|
||||
testTransactionValidator: testTransactionValidator,
|
||||
}
|
||||
tstConsensus.testBlockBuilder = blockbuilder.NewTestBlockBuilder(consensusAsImplementation.blockBuilder, tstConsensus)
|
||||
teardown = func() {
|
||||
teardown = func(keepDataDir bool) {
|
||||
db.Close()
|
||||
os.RemoveAll(dataDir)
|
||||
if !keepDataDir {
|
||||
err := os.RemoveAll(dataDir)
|
||||
if err != nil {
|
||||
log.Errorf("Error removing data directory for test consensus: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tstConsensus, teardown, nil
|
||||
|
||||
@@ -24,7 +24,7 @@ func TestFinality(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown()
|
||||
defer teardown(false)
|
||||
|
||||
buildAndInsertBlock := func(parentHashes []*externalapi.DomainHash) (*externalapi.DomainBlock, error) {
|
||||
block, _, err := consensus.BuildBlockWithParents(parentHashes, nil, nil)
|
||||
@@ -32,7 +32,7 @@ func TestFinality(t *testing.T) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = consensus.ValidateAndInsertBlock(block)
|
||||
_, err = consensus.ValidateAndInsertBlock(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -190,7 +190,7 @@ func TestBoundedMergeDepth(t *testing.T) {
|
||||
return nil, false // fo some reason go doesn't recognize that t.Fatalf never returns
|
||||
}
|
||||
|
||||
err = consensus.ValidateAndInsertBlock(block)
|
||||
_, err = consensus.ValidateAndInsertBlock(block)
|
||||
if err == nil {
|
||||
return block, false
|
||||
} else if errors.Is(err, ruleerrors.ErrViolatingBoundedMergeDepth) {
|
||||
@@ -202,7 +202,7 @@ func TestBoundedMergeDepth(t *testing.T) {
|
||||
}
|
||||
|
||||
processBlock := func(consensus testapi.TestConsensus, block *externalapi.DomainBlock, name string) {
|
||||
err := consensus.ValidateAndInsertBlock(block)
|
||||
_, err := consensus.ValidateAndInsertBlock(block)
|
||||
if err != nil {
|
||||
t.Fatalf("TestBoundedMergeDepth: %s got unexpected error from ProcessBlock: %+v", name, err)
|
||||
|
||||
@@ -214,7 +214,7 @@ func TestBoundedMergeDepth(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("TestBoundedMergeDepth: Failed building block: %v", err)
|
||||
}
|
||||
err = consensus.ValidateAndInsertBlock(block)
|
||||
_, err = consensus.ValidateAndInsertBlock(block)
|
||||
if err != nil {
|
||||
t.Fatalf("TestBoundedMergeDepth: Failed Inserting block to consensus: %v", err)
|
||||
}
|
||||
@@ -241,7 +241,7 @@ func TestBoundedMergeDepth(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("TestBoundedMergeDepth: Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardownFunc2()
|
||||
defer teardownFunc2(false)
|
||||
|
||||
// Create a block on top on genesis
|
||||
block1 := buildAndInsertBlock(consensusBuild, []*externalapi.DomainHash{params.GenesisHash})
|
||||
@@ -266,7 +266,7 @@ func TestBoundedMergeDepth(t *testing.T) {
|
||||
}
|
||||
|
||||
// Teardown and assign nil to make sure we use the right DAG from here on.
|
||||
teardownFunc1()
|
||||
teardownFunc1(false)
|
||||
consensusBuild = nil
|
||||
|
||||
// Now test against the real DAG
|
||||
|
||||
7
domain/consensus/log.go
Normal file
7
domain/consensus/log.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package consensus
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
)
|
||||
|
||||
var log, _ = logger.Get(logger.SubsystemTags.BDAG)
|
||||
@@ -5,6 +5,4 @@ type BlockInfo struct {
|
||||
Exists bool
|
||||
BlockStatus BlockStatus
|
||||
BlueScore uint64
|
||||
|
||||
IsBlockInHeaderPruningPointFuture bool
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package externalapi
|
||||
// Consensus maintains the current core state of the node
|
||||
type Consensus interface {
|
||||
BuildBlock(coinbaseData *DomainCoinbaseData, transactions []*DomainTransaction) (*DomainBlock, error)
|
||||
ValidateAndInsertBlock(block *DomainBlock) error
|
||||
ValidateAndInsertBlock(block *DomainBlock) (*BlockInsertionResult, error)
|
||||
ValidateTransactionAndPopulateWithConsensusData(transaction *DomainTransaction) error
|
||||
|
||||
GetBlock(blockHash *DomainHash) (*DomainBlock, error)
|
||||
@@ -13,7 +13,7 @@ type Consensus interface {
|
||||
GetHashesBetween(lowHash, highHash *DomainHash) ([]*DomainHash, error)
|
||||
GetMissingBlockBodyHashes(highHash *DomainHash) ([]*DomainHash, error)
|
||||
GetPruningPointUTXOSet(expectedPruningPointHash *DomainHash) ([]byte, error)
|
||||
SetPruningPointUTXOSet(serializedUTXOSet []byte) error
|
||||
ValidateAndInsertPruningPoint(newPruningPoint *DomainBlock, serializedUTXOSet []byte) error
|
||||
GetVirtualSelectedParent() (*DomainBlock, error)
|
||||
CreateBlockLocator(lowHash, highHash *DomainHash, limit uint32) (BlockLocator, error)
|
||||
FindNextBlockLocatorBoundaries(blockLocator BlockLocator) (lowHash, highHash *DomainHash, err error)
|
||||
|
||||
12
domain/consensus/model/externalapi/insertblockresult.go
Normal file
12
domain/consensus/model/externalapi/insertblockresult.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package externalapi
|
||||
|
||||
// BlockInsertionResult is auxiliary data returned from ValidateAndInsertBlock
|
||||
type BlockInsertionResult struct {
|
||||
SelectedParentChainChanges *SelectedParentChainChanges
|
||||
}
|
||||
|
||||
// SelectedParentChainChanges is the set of changes made to the selected parent chain
|
||||
type SelectedParentChainChanges struct {
|
||||
Added []*DomainHash
|
||||
Removed []*DomainHash
|
||||
}
|
||||
@@ -1,37 +1,8 @@
|
||||
package externalapi
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Each of the following represent one of the possible sync
|
||||
// states of the consensus
|
||||
const (
|
||||
SyncStateSynced SyncState = iota
|
||||
SyncStateAwaitingGenesis
|
||||
SyncStateAwaitingUTXOSet
|
||||
SyncStateAwaitingBlockBodies
|
||||
)
|
||||
|
||||
// SyncState represents the current sync state of the consensus
|
||||
type SyncState uint8
|
||||
|
||||
func (s SyncState) String() string {
|
||||
switch s {
|
||||
case SyncStateSynced:
|
||||
return "SyncStateSynced"
|
||||
case SyncStateAwaitingGenesis:
|
||||
return "SyncStateAwaitingGenesis"
|
||||
case SyncStateAwaitingUTXOSet:
|
||||
return "SyncStateAwaitingUTXOSet"
|
||||
case SyncStateAwaitingBlockBodies:
|
||||
return "SyncStateAwaitingBlockBodies"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("<unknown state (%d)>", s)
|
||||
}
|
||||
|
||||
// SyncInfo holds info about the current sync state of the consensus
|
||||
type SyncInfo struct {
|
||||
State SyncState
|
||||
IsAwaitingUTXOSet bool
|
||||
IBDRootUTXOBlockHash *DomainHash
|
||||
HeaderCount uint64
|
||||
BlockCount uint64
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -4,5 +4,6 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
|
||||
// BlockProcessor is responsible for processing incoming blocks
|
||||
type BlockProcessor interface {
|
||||
ValidateAndInsertBlock(block *externalapi.DomainBlock) error
|
||||
ValidateAndInsertBlock(block *externalapi.DomainBlock) (*externalapi.BlockInsertionResult, error)
|
||||
ValidateAndInsertPruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error
|
||||
}
|
||||
|
||||
@@ -4,10 +4,9 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
|
||||
// ConsensusStateManager manages the node's consensus state
|
||||
type ConsensusStateManager interface {
|
||||
AddBlockToVirtual(blockHash *externalapi.DomainHash) error
|
||||
AddBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error)
|
||||
PopulateTransactionWithUTXOEntries(transaction *externalapi.DomainTransaction) error
|
||||
SetPruningPointUTXOSet(serializedUTXOSet []byte) error
|
||||
UpdatePruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error
|
||||
RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) (ReadOnlyUTXOSetIterator, error)
|
||||
HeaderTipsPruningPoint() (*externalapi.DomainHash, error)
|
||||
CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) (UTXODiff, AcceptanceData, Multiset, error)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ type TestConsensus interface {
|
||||
externalapi.Consensus
|
||||
|
||||
DAGParams() *dagconfig.Params
|
||||
DatabaseContext() model.DBReader
|
||||
DatabaseContext() model.DBManager
|
||||
|
||||
BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData,
|
||||
transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, model.UTXODiff, error)
|
||||
@@ -19,7 +19,7 @@ type TestConsensus interface {
|
||||
// AddBlock builds a block with given information, solves it, and adds to the DAG.
|
||||
// Returns the hash of the added block
|
||||
AddBlock(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData,
|
||||
transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, error)
|
||||
transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, *externalapi.BlockInsertionResult, error)
|
||||
|
||||
DiscardAllStores()
|
||||
|
||||
@@ -30,7 +30,7 @@ type TestConsensus interface {
|
||||
BlockStore() model.BlockStore
|
||||
ConsensusStateStore() model.ConsensusStateStore
|
||||
GHOSTDAGDataStore() model.GHOSTDAGDataStore
|
||||
HeaderTipsStore() model.HeaderTipsStore
|
||||
HeaderTipsStore() model.HeaderSelectedTipStore
|
||||
MultisetStore() model.MultisetStore
|
||||
PruningStore() model.PruningStore
|
||||
ReachabilityDataStore() model.ReachabilityDataStore
|
||||
@@ -46,7 +46,7 @@ type TestConsensus interface {
|
||||
DAGTraversalManager() model.DAGTraversalManager
|
||||
DifficultyManager() model.DifficultyManager
|
||||
GHOSTDAGManager() model.GHOSTDAGManager
|
||||
HeaderTipsManager() model.HeaderTipsManager
|
||||
HeaderTipsManager() model.HeadersSelectedTipManager
|
||||
MergeDepthManager() model.MergeDepthManager
|
||||
PastMedianTimeManager() model.PastMedianTimeManager
|
||||
PruningManager() model.PruningManager
|
||||
|
||||
@@ -21,22 +21,22 @@ type blockProcessor struct {
|
||||
ghostdagManager model.GHOSTDAGManager
|
||||
pastMedianTimeManager model.PastMedianTimeManager
|
||||
coinbaseManager model.CoinbaseManager
|
||||
headerTipsManager model.HeaderTipsManager
|
||||
headerTipsManager model.HeadersSelectedTipManager
|
||||
syncManager model.SyncManager
|
||||
|
||||
acceptanceDataStore model.AcceptanceDataStore
|
||||
blockStore model.BlockStore
|
||||
blockStatusStore model.BlockStatusStore
|
||||
blockRelationStore model.BlockRelationStore
|
||||
multisetStore model.MultisetStore
|
||||
ghostdagDataStore model.GHOSTDAGDataStore
|
||||
consensusStateStore model.ConsensusStateStore
|
||||
pruningStore model.PruningStore
|
||||
reachabilityDataStore model.ReachabilityDataStore
|
||||
utxoDiffStore model.UTXODiffStore
|
||||
blockHeaderStore model.BlockHeaderStore
|
||||
headerTipsStore model.HeaderTipsStore
|
||||
finalityStore model.FinalityStore
|
||||
acceptanceDataStore model.AcceptanceDataStore
|
||||
blockStore model.BlockStore
|
||||
blockStatusStore model.BlockStatusStore
|
||||
blockRelationStore model.BlockRelationStore
|
||||
multisetStore model.MultisetStore
|
||||
ghostdagDataStore model.GHOSTDAGDataStore
|
||||
consensusStateStore model.ConsensusStateStore
|
||||
pruningStore model.PruningStore
|
||||
reachabilityDataStore model.ReachabilityDataStore
|
||||
utxoDiffStore model.UTXODiffStore
|
||||
blockHeaderStore model.BlockHeaderStore
|
||||
headersSelectedTipStore model.HeaderSelectedTipStore
|
||||
finalityStore model.FinalityStore
|
||||
|
||||
stores []model.Store
|
||||
}
|
||||
@@ -54,7 +54,7 @@ func New(
|
||||
pastMedianTimeManager model.PastMedianTimeManager,
|
||||
ghostdagManager model.GHOSTDAGManager,
|
||||
coinbaseManager model.CoinbaseManager,
|
||||
headerTipsManager model.HeaderTipsManager,
|
||||
headerTipsManager model.HeadersSelectedTipManager,
|
||||
syncManager model.SyncManager,
|
||||
|
||||
acceptanceDataStore model.AcceptanceDataStore,
|
||||
@@ -68,7 +68,7 @@ func New(
|
||||
reachabilityDataStore model.ReachabilityDataStore,
|
||||
utxoDiffStore model.UTXODiffStore,
|
||||
blockHeaderStore model.BlockHeaderStore,
|
||||
headerTipsStore model.HeaderTipsStore,
|
||||
headersSelectedTipStore model.HeaderSelectedTipStore,
|
||||
finalityStore model.FinalityStore,
|
||||
) model.BlockProcessor {
|
||||
|
||||
@@ -86,20 +86,20 @@ func New(
|
||||
headerTipsManager: headerTipsManager,
|
||||
syncManager: syncManager,
|
||||
|
||||
consensusStateManager: consensusStateManager,
|
||||
acceptanceDataStore: acceptanceDataStore,
|
||||
blockStore: blockStore,
|
||||
blockStatusStore: blockStatusStore,
|
||||
blockRelationStore: blockRelationStore,
|
||||
multisetStore: multisetStore,
|
||||
ghostdagDataStore: ghostdagDataStore,
|
||||
consensusStateStore: consensusStateStore,
|
||||
pruningStore: pruningStore,
|
||||
reachabilityDataStore: reachabilityDataStore,
|
||||
utxoDiffStore: utxoDiffStore,
|
||||
blockHeaderStore: blockHeaderStore,
|
||||
headerTipsStore: headerTipsStore,
|
||||
finalityStore: finalityStore,
|
||||
consensusStateManager: consensusStateManager,
|
||||
acceptanceDataStore: acceptanceDataStore,
|
||||
blockStore: blockStore,
|
||||
blockStatusStore: blockStatusStore,
|
||||
blockRelationStore: blockRelationStore,
|
||||
multisetStore: multisetStore,
|
||||
ghostdagDataStore: ghostdagDataStore,
|
||||
consensusStateStore: consensusStateStore,
|
||||
pruningStore: pruningStore,
|
||||
reachabilityDataStore: reachabilityDataStore,
|
||||
utxoDiffStore: utxoDiffStore,
|
||||
blockHeaderStore: blockHeaderStore,
|
||||
headersSelectedTipStore: headersSelectedTipStore,
|
||||
finalityStore: finalityStore,
|
||||
|
||||
stores: []model.Store{
|
||||
consensusStateStore,
|
||||
@@ -114,7 +114,7 @@ func New(
|
||||
reachabilityDataStore,
|
||||
utxoDiffStore,
|
||||
blockHeaderStore,
|
||||
headerTipsStore,
|
||||
headersSelectedTipStore,
|
||||
finalityStore,
|
||||
},
|
||||
}
|
||||
@@ -122,9 +122,16 @@ func New(
|
||||
|
||||
// ValidateAndInsertBlock validates the given block and, if valid, applies it
|
||||
// to the current state
|
||||
func (bp *blockProcessor) ValidateAndInsertBlock(block *externalapi.DomainBlock) error {
|
||||
func (bp *blockProcessor) ValidateAndInsertBlock(block *externalapi.DomainBlock) (*externalapi.BlockInsertionResult, error) {
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "ValidateAndInsertBlock")
|
||||
defer onEnd()
|
||||
|
||||
return bp.validateAndInsertBlock(block)
|
||||
}
|
||||
|
||||
func (bp *blockProcessor) ValidateAndInsertPruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error {
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "ValidateAndInsertPruningPoint")
|
||||
defer onEnd()
|
||||
|
||||
return bp.validateAndInsertPruningPoint(newPruningPoint, serializedUTXOSet)
|
||||
}
|
||||
|
||||
@@ -11,36 +11,16 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type insertMode uint8
|
||||
|
||||
const (
|
||||
insertModeGenesis insertMode = iota
|
||||
insertModeHeader
|
||||
insertModeBlockBody
|
||||
insertModeBlock
|
||||
)
|
||||
|
||||
func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) error {
|
||||
func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) (*externalapi.BlockInsertionResult, error) {
|
||||
blockHash := consensushashing.HeaderHash(block.Header)
|
||||
log.Debugf("Validating block %s", blockHash)
|
||||
|
||||
insertMode, err := bp.validateAgainstSyncStateAndResolveInsertMode(block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = bp.checkBlockStatus(blockHash, insertMode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = bp.validateBlock(block, insertMode)
|
||||
err := bp.validateBlock(block)
|
||||
if err != nil {
|
||||
bp.discardAllChanges()
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if insertMode == insertModeHeader {
|
||||
isHeaderOnlyBlock := isHeaderOnlyBlock(block)
|
||||
if isHeaderOnlyBlock {
|
||||
bp.blockStatusStore.Stage(blockHash, externalapi.StatusHeaderOnly)
|
||||
} else {
|
||||
bp.blockStatusStore.Stage(blockHash, externalapi.StatusUTXOPendingVerification)
|
||||
@@ -50,55 +30,51 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock)
|
||||
// collected so far
|
||||
err = bp.commitAllChanges()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var oldHeadersSelectedTip *externalapi.DomainHash
|
||||
if insertMode != insertModeGenesis {
|
||||
isGenesis := *blockHash != *bp.genesisHash
|
||||
if isGenesis {
|
||||
var err error
|
||||
oldHeadersSelectedTip, err = bp.headerTipsManager.SelectedTip()
|
||||
oldHeadersSelectedTip, err = bp.headersSelectedTipStore.HeadersSelectedTip(bp.databaseContext)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if insertMode == insertModeHeader {
|
||||
err = bp.headerTipsManager.AddHeaderTip(blockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if insertMode == insertModeBlock || insertMode == insertModeGenesis {
|
||||
err = bp.headerTipsManager.AddHeaderTip(blockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var selectedParentChainChanges *externalapi.SelectedParentChainChanges
|
||||
if !isHeaderOnlyBlock {
|
||||
// Attempt to add the block to the virtual
|
||||
err = bp.consensusStateManager.AddBlockToVirtual(blockHash)
|
||||
selectedParentChainChanges, err = bp.consensusStateManager.AddBlock(blockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tips, err := bp.consensusStateStore.Tips(bp.databaseContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bp.headerTipsStore.Stage(tips)
|
||||
}
|
||||
|
||||
if insertMode != insertModeGenesis {
|
||||
if isGenesis {
|
||||
err := bp.updateReachabilityReindexRoot(oldHeadersSelectedTip)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if insertMode == insertModeBlock {
|
||||
if !isHeaderOnlyBlock {
|
||||
// Trigger pruning, which will check if the pruning point changed and delete the data if it did.
|
||||
err = bp.pruningManager.FindNextPruningPoint()
|
||||
err = bp.pruningManager.UpdatePruningPointByVirtual()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = bp.commitAllChanges()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugf("Block %s validated and inserted", blockHash)
|
||||
@@ -110,71 +86,18 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock)
|
||||
logClosureErr = err
|
||||
return fmt.Sprintf("Failed to get virtual GHOSTDAG data: %s", err)
|
||||
}
|
||||
syncInfo, err := bp.syncManager.GetSyncInfo()
|
||||
if err != nil {
|
||||
logClosureErr = err
|
||||
return fmt.Sprintf("Failed to get sync info: %s", err)
|
||||
}
|
||||
return fmt.Sprintf("New virtual's blue score: %d. Sync state: %s. Block count: %d. Header count: %d",
|
||||
virtualGhostDAGData.BlueScore(), syncInfo.State, syncInfo.BlockCount, syncInfo.HeaderCount)
|
||||
headerCount := bp.blockHeaderStore.Count()
|
||||
blockCount := bp.blockStore.Count()
|
||||
return fmt.Sprintf("New virtual's blue score: %d. Block count: %d. Header count: %d",
|
||||
virtualGhostDAGData.BlueScore(), blockCount, headerCount)
|
||||
}))
|
||||
if logClosureErr != nil {
|
||||
return logClosureErr
|
||||
return nil, logClosureErr
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bp *blockProcessor) validateAgainstSyncStateAndResolveInsertMode(block *externalapi.DomainBlock) (insertMode, error) {
|
||||
syncInfo, err := bp.syncManager.GetSyncInfo()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
syncState := syncInfo.State
|
||||
|
||||
isHeaderOnlyBlock := isHeaderOnlyBlock(block)
|
||||
blockHash := consensushashing.HeaderHash(block.Header)
|
||||
if syncState == externalapi.SyncStateAwaitingGenesis {
|
||||
if isHeaderOnlyBlock {
|
||||
return 0, errors.Errorf("Got a header-only block while awaiting genesis")
|
||||
}
|
||||
if *blockHash != *bp.genesisHash {
|
||||
return 0, errors.Errorf("Received a non-genesis block while awaiting genesis")
|
||||
}
|
||||
return insertModeGenesis, nil
|
||||
}
|
||||
|
||||
if isHeaderOnlyBlock {
|
||||
return insertModeHeader, nil
|
||||
}
|
||||
|
||||
if syncState == externalapi.SyncStateAwaitingUTXOSet {
|
||||
headerTipsPruningPoint, err := bp.consensusStateManager.HeaderTipsPruningPoint()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if *blockHash != *headerTipsPruningPoint {
|
||||
return 0, errors.Errorf("cannot insert blocks other than the header pruning point " +
|
||||
"while awaiting the UTXO set")
|
||||
}
|
||||
return insertModeBlock, nil
|
||||
}
|
||||
|
||||
if syncState == externalapi.SyncStateAwaitingBlockBodies {
|
||||
headerTips, err := bp.headerTipsStore.Tips(bp.databaseContext)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
selectedHeaderTip, err := bp.ghostdagManager.ChooseSelectedParent(headerTips...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if *selectedHeaderTip != *blockHash {
|
||||
return insertModeBlockBody, nil
|
||||
}
|
||||
}
|
||||
|
||||
return insertModeBlock, nil
|
||||
return &externalapi.BlockInsertionResult{
|
||||
SelectedParentChainChanges: selectedParentChainChanges,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func isHeaderOnlyBlock(block *externalapi.DomainBlock) bool {
|
||||
@@ -182,7 +105,7 @@ func isHeaderOnlyBlock(block *externalapi.DomainBlock) bool {
|
||||
}
|
||||
|
||||
func (bp *blockProcessor) updateReachabilityReindexRoot(oldHeadersSelectedTip *externalapi.DomainHash) error {
|
||||
headersSelectedTip, err := bp.headerTipsManager.SelectedTip()
|
||||
headersSelectedTip, err := bp.headersSelectedTipStore.HeadersSelectedTip(bp.databaseContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -194,7 +117,9 @@ func (bp *blockProcessor) updateReachabilityReindexRoot(oldHeadersSelectedTip *e
|
||||
return bp.reachabilityManager.UpdateReindexRoot(headersSelectedTip)
|
||||
}
|
||||
|
||||
func (bp *blockProcessor) checkBlockStatus(hash *externalapi.DomainHash, mode insertMode) error {
|
||||
func (bp *blockProcessor) checkBlockStatus(block *externalapi.DomainBlock) error {
|
||||
hash := consensushashing.BlockHash(block)
|
||||
isHeaderOnlyBlock := isHeaderOnlyBlock(block)
|
||||
exists, err := bp.blockStatusStore.Exists(bp.databaseContext, hash)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -212,12 +137,12 @@ func (bp *blockProcessor) checkBlockStatus(hash *externalapi.DomainHash, mode in
|
||||
return errors.Wrapf(ruleerrors.ErrKnownInvalid, "block %s is a known invalid block", hash)
|
||||
}
|
||||
|
||||
isBlockBodyAfterBlockHeader := mode != insertModeHeader && status == externalapi.StatusHeaderOnly
|
||||
isBlockBodyAfterBlockHeader := !isHeaderOnlyBlock && status == externalapi.StatusHeaderOnly
|
||||
if !isBlockBodyAfterBlockHeader {
|
||||
return errors.Wrapf(ruleerrors.ErrDuplicateBlock, "block %s already exists", hash)
|
||||
}
|
||||
|
||||
isDuplicateHeader := mode == insertModeHeader && status == externalapi.StatusHeaderOnly
|
||||
isDuplicateHeader := isHeaderOnlyBlock && status == externalapi.StatusHeaderOnly
|
||||
if isDuplicateHeader {
|
||||
return errors.Wrapf(ruleerrors.ErrDuplicateBlock, "block %s already exists", hash)
|
||||
}
|
||||
@@ -225,57 +150,16 @@ func (bp *blockProcessor) checkBlockStatus(hash *externalapi.DomainHash, mode in
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, mode insertMode) error {
|
||||
blockHash := consensushashing.HeaderHash(block.Header)
|
||||
hasHeader, err := bp.hasHeader(blockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !hasHeader {
|
||||
bp.blockHeaderStore.Stage(blockHash, block.Header)
|
||||
}
|
||||
|
||||
// If any validation until (included) proof-of-work fails, simply
|
||||
// return an error without writing anything in the database.
|
||||
// This is to prevent spamming attacks.
|
||||
err = bp.validatePreProofOfWork(block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = bp.validatePruningPointViolationAndProofOfWorkAndDifficulty(block, mode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If in-context validations fail, discard all changes and store the
|
||||
// block with StatusInvalid.
|
||||
err = bp.validatePostProofOfWork(block, mode)
|
||||
if err != nil {
|
||||
if errors.As(err, &ruleerrors.RuleError{}) {
|
||||
bp.discardAllChanges()
|
||||
hash := consensushashing.BlockHash(block)
|
||||
bp.blockStatusStore.Stage(hash, externalapi.StatusInvalid)
|
||||
commitErr := bp.commitAllChanges()
|
||||
if commitErr != nil {
|
||||
return commitErr
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bp *blockProcessor) validatePreProofOfWork(block *externalapi.DomainBlock) error {
|
||||
blockHash := consensushashing.BlockHash(block)
|
||||
|
||||
hasHeader, err := bp.hasHeader(blockHash)
|
||||
hasValidatedOnlyHeader, err := bp.hasValidatedOnlyHeader(blockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if hasHeader {
|
||||
if hasValidatedOnlyHeader {
|
||||
log.Debugf("Block %s header was already validated, so skip the rest of validatePreProofOfWork", blockHash)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -286,41 +170,43 @@ func (bp *blockProcessor) validatePreProofOfWork(block *externalapi.DomainBlock)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bp *blockProcessor) validatePruningPointViolationAndProofOfWorkAndDifficulty(block *externalapi.DomainBlock, mode insertMode) error {
|
||||
blockHash := consensushashing.HeaderHash(block.Header)
|
||||
if mode != insertModeHeader {
|
||||
// We stage the block here since we need it for parent validation
|
||||
bp.blockStore.Stage(blockHash, block)
|
||||
}
|
||||
return bp.blockValidator.ValidatePruningPointViolationAndProofOfWorkAndDifficulty(blockHash)
|
||||
}
|
||||
|
||||
func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock, mode insertMode) error {
|
||||
func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock) error {
|
||||
blockHash := consensushashing.BlockHash(block)
|
||||
|
||||
if mode != insertModeHeader {
|
||||
isHeaderOnlyBlock := isHeaderOnlyBlock(block)
|
||||
if !isHeaderOnlyBlock {
|
||||
bp.blockStore.Stage(blockHash, block)
|
||||
err := bp.blockValidator.ValidateBodyInIsolation(blockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
hasHeader, err := bp.hasHeader(blockHash)
|
||||
hasValidatedHeader, err := bp.hasValidatedOnlyHeader(blockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !hasHeader {
|
||||
if !hasValidatedHeader {
|
||||
err = bp.blockValidator.ValidateHeaderInContext(blockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !isHeaderOnlyBlock {
|
||||
err = bp.blockValidator.ValidateBodyInContext(blockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
log.Tracef("Skipping ValidateBodyInContext for block %s because it's header only", blockHash)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bp *blockProcessor) hasHeader(blockHash *externalapi.DomainHash) (bool, error) {
|
||||
func (bp *blockProcessor) hasValidatedOnlyHeader(blockHash *externalapi.DomainHash) (bool, error) {
|
||||
exists, err := bp.blockStatusStore.Exists(bp.databaseContext, blockHash)
|
||||
if err != nil {
|
||||
return false, err
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package blockprocessor
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (bp *blockProcessor) validateAndInsertPruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error {
|
||||
log.Info("Checking that the given pruning point is the expected pruning point")
|
||||
|
||||
expectedNewPruningPointHash, err := bp.pruningManager.CalculatePruningPointByHeaderSelectedTip()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newPruningPointHash := consensushashing.BlockHash(newPruningPoint)
|
||||
|
||||
if *expectedNewPruningPointHash != *newPruningPointHash {
|
||||
return errors.Wrapf(ruleerrors.ErrUnexpectedPruningPoint, "expected pruning point %s but got %s",
|
||||
expectedNewPruningPointHash, newPruningPointHash)
|
||||
}
|
||||
|
||||
// We have to validate the pruning point block before we set the new pruning point in consensusStateManager.
|
||||
log.Infof("Validating the new pruning point %s", newPruningPointHash)
|
||||
err = bp.validateBlockAndDiscardChanges(newPruningPoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = bp.consensusStateManager.UpdatePruningPoint(newPruningPoint, serializedUTXOSet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = bp.ValidateAndInsertBlock(newPruningPoint)
|
||||
return err
|
||||
}
|
||||
67
domain/consensus/processes/blockprocessor/validateblock.go
Normal file
67
domain/consensus/processes/blockprocessor/validateblock.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package blockprocessor
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (bp *blockProcessor) validateBlockAndDiscardChanges(block *externalapi.DomainBlock) error {
|
||||
defer bp.discardAllChanges()
|
||||
return bp.validateBlock(block)
|
||||
}
|
||||
|
||||
func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock) error {
|
||||
blockHash := consensushashing.HeaderHash(block.Header)
|
||||
log.Debugf("Validating block %s", blockHash)
|
||||
|
||||
err := bp.checkBlockStatus(block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hasValidatedHeader, err := bp.hasValidatedOnlyHeader(blockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !hasValidatedHeader {
|
||||
log.Tracef("Staging block %s header", blockHash)
|
||||
bp.blockHeaderStore.Stage(blockHash, block.Header)
|
||||
} else {
|
||||
log.Tracef("Block %s header is already known, so no need to stage it", blockHash)
|
||||
}
|
||||
|
||||
// If any validation until (included) proof-of-work fails, simply
|
||||
// return an error without writing anything in the database.
|
||||
// This is to prevent spamming attacks.
|
||||
err = bp.validatePreProofOfWork(block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !hasValidatedHeader {
|
||||
err = bp.blockValidator.ValidatePruningPointViolationAndProofOfWorkAndDifficulty(blockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// If in-context validations fail, discard all changes and store the
|
||||
// block with StatusInvalid.
|
||||
err = bp.validatePostProofOfWork(block)
|
||||
if err != nil {
|
||||
if errors.As(err, &ruleerrors.RuleError{}) {
|
||||
bp.discardAllChanges()
|
||||
hash := consensushashing.BlockHash(block)
|
||||
bp.blockStatusStore.Stage(hash, externalapi.StatusInvalid)
|
||||
commitErr := bp.commitAllChanges()
|
||||
if commitErr != nil {
|
||||
return commitErr
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -24,9 +24,9 @@ func TestChainedTransactions(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown()
|
||||
defer teardown(false)
|
||||
|
||||
block1Hash, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
block1Hash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -47,13 +47,13 @@ func TestChainedTransactions(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check that a block is invalid if it contains chained transactions
|
||||
_, err = tc.AddBlock([]*externalapi.DomainHash{block1Hash}, nil,
|
||||
_, _, err = tc.AddBlock([]*externalapi.DomainHash{block1Hash}, nil,
|
||||
[]*externalapi.DomainTransaction{tx1, chainedTx})
|
||||
if !errors.Is(err, ruleerrors.ErrChainedTransactions) {
|
||||
t.Fatalf("unexpected error %+v", err)
|
||||
}
|
||||
|
||||
block2Hash, err := tc.AddBlock([]*externalapi.DomainHash{block1Hash}, nil, nil)
|
||||
block2Hash, _, err := tc.AddBlock([]*externalapi.DomainHash{block1Hash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %+v", err)
|
||||
}
|
||||
@@ -69,7 +69,7 @@ func TestChainedTransactions(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check that a block is valid if it contains two non chained transactions
|
||||
_, err = tc.AddBlock([]*externalapi.DomainHash{block2Hash}, nil,
|
||||
_, _, err = tc.AddBlock([]*externalapi.DomainHash{block2Hash}, nil,
|
||||
[]*externalapi.DomainTransaction{tx1, tx2})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %+v", err)
|
||||
@@ -86,7 +86,7 @@ func TestCheckBlockSanity(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown()
|
||||
defer teardown(false)
|
||||
blockHash := consensushashing.BlockHash(&exampleValidBlock)
|
||||
if len(exampleValidBlock.Transactions) < 3 {
|
||||
t.Fatalf("Too few transactions in block, expect at least 3, got %v", len(exampleValidBlock.Transactions))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -20,7 +20,7 @@ func TestValidateMedianTime(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown()
|
||||
defer teardown(false)
|
||||
|
||||
addBlock := func(blockTime int64, parents []*externalapi.DomainHash, expectedErr error) (*externalapi.DomainBlock, *externalapi.DomainHash) {
|
||||
block, _, err := tc.BuildBlockWithParents(parents, nil, nil)
|
||||
@@ -29,7 +29,7 @@ func TestValidateMedianTime(t *testing.T) {
|
||||
}
|
||||
|
||||
block.Header.TimeInMilliseconds = blockTime
|
||||
err = tc.ValidateAndInsertBlock(block)
|
||||
_, err = tc.ValidateAndInsertBlock(block)
|
||||
if !errors.Is(err, expectedErr) {
|
||||
t.Fatalf("expected error %s but got %+v", expectedErr, err)
|
||||
}
|
||||
@@ -87,19 +87,19 @@ func TestCheckParentsIncest(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown()
|
||||
defer teardown(false)
|
||||
|
||||
a, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
a, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
|
||||
b, err := tc.AddBlock([]*externalapi.DomainHash{a}, nil, nil)
|
||||
b, _, err := tc.AddBlock([]*externalapi.DomainHash{a}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
|
||||
c, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
c, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -118,7 +118,7 @@ func TestCheckParentsIncest(t *testing.T) {
|
||||
Transactions: nil,
|
||||
}
|
||||
|
||||
err = tc.ValidateAndInsertBlock(directParentsRelationBlock)
|
||||
_, err = tc.ValidateAndInsertBlock(directParentsRelationBlock)
|
||||
if !errors.Is(err, ruleerrors.ErrInvalidParentsRelation) {
|
||||
t.Fatalf("unexpected error %+v", err)
|
||||
}
|
||||
@@ -137,13 +137,13 @@ func TestCheckParentsIncest(t *testing.T) {
|
||||
Transactions: nil,
|
||||
}
|
||||
|
||||
err = tc.ValidateAndInsertBlock(indirectParentsRelationBlock)
|
||||
_, err = tc.ValidateAndInsertBlock(indirectParentsRelationBlock)
|
||||
if !errors.Is(err, ruleerrors.ErrInvalidParentsRelation) {
|
||||
t.Fatalf("unexpected error %+v", err)
|
||||
}
|
||||
|
||||
// Try to add block with unrelated parents
|
||||
_, err = tc.AddBlock([]*externalapi.DomainHash{b, c}, nil, nil)
|
||||
_, _, err = tc.AddBlock([]*externalapi.DomainHash{b, c}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %s", err)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
7
domain/consensus/processes/blockvalidator/log.go
Normal file
7
domain/consensus/processes/blockvalidator/log.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package blockvalidator
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
)
|
||||
|
||||
var log, _ = logger.Get(logger.SubsystemTags.BLVL)
|
||||
@@ -5,11 +5,15 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/pow"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (v *blockValidator) ValidatePruningPointViolationAndProofOfWorkAndDifficulty(blockHash *externalapi.DomainHash) error {
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "ValidatePruningPointViolationAndProofOfWorkAndDifficulty")
|
||||
defer onEnd()
|
||||
|
||||
header, err := v.blockHeaderStore.BlockHeader(v.databaseContext, blockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -93,7 +97,7 @@ func (v *blockValidator) checkProofOfWork(header *externalapi.DomainBlockHeader)
|
||||
if !v.skipPoW {
|
||||
valid := pow.CheckProofOfWorkWithTarget(header, target)
|
||||
if !valid {
|
||||
return errors.Wrap(ruleerrors.ErrUnexpectedDifficulty, "block has invalid difficulty")
|
||||
return errors.Wrap(ruleerrors.ErrInvalidPoW, "block has invalid proof of work")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -102,7 +106,7 @@ func (v *blockValidator) checkProofOfWork(header *externalapi.DomainBlockHeader)
|
||||
func (v *blockValidator) checkParentsExist(blockHash *externalapi.DomainHash, header *externalapi.DomainBlockHeader) error {
|
||||
missingParentHashes := []*externalapi.DomainHash{}
|
||||
|
||||
isFullBlock, err := v.blockStore.HasBlock(v.databaseContext, blockHash)
|
||||
hasBlockBody, err := v.blockStore.HasBlock(v.databaseContext, blockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -117,12 +121,31 @@ func (v *blockValidator) checkParentsExist(blockHash *externalapi.DomainHash, he
|
||||
continue
|
||||
}
|
||||
|
||||
if isFullBlock {
|
||||
parentStatus, err := v.blockStatusStore.Get(v.databaseContext, parent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parentStatus, err := v.blockStatusStore.Get(v.databaseContext, parent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if parentStatus == externalapi.StatusInvalid {
|
||||
return errors.Wrapf(ruleerrors.ErrInvalidAncestorBlock, "parent %s is invalid", parent)
|
||||
}
|
||||
|
||||
if hasBlockBody {
|
||||
if parentStatus == externalapi.StatusHeaderOnly {
|
||||
pruningPoint, err := v.pruningStore.PruningPoint(v.databaseContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
isInPastOfPruningPoint, err := v.dagTopologyManager.IsAncestorOf(parent, pruningPoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if isInPastOfPruningPoint {
|
||||
continue
|
||||
}
|
||||
|
||||
missingParentHashes = append(missingParentHashes, parent)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -8,41 +8,41 @@ import (
|
||||
// AddBlockToVirtual submits the given block to be added to the
|
||||
// current virtual. This process may result in a new virtual block
|
||||
// getting created
|
||||
func (csm *consensusStateManager) AddBlockToVirtual(blockHash *externalapi.DomainHash) error {
|
||||
log.Tracef("AddBlockToVirtual start for block %s", blockHash)
|
||||
defer log.Tracef("AddBlockToVirtual end for block %s", blockHash)
|
||||
func (csm *consensusStateManager) AddBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error) {
|
||||
log.Tracef("AddBlock start for block %s", blockHash)
|
||||
defer log.Tracef("AddBlock end for block %s", blockHash)
|
||||
|
||||
log.Tracef("Resolving whether the block %s is the next virtual selected parent", blockHash)
|
||||
isNextVirtualSelectedParent, err := csm.isNextVirtualSelectedParent(blockHash)
|
||||
isCandidateToBeNextVirtualSelectedParent, err := csm.isCandidateToBeNextVirtualSelectedParent(blockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if isNextVirtualSelectedParent {
|
||||
log.Tracef("Block %s is the new virtual. Resolving its block status", blockHash)
|
||||
blockStatus, err := csm.resolveBlockStatus(blockHash)
|
||||
if isCandidateToBeNextVirtualSelectedParent {
|
||||
// It's important to check for finality violation before resolving the block status, because the status of
|
||||
// blocks with a selected chain that doesn't contain the pruning point cannot be resolved because they will
|
||||
// eventually try to fetch UTXO diffs from the past of the pruning point.
|
||||
log.Tracef("Block %s is candidate to be the next virtual selected parent. Resolving whether it violates "+
|
||||
"finality", blockHash)
|
||||
isViolatingFinality, shouldNotify, err := csm.isViolatingFinality(blockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if blockStatus == externalapi.StatusValid {
|
||||
log.Tracef("Block %s is tentatively valid. Resolving whether it violates finality", blockHash)
|
||||
err = csm.checkFinalityViolation(blockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Re-fetch the block status for logging purposes
|
||||
// because it could've been changed in
|
||||
// checkFinalityViolation
|
||||
blockStatus, err = csm.blockStatusStore.Get(csm.databaseContext, blockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if shouldNotify {
|
||||
//TODO: Send finality conflict notification
|
||||
log.Warnf("Finality Violation Detected! Block %s violates finality!", blockHash)
|
||||
}
|
||||
|
||||
log.Debugf("Block %s is the next virtual selected parent. "+
|
||||
"Its resolved status is `%s`", blockHash, blockStatus)
|
||||
if !isViolatingFinality {
|
||||
log.Tracef("Block %s doesn't violate finality. Resolving its block status", blockHash)
|
||||
blockStatus, err := csm.resolveBlockStatus(blockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugf("Block %s resolved to status `%s`", blockHash, blockStatus)
|
||||
}
|
||||
} else {
|
||||
log.Debugf("Block %s is not the next virtual selected parent, "+
|
||||
"therefore its status remains `%s`", blockHash, externalapi.StatusUTXOPendingVerification)
|
||||
@@ -51,22 +51,22 @@ func (csm *consensusStateManager) AddBlockToVirtual(blockHash *externalapi.Domai
|
||||
log.Tracef("Adding block %s to the DAG tips", blockHash)
|
||||
newTips, err := csm.addTip(blockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
log.Tracef("After adding %s, the new tips are %s", blockHash, newTips)
|
||||
|
||||
log.Tracef("Updating the virtual with the new tips")
|
||||
err = csm.updateVirtual(blockHash, newTips)
|
||||
selectedParentChainChanges, err := csm.updateVirtual(blockHash, newTips)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return selectedParentChainChanges, nil
|
||||
}
|
||||
|
||||
func (csm *consensusStateManager) isNextVirtualSelectedParent(blockHash *externalapi.DomainHash) (bool, error) {
|
||||
log.Tracef("isNextVirtualSelectedParent start for block %s", blockHash)
|
||||
defer log.Tracef("isNextVirtualSelectedParent end for block %s", blockHash)
|
||||
func (csm *consensusStateManager) isCandidateToBeNextVirtualSelectedParent(blockHash *externalapi.DomainHash) (bool, error) {
|
||||
log.Tracef("isCandidateToBeNextVirtualSelectedParent start for block %s", blockHash)
|
||||
defer log.Tracef("isCandidateToBeNextVirtualSelectedParent end for block %s", blockHash)
|
||||
|
||||
if *blockHash == *csm.genesisHash {
|
||||
log.Tracef("Block %s is the genesis block, therefore it is "+
|
||||
|
||||
@@ -23,7 +23,7 @@ func TestUTXOCommitment(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown()
|
||||
defer teardown(false)
|
||||
|
||||
// Build the following DAG:
|
||||
// G <- A <- B <- C <- E
|
||||
@@ -32,13 +32,13 @@ func TestUTXOCommitment(t *testing.T) {
|
||||
genesisHash := params.GenesisHash
|
||||
|
||||
// Block A:
|
||||
blockAHash, err := consensus.AddBlock([]*externalapi.DomainHash{genesisHash}, nil, nil)
|
||||
blockAHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{genesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating block A: %+v", err)
|
||||
}
|
||||
checkBlockUTXOCommitment(t, consensus, blockAHash, "A")
|
||||
// Block B:
|
||||
blockBHash, err := consensus.AddBlock([]*externalapi.DomainHash{blockAHash}, nil, nil)
|
||||
blockBHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{blockAHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating block B: %+v", err)
|
||||
}
|
||||
@@ -48,7 +48,7 @@ func TestUTXOCommitment(t *testing.T) {
|
||||
}
|
||||
checkBlockUTXOCommitment(t, consensus, blockBHash, "B")
|
||||
// Block C:
|
||||
blockCHash, err := consensus.AddBlock([]*externalapi.DomainHash{blockBHash}, nil, nil)
|
||||
blockCHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{blockBHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating block C: %+v", err)
|
||||
}
|
||||
@@ -59,14 +59,14 @@ func TestUTXOCommitment(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating transaction: %+v", err)
|
||||
}
|
||||
blockDHash, err := consensus.AddBlock([]*externalapi.DomainHash{blockBHash}, nil,
|
||||
blockDHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{blockBHash}, nil,
|
||||
[]*externalapi.DomainTransaction{blockDTransaction})
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating block D: %+v", err)
|
||||
}
|
||||
checkBlockUTXOCommitment(t, consensus, blockDHash, "D")
|
||||
// Block E:
|
||||
blockEHash, err := consensus.AddBlock([]*externalapi.DomainHash{blockCHash, blockDHash}, nil, nil)
|
||||
blockEHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{blockCHash, blockDHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating block E: %+v", err)
|
||||
}
|
||||
@@ -119,12 +119,12 @@ func TestPastUTXOMultiset(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown()
|
||||
defer teardown(false)
|
||||
|
||||
// Build a short chain
|
||||
currentHash := params.GenesisHash
|
||||
for i := 0; i < 3; i++ {
|
||||
currentHash, err = consensus.AddBlock([]*externalapi.DomainHash{currentHash}, nil, nil)
|
||||
currentHash, _, err = consensus.AddBlock([]*externalapi.DomainHash{currentHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating block A: %+v", err)
|
||||
}
|
||||
@@ -141,7 +141,7 @@ func TestPastUTXOMultiset(t *testing.T) {
|
||||
firstMultisetHash := firstMultiset.Hash()
|
||||
|
||||
// Add another block on top of testedBlock
|
||||
_, err = consensus.AddBlock([]*externalapi.DomainHash{testedBlockHash}, nil, nil)
|
||||
_, _, err = consensus.AddBlock([]*externalapi.DomainHash{testedBlockHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating block A: %+v", err)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -25,14 +25,14 @@ func TestDoubleSpends(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown()
|
||||
defer teardown(false)
|
||||
|
||||
// Mine chain of two blocks to fund our double spend
|
||||
firstBlockHash, err := consensus.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
firstBlockHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating firstBlock: %+v", err)
|
||||
}
|
||||
fundingBlockHash, err := consensus.AddBlock([]*externalapi.DomainHash{firstBlockHash}, nil, nil)
|
||||
fundingBlockHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{firstBlockHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating fundingBlock: %+v", err)
|
||||
}
|
||||
@@ -61,7 +61,7 @@ func TestDoubleSpends(t *testing.T) {
|
||||
}
|
||||
|
||||
// Mine a block with spendingTransaction1 and make sure that it's valid
|
||||
goodBlock1Hash, err := consensus.AddBlock([]*externalapi.DomainHash{fundingBlockHash}, nil,
|
||||
goodBlock1Hash, _, err := consensus.AddBlock([]*externalapi.DomainHash{fundingBlockHash}, nil,
|
||||
[]*externalapi.DomainTransaction{spendingTransaction1})
|
||||
if err != nil {
|
||||
t.Fatalf("Error adding goodBlock1: %+v", err)
|
||||
@@ -76,7 +76,7 @@ func TestDoubleSpends(t *testing.T) {
|
||||
|
||||
// To check that a block containing the same transaction already in it's past is disqualified:
|
||||
// Add a block on top of goodBlock, containing spendingTransaction1, and make sure it's disqualified
|
||||
doubleSpendingBlock1Hash, err := consensus.AddBlock([]*externalapi.DomainHash{goodBlock1Hash}, nil,
|
||||
doubleSpendingBlock1Hash, _, err := consensus.AddBlock([]*externalapi.DomainHash{goodBlock1Hash}, nil,
|
||||
[]*externalapi.DomainTransaction{spendingTransaction1})
|
||||
if err != nil {
|
||||
t.Fatalf("Error adding doubleSpendingBlock1: %+v", err)
|
||||
@@ -93,7 +93,7 @@ func TestDoubleSpends(t *testing.T) {
|
||||
// To check that a block containing a transaction that double-spends a transaction that
|
||||
// is in it's past is disqualified:
|
||||
// Add a block on top of goodBlock, containing spendingTransaction2, and make sure it's disqualified
|
||||
doubleSpendingBlock2Hash, err := consensus.AddBlock([]*externalapi.DomainHash{goodBlock1Hash}, nil,
|
||||
doubleSpendingBlock2Hash, _, err := consensus.AddBlock([]*externalapi.DomainHash{goodBlock1Hash}, nil,
|
||||
[]*externalapi.DomainTransaction{spendingTransaction2})
|
||||
if err != nil {
|
||||
t.Fatalf("Error adding doubleSpendingBlock2: %+v", err)
|
||||
@@ -110,7 +110,7 @@ func TestDoubleSpends(t *testing.T) {
|
||||
// To make sure that a block double-spending itself is rejected:
|
||||
// Add a block on top of goodBlock, containing both spendingTransaction1 and spendingTransaction2, and make
|
||||
// sure AddBlock returns a RuleError
|
||||
_, err = consensus.AddBlock([]*externalapi.DomainHash{goodBlock1Hash}, nil,
|
||||
_, _, err = consensus.AddBlock([]*externalapi.DomainHash{goodBlock1Hash}, nil,
|
||||
[]*externalapi.DomainTransaction{spendingTransaction1, spendingTransaction2})
|
||||
if err == nil {
|
||||
t.Fatalf("No error when adding a self-double-spending block")
|
||||
@@ -123,7 +123,7 @@ func TestDoubleSpends(t *testing.T) {
|
||||
// To make sure that a block containing the same transaction twice is rejected:
|
||||
// Add a block on top of goodBlock, containing spendingTransaction1 twice, and make
|
||||
// sure AddBlock returns a RuleError
|
||||
_, err = consensus.AddBlock([]*externalapi.DomainHash{goodBlock1Hash}, nil,
|
||||
_, _, err = consensus.AddBlock([]*externalapi.DomainHash{goodBlock1Hash}, nil,
|
||||
[]*externalapi.DomainTransaction{spendingTransaction1, spendingTransaction1})
|
||||
if err == nil {
|
||||
t.Fatalf("No error when adding a block containing the same transactin twice")
|
||||
@@ -135,7 +135,7 @@ func TestDoubleSpends(t *testing.T) {
|
||||
|
||||
// Check that a block will not get disqualified if it has a transaction that double spends
|
||||
// a transaction from its anticone.
|
||||
goodBlock2Hash, err := consensus.AddBlock([]*externalapi.DomainHash{fundingBlockHash}, nil,
|
||||
goodBlock2Hash, _, err := consensus.AddBlock([]*externalapi.DomainHash{fundingBlockHash}, nil,
|
||||
[]*externalapi.DomainTransaction{spendingTransaction2})
|
||||
if err != nil {
|
||||
t.Fatalf("Error adding goodBlock: %+v", err)
|
||||
@@ -157,7 +157,7 @@ func TestResolveBlockStatusSanity(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown()
|
||||
defer teardown(false)
|
||||
|
||||
genesisHash := params.GenesisHash
|
||||
allHashes := []*externalapi.DomainHash{genesisHash}
|
||||
@@ -177,7 +177,7 @@ func TestResolveBlockStatusSanity(t *testing.T) {
|
||||
// statuses are valid
|
||||
currentHash := genesisHash
|
||||
for i := 0; i < chainLength; i++ {
|
||||
addedBlockHash, err := consensus.AddBlock([]*externalapi.DomainHash{currentHash}, nil, nil)
|
||||
addedBlockHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{currentHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("error adding block %d: %s", i, err)
|
||||
}
|
||||
@@ -197,7 +197,7 @@ func TestResolveBlockStatusSanity(t *testing.T) {
|
||||
// StatusUTXOPendingVerification
|
||||
currentHash = genesisHash
|
||||
for i := 0; i < chainLength-1; i++ {
|
||||
addedBlockHash, err := consensus.AddBlock([]*externalapi.DomainHash{currentHash}, nil, nil)
|
||||
addedBlockHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{currentHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("error adding block %d: %s", i, err)
|
||||
}
|
||||
@@ -216,7 +216,7 @@ func TestResolveBlockStatusSanity(t *testing.T) {
|
||||
// Add another two blocks to the second chain. This should trigger
|
||||
// resolving the entire chain
|
||||
for i := 0; i < 2; i++ {
|
||||
addedBlockHash, err := consensus.AddBlock([]*externalapi.DomainHash{currentHash}, nil, nil)
|
||||
addedBlockHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{currentHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("error adding block %d: %s", i, err)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/serialization"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/utxoserialization"
|
||||
@@ -12,18 +13,11 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var virtualHeaderHash = &externalapi.DomainHash{
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
||||
}
|
||||
|
||||
func (csm *consensusStateManager) SetPruningPointUTXOSet(serializedUTXOSet []byte) error {
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "SetPruningPointUTXOSet")
|
||||
func (csm *consensusStateManager) UpdatePruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error {
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "UpdatePruningPoint")
|
||||
defer onEnd()
|
||||
|
||||
err := csm.setPruningPointUTXOSet(serializedUTXOSet)
|
||||
err := csm.updatePruningPoint(newPruningPoint, serializedUTXOSet)
|
||||
if err != nil {
|
||||
csm.discardSetPruningPointUTXOSetChanges()
|
||||
return err
|
||||
@@ -32,15 +26,23 @@ func (csm *consensusStateManager) SetPruningPointUTXOSet(serializedUTXOSet []byt
|
||||
return csm.commitSetPruningPointUTXOSetAll()
|
||||
}
|
||||
|
||||
func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byte) error {
|
||||
log.Tracef("setPruningPointUTXOSet start")
|
||||
defer log.Tracef("setPruningPointUTXOSet end")
|
||||
func (csm *consensusStateManager) updatePruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error {
|
||||
log.Tracef("updatePruningPoint start")
|
||||
defer log.Tracef("updatePruningPoint end")
|
||||
|
||||
headerTipsPruningPoint, err := csm.HeaderTipsPruningPoint()
|
||||
newPruningPointHash := consensushashing.BlockHash(newPruningPoint)
|
||||
|
||||
// We ignore the shouldSendNotification return value because we always want to send finality conflict notification
|
||||
// in case the new pruning point violates finality
|
||||
isViolatingFinality, _, err := csm.isViolatingFinality(newPruningPointHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Tracef("The pruning point of the header tips is: %s", headerTipsPruningPoint)
|
||||
|
||||
if isViolatingFinality {
|
||||
log.Warnf("Finality Violation Detected! The suggest pruning point %s violates finality!", newPruningPointHash)
|
||||
return nil
|
||||
}
|
||||
|
||||
protoUTXOSet := &utxoserialization.ProtoUTXOSet{}
|
||||
err = proto.Unmarshal(serializedUTXOSet, protoUTXOSet)
|
||||
@@ -54,24 +56,24 @@ func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byt
|
||||
}
|
||||
log.Tracef("Calculated multiset for given UTXO set: %s", utxoSetMultiSet.Hash())
|
||||
|
||||
headerTipsPruningPointHeader, err := csm.blockHeaderStore.BlockHeader(csm.databaseContext, headerTipsPruningPoint)
|
||||
newPruningPointHeader, err := csm.blockHeaderStore.BlockHeader(csm.databaseContext, newPruningPointHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Tracef("The multiset in the header of the header tip pruning point: %s",
|
||||
headerTipsPruningPointHeader.UTXOCommitment)
|
||||
log.Tracef("The UTXO commitment of the pruning point: %s",
|
||||
newPruningPointHeader.UTXOCommitment)
|
||||
|
||||
if headerTipsPruningPointHeader.UTXOCommitment != *utxoSetMultiSet.Hash() {
|
||||
if newPruningPointHeader.UTXOCommitment != *utxoSetMultiSet.Hash() {
|
||||
return errors.Wrapf(ruleerrors.ErrBadPruningPointUTXOSet, "the expected multiset hash of the pruning "+
|
||||
"point UTXO set is %s but got %s", headerTipsPruningPointHeader.UTXOCommitment, *utxoSetMultiSet.Hash())
|
||||
"point UTXO set is %s but got %s", newPruningPointHeader.UTXOCommitment, *utxoSetMultiSet.Hash())
|
||||
}
|
||||
log.Tracef("Header tip pruning point multiset validation passed")
|
||||
log.Tracef("The new pruning point UTXO commitment validation passed")
|
||||
|
||||
log.Tracef("Staging the parent hashes for the header tips pruning point as the DAG tips")
|
||||
csm.consensusStateStore.StageTips(headerTipsPruningPointHeader.ParentHashes)
|
||||
log.Tracef("Staging the parent hashes for pruning point as the DAG tips")
|
||||
csm.consensusStateStore.StageTips(newPruningPointHeader.ParentHashes)
|
||||
|
||||
log.Tracef("Setting the parent hashes for the header tips pruning point as the virtual parents")
|
||||
err = csm.dagTopologyManager.SetParents(model.VirtualBlockHash, headerTipsPruningPointHeader.ParentHashes)
|
||||
err = csm.dagTopologyManager.SetParents(model.VirtualBlockHash, newPruningPointHeader.ParentHashes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -82,6 +84,13 @@ func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byt
|
||||
return err
|
||||
}
|
||||
|
||||
// Before we manually mark the new pruning point as valid, we validate that all of its transactions are valid
|
||||
// against the provided UTXO set.
|
||||
err = csm.validateBlockTransactionsAgainstPastUTXO(newPruningPoint, utxo.NewUTXODiff())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = csm.ghostdagManager.GHOSTDAG(model.VirtualBlockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -93,8 +102,11 @@ func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byt
|
||||
return err
|
||||
}
|
||||
|
||||
log.Tracef("Staging the status of the header tips pruning point as %s", externalapi.StatusValid)
|
||||
csm.blockStatusStore.Stage(headerTipsPruningPoint, externalapi.StatusValid)
|
||||
log.Tracef("Staging the new pruning point and its UTXO set")
|
||||
csm.pruningStore.Stage(newPruningPointHash, serializedUTXOSet)
|
||||
|
||||
log.Tracef("Staging the new pruning point as %s", externalapi.StatusValid)
|
||||
csm.blockStatusStore.Stage(newPruningPointHash, externalapi.StatusValid)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -125,12 +137,12 @@ type protoUTXOSetIterator struct {
|
||||
index int
|
||||
}
|
||||
|
||||
func (p protoUTXOSetIterator) Next() bool {
|
||||
func (p *protoUTXOSetIterator) Next() bool {
|
||||
p.index++
|
||||
return p.index < len(p.utxoSet.Utxos)
|
||||
}
|
||||
|
||||
func (p protoUTXOSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry externalapi.UTXOEntry, err error) {
|
||||
func (p *protoUTXOSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry externalapi.UTXOEntry, err error) {
|
||||
entry, outpoint, err := utxo.DeserializeUTXO(p.utxoSet.Utxos[p.index].EntryOutpointPair)
|
||||
if err != nil {
|
||||
if serialization.IsMalformedError(err) {
|
||||
@@ -145,34 +157,3 @@ func (p protoUTXOSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoE
|
||||
func protoUTXOSetToReadOnlyUTXOSetIterator(protoUTXOSet *utxoserialization.ProtoUTXOSet) model.ReadOnlyUTXOSetIterator {
|
||||
return &protoUTXOSetIterator{utxoSet: protoUTXOSet}
|
||||
}
|
||||
|
||||
func (csm *consensusStateManager) HeaderTipsPruningPoint() (*externalapi.DomainHash, error) {
|
||||
log.Tracef("HeaderTipsPruningPoint start")
|
||||
defer log.Tracef("HeaderTipsPruningPoint end")
|
||||
|
||||
headerTips, err := csm.headerTipsStore.Tips(csm.databaseContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Tracef("The current header tips are: %s", headerTips)
|
||||
|
||||
log.Tracef("Temporarily staging the parents of the virtual header to be the header tips: %s", headerTips)
|
||||
csm.blockRelationStore.StageBlockRelation(virtualHeaderHash, &model.BlockRelations{
|
||||
Parents: headerTips,
|
||||
})
|
||||
|
||||
defer csm.blockRelationStore.Discard()
|
||||
|
||||
err = csm.ghostdagManager.GHOSTDAG(virtualHeaderHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer csm.ghostdagDataStore.Discard()
|
||||
|
||||
pruningPoint, err := csm.dagTraversalManager.BlockAtDepth(virtualHeaderHash, csm.pruningDepth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Tracef("The block at depth %d from %s is: %s", csm.pruningDepth, virtualHeaderHash, pruningPoint)
|
||||
return pruningPoint, nil
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -16,28 +16,28 @@ func TestIsAncestorOf(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("NewTestConsensus: %s", err)
|
||||
}
|
||||
defer tearDown()
|
||||
defer tearDown(false)
|
||||
|
||||
// Add a chain of two blocks above the genesis. This will be the
|
||||
// selected parent chain.
|
||||
blockA, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
blockA, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
|
||||
blockB, err := tc.AddBlock([]*externalapi.DomainHash{blockA}, nil, nil)
|
||||
blockB, _, err := tc.AddBlock([]*externalapi.DomainHash{blockA}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %s", err)
|
||||
}
|
||||
|
||||
// Add another block above the genesis
|
||||
blockC, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
blockC, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %s", err)
|
||||
}
|
||||
|
||||
// Add a block whose parents are the two tips
|
||||
blockD, err := tc.AddBlock([]*externalapi.DomainHash{blockB, blockC}, nil, nil)
|
||||
blockD, _, err := tc.AddBlock([]*externalapi.DomainHash{blockB, blockC}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %s", err)
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
package dagtraversalmanager_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/hashset"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/pkg/errors"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBlueBlockWindow(t *testing.T) {
|
||||
@@ -313,7 +314,7 @@ func TestBlueBlockWindow(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("NewTestConsensus: %s", err)
|
||||
}
|
||||
defer tearDown()
|
||||
defer tearDown(false)
|
||||
|
||||
windowSize := 10
|
||||
blockByIDMap := make(map[string]*externalapi.DomainHash)
|
||||
@@ -330,7 +331,7 @@ func TestBlueBlockWindow(t *testing.T) {
|
||||
parents.Add(parent)
|
||||
}
|
||||
|
||||
block, err := tc.AddBlock(parents.ToSlice(), nil, nil)
|
||||
block, _, err := tc.AddBlock(parents.ToSlice(), nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ func TestDifficulty(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown()
|
||||
defer teardown(false)
|
||||
|
||||
addBlock := func(blockTime int64, parents ...*externalapi.DomainHash) (*externalapi.DomainBlock, *externalapi.DomainHash) {
|
||||
bluestParent, err := tc.GHOSTDAGManager().ChooseSelectedParent(parents...)
|
||||
@@ -49,7 +49,7 @@ func TestDifficulty(t *testing.T) {
|
||||
}
|
||||
|
||||
block.Header.TimeInMilliseconds = blockTime
|
||||
err = tc.ValidateAndInsertBlock(block)
|
||||
_, err = tc.ValidateAndInsertBlock(block)
|
||||
if err != nil {
|
||||
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -17,7 +17,7 @@ func TestPastMedianTime(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("NewTestConsensus: %s", err)
|
||||
}
|
||||
defer tearDown()
|
||||
defer tearDown(false)
|
||||
|
||||
numBlocks := uint32(300)
|
||||
blockHashes := make([]*externalapi.DomainHash, numBlocks)
|
||||
@@ -31,7 +31,7 @@ func TestPastMedianTime(t *testing.T) {
|
||||
}
|
||||
|
||||
block.Header.TimeInMilliseconds = blockTime
|
||||
err = tc.ValidateAndInsertBlock(block)
|
||||
_, err = tc.ValidateAndInsertBlock(block)
|
||||
if err != nil {
|
||||
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
||||
}
|
||||
|
||||
5
domain/consensus/processes/pruningmanager/log.go
Normal file
5
domain/consensus/processes/pruningmanager/log.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package pruningmanager
|
||||
|
||||
import "github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
|
||||
var log, _ = logger.Get(logger.SubsystemTags.PRNM)
|
||||
@@ -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 {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package reachabilitymanager_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot(t *testing.T) {
|
||||
@@ -16,7 +17,7 @@ func TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot(t *t
|
||||
if err != nil {
|
||||
t.Fatalf("NewTestConsensus: %+v", err)
|
||||
}
|
||||
defer tearDown()
|
||||
defer tearDown(false)
|
||||
|
||||
tc.ReachabilityManager().SetReachabilityReindexWindow(reachabilityReindexWindow)
|
||||
|
||||
@@ -30,7 +31,7 @@ func TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot(t *t
|
||||
}
|
||||
|
||||
// Add a block on top of the genesis block
|
||||
chainRootBlock, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
chainRootBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -39,7 +40,7 @@ func TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot(t *t
|
||||
// This should move the reindex root
|
||||
chainRootBlockTipHash := chainRootBlock
|
||||
for i := uint64(0); i < reachabilityReindexWindow; i++ {
|
||||
chainBlock, err := tc.AddBlock([]*externalapi.DomainHash{chainRootBlockTipHash}, nil, nil)
|
||||
chainBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{chainRootBlockTipHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -56,7 +57,7 @@ func TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot(t *t
|
||||
}
|
||||
|
||||
// Add another block over genesis
|
||||
_, err = tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
_, _, err = tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -71,7 +72,7 @@ func TestUpdateReindexRoot(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("NewTestConsensus: %s", err)
|
||||
}
|
||||
defer tearDown()
|
||||
defer tearDown(false)
|
||||
|
||||
tc.ReachabilityManager().SetReachabilityReindexWindow(reachabilityReindexWindow)
|
||||
|
||||
@@ -84,12 +85,12 @@ func TestUpdateReindexRoot(t *testing.T) {
|
||||
}
|
||||
|
||||
// Add two blocks on top of the genesis block
|
||||
chain1RootBlock, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
chain1RootBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
|
||||
chain2RootBlock, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
chain2RootBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -98,12 +99,12 @@ func TestUpdateReindexRoot(t *testing.T) {
|
||||
chain1Tip, chain2Tip := chain1RootBlock, chain2RootBlock
|
||||
for i := uint64(0); i < reachabilityReindexWindow-1; i++ {
|
||||
var err error
|
||||
chain1Tip, err = tc.AddBlock([]*externalapi.DomainHash{chain1Tip}, nil, nil)
|
||||
chain1Tip, _, err = tc.AddBlock([]*externalapi.DomainHash{chain1Tip}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
|
||||
chain2Tip, err = tc.AddBlock([]*externalapi.DomainHash{chain2Tip}, nil, nil)
|
||||
chain2Tip, _, err = tc.AddBlock([]*externalapi.DomainHash{chain2Tip}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -119,7 +120,7 @@ func TestUpdateReindexRoot(t *testing.T) {
|
||||
}
|
||||
|
||||
// Add another block over chain1. This will move the reindex root to chain1RootBlock
|
||||
_, err = tc.AddBlock([]*externalapi.DomainHash{chain1Tip}, nil, nil)
|
||||
_, _, err = tc.AddBlock([]*externalapi.DomainHash{chain1Tip}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -159,9 +160,9 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, tearDown, err := factory.NewTestConsensus(params, "TestUpdateReindexRoot")
|
||||
if err != nil {
|
||||
t.Fatalf("NewTestConsensus: %s", err)
|
||||
t.Fatalf("NewTestConsensus: %+v", err)
|
||||
}
|
||||
defer tearDown()
|
||||
defer tearDown(false)
|
||||
|
||||
tc.ReachabilityManager().SetReachabilityReindexWindow(reachabilityReindexWindow)
|
||||
|
||||
@@ -174,17 +175,17 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
|
||||
}
|
||||
|
||||
// Add three children to the genesis: leftBlock, centerBlock, rightBlock
|
||||
leftBlock, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
leftBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
|
||||
centerBlock, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
centerBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
|
||||
rightBlock, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
rightBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -194,7 +195,7 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
|
||||
centerTipHash := centerBlock
|
||||
for i := uint64(0); i < reachabilityReindexWindow; i++ {
|
||||
var err error
|
||||
centerTipHash, err = tc.AddBlock([]*externalapi.DomainHash{centerTipHash}, nil, nil)
|
||||
centerTipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{centerTipHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -246,7 +247,7 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
|
||||
leftTipHash := leftBlock
|
||||
for i := uint64(0); i < reachabilityReindexWindow-1; i++ {
|
||||
var err error
|
||||
leftTipHash, err = tc.AddBlock([]*externalapi.DomainHash{leftTipHash}, nil, nil)
|
||||
leftTipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{leftTipHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -269,7 +270,7 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
|
||||
rightTipHash := rightBlock
|
||||
for i := uint64(0); i < reachabilityReindexWindow-1; i++ {
|
||||
var err error
|
||||
rightTipHash, err = tc.AddBlock([]*externalapi.DomainHash{rightTipHash}, nil, nil)
|
||||
rightTipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{rightTipHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -295,7 +296,7 @@ func TestTipsAfterReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("NewTestConsensus: %s", err)
|
||||
}
|
||||
defer tearDown()
|
||||
defer tearDown(false)
|
||||
|
||||
tc.ReachabilityManager().SetReachabilityReindexWindow(reachabilityReindexWindow)
|
||||
|
||||
@@ -303,7 +304,7 @@ func TestTipsAfterReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
|
||||
// This will set the reindex root to the child of genesis
|
||||
chainTipHash := params.GenesisHash
|
||||
for i := uint64(0); i < reachabilityReindexWindow+1; i++ {
|
||||
chainTipHash, err = tc.AddBlock([]*externalapi.DomainHash{chainTipHash}, nil, nil)
|
||||
chainTipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{chainTipHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -311,14 +312,14 @@ func TestTipsAfterReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
|
||||
|
||||
// Add another block above the genesis block. This will trigger an
|
||||
// earlier-than-reindex-root reindex
|
||||
sideBlock, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
sideBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
|
||||
// Add a block whose parents are the chain tip and the side block.
|
||||
// We expect this not to fail
|
||||
_, err = tc.AddBlock([]*externalapi.DomainHash{sideBlock}, nil, nil)
|
||||
_, _, err = tc.AddBlock([]*externalapi.DomainHash{sideBlock}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -16,19 +16,17 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lowBlockBlueScore := lowBlockGHOSTDAGData.BlueScore()
|
||||
highBlockGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, highHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
highBlockBlueScore := highBlockGHOSTDAGData.BlueScore()
|
||||
if lowBlockBlueScore >= highBlockBlueScore {
|
||||
if lowBlockGHOSTDAGData.BlueScore() >= highBlockGHOSTDAGData.BlueScore() {
|
||||
return nil, errors.Errorf("low hash blueScore >= high hash blueScore (%d >= %d)",
|
||||
lowBlockBlueScore, highBlockBlueScore)
|
||||
lowBlockGHOSTDAGData.BlueScore(), highBlockGHOSTDAGData.BlueScore())
|
||||
}
|
||||
|
||||
// In order to get no more then maxHashesInAntiPastHashesBetween
|
||||
// blocks from th future of the lowHash (including itself),
|
||||
// blocks from the future of the lowHash (including itself),
|
||||
// we iterate the selected parent chain of the highNode and
|
||||
// stop once we reach
|
||||
// highBlockBlueScore-lowBlockBlueScore+1 <= maxHashesInAntiPastHashesBetween.
|
||||
@@ -36,8 +34,13 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma
|
||||
// Using blueScore as an approximation is considered to be
|
||||
// fairly accurate because we presume that most DAG blocks are
|
||||
// blue.
|
||||
for highBlockBlueScore-lowBlockBlueScore+1 > maxHashesInAntiPastHashesBetween {
|
||||
for highBlockGHOSTDAGData.BlueScore()-lowBlockGHOSTDAGData.BlueScore()+1 > maxHashesInAntiPastHashesBetween {
|
||||
highHash = highBlockGHOSTDAGData.SelectedParent()
|
||||
var err error
|
||||
highBlockGHOSTDAGData, err = sm.ghostdagDataStore.Get(sm.databaseContext, highHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Collect every node in highHash's past (including itself) but
|
||||
@@ -99,26 +102,26 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma
|
||||
}
|
||||
|
||||
func (sm *syncManager) missingBlockBodyHashes(highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) {
|
||||
headerTipsPruningPoint, err := sm.consensusStateManager.HeaderTipsPruningPoint()
|
||||
pruningPoint, err := sm.pruningStore.PruningPoint(sm.databaseContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
selectedChildIterator, err := sm.dagTraversalManager.SelectedChildIterator(highHash, headerTipsPruningPoint)
|
||||
selectedChildIterator, err := sm.dagTraversalManager.SelectedChildIterator(highHash, pruningPoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lowHash := headerTipsPruningPoint
|
||||
lowHash := pruningPoint
|
||||
foundHeaderOnlyBlock := false
|
||||
for selectedChildIterator.Next() {
|
||||
selectedChild := selectedChildIterator.Get()
|
||||
selectedChildStatus, err := sm.blockStatusStore.Get(sm.databaseContext, selectedChild)
|
||||
hasBlock, err := sm.blockStore.HasBlock(sm.databaseContext, selectedChild)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if selectedChildStatus == externalapi.StatusHeaderOnly {
|
||||
if !hasBlock {
|
||||
foundHeaderOnlyBlock = true
|
||||
break
|
||||
}
|
||||
@@ -167,24 +170,3 @@ func (sm *syncManager) isHeaderOnlyBlock(blockHash *externalapi.DomainHash) (boo
|
||||
|
||||
return status == externalapi.StatusHeaderOnly, nil
|
||||
}
|
||||
|
||||
func (sm *syncManager) isBlockInHeaderPruningPointFuture(blockHash *externalapi.DomainHash) (bool, error) {
|
||||
if *blockHash == *sm.genesisBlockHash {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
exists, err := sm.blockStatusStore.Exists(sm.databaseContext, blockHash)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !exists {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
headerTipsPruningPoint, err := sm.consensusStateManager.HeaderTipsPruningPoint()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return sm.dagTopologyManager.IsAncestorOf(headerTipsPruningPoint, blockHash)
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -44,6 +44,9 @@ var (
|
||||
// range.
|
||||
ErrUnexpectedDifficulty = newRuleError("ErrUnexpectedDifficulty")
|
||||
|
||||
// ErrInvalidPoW indicates that the block proof-of-work is invalid.
|
||||
ErrInvalidPoW = newRuleError("ErrInvalidPoW")
|
||||
|
||||
// ErrHighHash indicates the block does not hash to a value which is
|
||||
// lower than the required target difficultly.
|
||||
ErrHighHash = newRuleError("ErrHighHash")
|
||||
@@ -56,7 +59,7 @@ var (
|
||||
// the expected value.
|
||||
ErrBadUTXOCommitment = newRuleError("ErrBadUTXOCommitment")
|
||||
|
||||
// ErrInvalidSubnetwork indicates the subnetwork is now allowed.
|
||||
// ErrInvalidSubnetwork indicates the subnetwork is not allowed.
|
||||
ErrInvalidSubnetwork = newRuleError("ErrInvalidSubnetwork")
|
||||
|
||||
// ErrFinalityPointTimeTooOld indicates a block has a timestamp before the
|
||||
@@ -237,6 +240,8 @@ var (
|
||||
|
||||
//ErrBlockIsTooMuchInTheFuture indicates that the block timestamp is too much in the future.
|
||||
ErrBlockIsTooMuchInTheFuture = newRuleError("ErrBlockIsTooMuchInTheFuture")
|
||||
|
||||
ErrUnexpectedPruningPoint = newRuleError("ErrUnexpectedPruningPoint")
|
||||
)
|
||||
|
||||
// RuleError identifies a rule violation. It is used to indicate that
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
|
||||
)
|
||||
|
||||
func (tc *testConsensus) DatabaseContext() model.DBReader {
|
||||
func (tc *testConsensus) DatabaseContext() model.DBManager {
|
||||
return tc.databaseContext
|
||||
}
|
||||
|
||||
@@ -37,8 +37,8 @@ func (tc *testConsensus) GHOSTDAGDataStore() model.GHOSTDAGDataStore {
|
||||
return tc.ghostdagDataStore
|
||||
}
|
||||
|
||||
func (tc *testConsensus) HeaderTipsStore() model.HeaderTipsStore {
|
||||
return tc.headerTipsStore
|
||||
func (tc *testConsensus) HeaderTipsStore() model.HeaderSelectedTipStore {
|
||||
return tc.headersSelectedTipStore
|
||||
}
|
||||
|
||||
func (tc *testConsensus) MultisetStore() model.MultisetStore {
|
||||
@@ -93,7 +93,7 @@ func (tc *testConsensus) GHOSTDAGManager() model.GHOSTDAGManager {
|
||||
return tc.ghostdagManager
|
||||
}
|
||||
|
||||
func (tc *testConsensus) HeaderTipsManager() model.HeaderTipsManager {
|
||||
func (tc *testConsensus) HeaderTipsManager() model.HeadersSelectedTipManager {
|
||||
return tc.headerTipsManager
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -439,7 +439,7 @@ message ChainBlock{
|
||||
|
||||
message AcceptedBlock{
|
||||
string hash = 1;
|
||||
repeated string acceptedTxIds = 2;
|
||||
repeated string acceptedTransactionIds = 2;
|
||||
}
|
||||
|
||||
message GetBlockRequestMessage{
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user