diff --git a/cmd/block/blockGenerator.go b/cmd/block/blockGenerator.go index 8c090415c..e73ffd8d4 100644 --- a/cmd/block/blockGenerator.go +++ b/cmd/block/blockGenerator.go @@ -152,6 +152,7 @@ func initialize( query.NewParticipationScoreQuery(), query.NewBlockQuery(chainType), log.New(), + &mockBlockchainStatusService{}, ) blocksmithStrategy = strategy.NewBlocksmithStrategyMain( queryExecutor, query.NewNodeRegistrationQuery(), query.NewSkippedBlocksmithQuery(), log.New(), diff --git a/common/blocker/blocker.go b/common/blocker/blocker.go index 04665cf41..2bffc44cc 100644 --- a/common/blocker/blocker.go +++ b/common/blocker/blocker.go @@ -16,21 +16,22 @@ type ( ) var ( - DBErr TypeBlocker = "DBErr" - DBRowNotFound TypeBlocker = "DBRowNotFound" - BlockErr TypeBlocker = "BlockErr" - BlockNotFoundErr TypeBlocker = "BlockNotFoundErr" - RequestParameterErr TypeBlocker = "RequestParameterErr" - AppErr TypeBlocker = "AppErr" - AuthErr TypeBlocker = "AuthErr" - ValidationErr TypeBlocker = "ValidationErr" - DuplicateMempoolErr TypeBlocker = "DuplicateMempoolErr" - DuplicateTransactionErr TypeBlocker = "DuplicateTransactionErr" - ParserErr TypeBlocker = "ParserErr" - ServerError TypeBlocker = "ServerError" - SmithingErr TypeBlocker = "SmithingErr" - ChainValidationErr TypeBlocker = "ChainValidationErr" - P2PNetworkConnectionErr TypeBlocker = "P2PNetworkConnectionErr" + DBErr TypeBlocker = "DBErr" + DBRowNotFound TypeBlocker = "DBRowNotFound" + BlockErr TypeBlocker = "BlockErr" + BlockNotFoundErr TypeBlocker = "BlockNotFoundErr" + RequestParameterErr TypeBlocker = "RequestParameterErr" + AppErr TypeBlocker = "AppErr" + AuthErr TypeBlocker = "AuthErr" + ValidationErr TypeBlocker = "ValidationErr" + DuplicateMempoolErr TypeBlocker = "DuplicateMempoolErr" + DuplicateTransactionErr TypeBlocker = "DuplicateTransactionErr" + ParserErr TypeBlocker = "ParserErr" + ServerError TypeBlocker = "ServerError" + SmithingErr TypeBlocker = "SmithingErr" + ZeroParticipationScoreErr TypeBlocker = "ZeroParticipationScoreErr" + ChainValidationErr TypeBlocker = "ChainValidationErr" + P2PNetworkConnectionErr TypeBlocker = "P2PNetworkConnectionErr" ) func NewBlocker(typeBlocker TypeBlocker, message string) error { diff --git a/core/service/blockMainService.go b/core/service/blockMainService.go index 4a468f49f..e388bb95a 100644 --- a/core/service/blockMainService.go +++ b/core/service/blockMainService.go @@ -1476,6 +1476,7 @@ func (bs *BlockService) WillSmith( // no negative scores allowed blocksmithScore = 0 bs.Logger.Errorf("Participation score calculation: %s", err) + return 0, blocker.NewBlocker(blocker.ZeroParticipationScoreErr, "participation score = 0") } err = bs.BlocksmithStrategy.CalculateSmith( lastBlock, diff --git a/core/service/blockchainStatusService.go b/core/service/blockchainStatusService.go index b800b90d0..31d81fede 100644 --- a/core/service/blockchainStatusService.go +++ b/core/service/blockchainStatusService.go @@ -18,6 +18,8 @@ type ( IsSmithing(ct chaintype.ChainType) bool SetIsDownloadingSnapshot(ct chaintype.ChainType, isDownloadingSnapshot bool) IsDownloadingSnapshot(ct chaintype.ChainType) bool + SetIsBlocksmith(isBlocksmith bool) + IsBlocksmith() bool } ) @@ -33,6 +35,7 @@ var ( isDownloadingSnapshot = model.NewMapIntBool() isSmithing = model.NewMapIntBool() isSmithingLocked bool + isBlocksmith bool ) func NewBlockchainStatusService( @@ -123,3 +126,11 @@ func (btss *BlockchainStatusService) IsDownloadingSnapshot(ct chaintype.ChainTyp } return false } + +func (btss *BlockchainStatusService) SetIsBlocksmith(blocksmith bool) { + isBlocksmith = blocksmith +} + +func (btss *BlockchainStatusService) IsBlocksmith() bool { + return isBlocksmith +} diff --git a/core/service/nodeAdminCoreService.go b/core/service/nodeAdminCoreService.go index 150f15f56..6cc94b1cc 100644 --- a/core/service/nodeAdminCoreService.go +++ b/core/service/nodeAdminCoreService.go @@ -120,7 +120,7 @@ func (*NodeAdminService) GetLastNodeKey(nodeKeys []*model.NodeKey) *model.NodeKe return max } -// GenerateNodeKey generates a new node ket from its seed and store it, together with relative public key into node_keys file +// GenerateNodeKey generates a new node key from its seed and store it, together with relative public key into node_keys file func (nas *NodeAdminService) GenerateNodeKey(seed string) ([]byte, error) { publicKey := crypto.NewEd25519Signature().GetPublicKeyFromSeed(seed) nodeKey := &model.NodeKey{ diff --git a/core/service/nodeRegistrationCoreService.go b/core/service/nodeRegistrationCoreService.go index dac30e0b9..7234865b9 100644 --- a/core/service/nodeRegistrationCoreService.go +++ b/core/service/nodeRegistrationCoreService.go @@ -1,6 +1,7 @@ package service import ( + "bytes" "math/big" "sort" "sync" @@ -31,6 +32,7 @@ type ( blockHeight uint32, ) (*model.ScrambledNodes, error) AddParticipationScore(nodeID, scoreDelta int64, height uint32, dbTx bool) (newScore int64, err error) + SetCurrentNodePublicKey(publicKey []byte) } // NodeRegistrationService mockable service methods @@ -45,6 +47,8 @@ type ( ScrambledNodes map[uint32]*model.ScrambledNodes ScrambledNodesLock sync.RWMutex MemoizedLatestScrambledNodes *model.ScrambledNodes + BlockchainStatusService BlockchainStatusServiceInterface + CurrentNodePublicKey []byte } ) @@ -55,6 +59,7 @@ func NewNodeRegistrationService( participationScoreQuery query.ParticipationScoreQueryInterface, blockQuery query.BlockQueryInterface, logger *log.Logger, + blockchainStatusService BlockchainStatusServiceInterface, ) *NodeRegistrationService { return &NodeRegistrationService{ QueryExecutor: queryExecutor, @@ -65,6 +70,7 @@ func NewNodeRegistrationService( NodeAdmittanceCycle: constant.NodeAdmittanceCycle, Logger: logger, ScrambledNodes: map[uint32]*model.ScrambledNodes{}, + BlockchainStatusService: blockchainStatusService, } } @@ -149,6 +155,9 @@ func (nrs *NodeRegistrationService) AdmitNodes(nodeRegistrations []*model.NodeRe if err := nrs.QueryExecutor.ExecuteTransactions(queries); err != nil { return err } + if bytes.Equal(nrs.CurrentNodePublicKey, nodeRegistration.NodePublicKey) { + nrs.BlockchainStatusService.SetIsBlocksmith(true) + } } return nil } @@ -411,3 +420,9 @@ func (nrs *NodeRegistrationService) AddParticipationScore(nodeID, scoreDelta int err = nrs.QueryExecutor.ExecuteTransactions(updateParticipationScoreQuery) return newScore, err } + +// SetCurrentNodePublicKey set the public key of running node, this information will be used to check if current node is +// being admitted and can start unlock smithing process +func (nrs *NodeRegistrationService) SetCurrentNodePublicKey(publicKey []byte) { + nrs.CurrentNodePublicKey = publicKey +} diff --git a/core/smith/blockchainProcessor.go b/core/smith/blockchainProcessor.go index 5e03a30dd..ccd6a583a 100644 --- a/core/smith/blockchainProcessor.go +++ b/core/smith/blockchainProcessor.go @@ -1,9 +1,10 @@ package smith import ( - "github.com/zoobc/zoobc-core/common/chaintype" "time" + "github.com/zoobc/zoobc-core/common/chaintype" + log "github.com/sirupsen/logrus" "github.com/zoobc/zoobc-core/common/blocker" "github.com/zoobc/zoobc-core/common/constant" @@ -180,12 +181,15 @@ func (bp *BlockchainProcessor) Start(sleepPeriod time.Duration) { return case <-ticker.C: // when starting a node, do not start smithing until the main blocks have been fully downloaded - if !bp.BlockchainStatusService.IsSmithingLocked() { + if !bp.BlockchainStatusService.IsSmithingLocked() && bp.BlockchainStatusService.IsBlocksmith() { err := bp.StartSmithing() if err != nil { bp.Logger.Debugf("Smith Error for %s. %s", bp.BlockService.GetChainType().GetName(), err.Error()) bp.BlockchainStatusService.SetIsSmithing(bp.ChainType, false) bp.smithError = err + if blockErr, ok := err.(blocker.Blocker); ok && blockErr.Type == blocker.ZeroParticipationScoreErr { + bp.BlockchainStatusService.SetIsBlocksmith(false) + } } else { bp.BlockchainStatusService.SetIsSmithing(bp.ChainType, true) bp.smithError = nil diff --git a/main.go b/main.go index f5db59f0e..c0f4967b5 100644 --- a/main.go +++ b/main.go @@ -140,6 +140,8 @@ func init() { kvExecutor = kvdb.NewKVExecutor(badgerDb) // initialize services + blockchainStatusService = service.NewBlockchainStatusService(true, loggerCoreService) + nodeRegistrationService = service.NewNodeRegistrationService( queryExecutor, query.NewAccountBalanceQuery(), @@ -147,6 +149,7 @@ func init() { query.NewParticipationScoreQuery(), query.NewBlockQuery(mainchain), loggerCoreService, + blockchainStatusService, ) receiptService = service.NewReceiptService( query.NewNodeReceiptQuery(), @@ -161,7 +164,6 @@ func init() { query.NewPublishedReceiptQuery(), receiptUtil, ) - blockchainStatusService = service.NewBlockchainStatusService(true, loggerCoreService) spineBlockManifestService = service.NewSpineBlockManifestService( queryExecutor, query.NewSpineBlockManifestQuery(), @@ -557,6 +559,10 @@ func startMainchain() { ) } if node != nil { + // register node config public key, so node registration service can detect if node has been admitted + nodeRegistrationService.SetCurrentNodePublicKey(nodePublicKey) + // default to isBlocksmith=true + blockchainStatusService.SetIsBlocksmith(true) mainchainProcessor = smith.NewBlockchainProcessor( mainchainBlockService.GetChainType(), model.NewBlocksmith(nodeSecretPhrase, nodePublicKey, node.NodeID),