diff --git a/cmd/harmony/main.go b/cmd/harmony/main.go index 4e63ad447..2424791f0 100644 --- a/cmd/harmony/main.go +++ b/cmd/harmony/main.go @@ -722,11 +722,12 @@ func setupConsensusAndNode(hc harmonyconfig.HarmonyConfig, nodeConfig *nodeconfi // We are not beacon chain, make sure beacon already initialized. if nodeConfig.ShardID != shard.BeaconChainShardID { - _, err = collection.ShardChain(shard.BeaconChainShardID, core.Options{EpochChain: true}) + beacon, err := collection.ShardChain(shard.BeaconChainShardID, core.Options{EpochChain: true}) if err != nil { _, _ = fmt.Fprintf(os.Stderr, "Error :%v \n", err) os.Exit(1) } + registry.SetBeaconchain(beacon) } blockchain, err = collection.ShardChain(nodeConfig.ShardID) @@ -734,11 +735,16 @@ func setupConsensusAndNode(hc harmonyconfig.HarmonyConfig, nodeConfig *nodeconfi _, _ = fmt.Fprintf(os.Stderr, "Error :%v \n", err) os.Exit(1) } + registry.SetBlockchain(blockchain) + registry.SetWebHooks(nodeConfig.WebHooks.Hooks) + if registry.GetBeaconchain() == nil { + registry.SetBeaconchain(registry.GetBlockchain()) + } // Consensus object. decider := quorum.NewDecider(quorum.SuperMajorityVote, nodeConfig.ShardID) currentConsensus, err := consensus.New( - myHost, nodeConfig.ShardID, nodeConfig.ConsensusPriKey, registry.SetBlockchain(blockchain), decider, minPeers, aggregateSig) + myHost, nodeConfig.ShardID, nodeConfig.ConsensusPriKey, registry, decider, minPeers, aggregateSig) if err != nil { _, _ = fmt.Fprintf(os.Stderr, "Error :%v \n", err) @@ -794,9 +800,6 @@ func setupConsensusAndNode(hc harmonyconfig.HarmonyConfig, nodeConfig *nodeconfi Uint64("viewID", viewID). Msg("Init Blockchain") - // Assign closure functions to the consensus object - currentConsensus.SetBlockVerifier( - node.VerifyNewBlock(currentNode.NodeConfig, currentNode.Blockchain(), currentNode.Beaconchain())) currentConsensus.PostConsensusJob = currentNode.PostConsensusProcessing // update consensus information based on the blockchain currentConsensus.SetMode(currentConsensus.UpdateConsensusInformation()) diff --git a/consensus/consensus.go b/consensus/consensus.go index c5573c972..ca2890fbb 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -6,6 +6,7 @@ import ( "sync/atomic" "time" + "github.com/harmony-one/harmony/consensus/engine" "github.com/harmony-one/harmony/core" "github.com/harmony-one/harmony/crypto/bls" "github.com/harmony-one/harmony/internal/registry" @@ -139,14 +140,20 @@ func (consensus *Consensus) Blockchain() core.BlockChain { return consensus.registry.GetBlockchain() } -func (consensus *Consensus) ReadySignal(p ProposalType) { - consensus.readySignal <- p +// ChainReader returns the chain reader. +// This is mostly the same as Blockchain, but it returns only read methods, so we assume it's safe for concurrent use. +func (consensus *Consensus) ChainReader() engine.ChainReader { + return consensus.Blockchain() } func (consensus *Consensus) GetReadySignal() chan ProposalType { return consensus.readySignal } +func (consensus *Consensus) ReadySignal(p ProposalType) { + consensus.readySignal <- p +} + func (consensus *Consensus) CommitSigChannel() chan []byte { return consensus.commitSigChannel } @@ -155,6 +162,11 @@ func (consensus *Consensus) GetCommitSigChannel() chan []byte { return consensus.commitSigChannel } +// Beaconchain returns the beaconchain. +func (consensus *Consensus) Beaconchain() core.BlockChain { + return consensus.registry.GetBeaconchain() +} + // VerifyBlock is a function used to verify the block and keep trace of verified blocks. func (consensus *Consensus) verifyBlock(block *types.Block) error { if !consensus.FBFTLog.IsBlockVerified(block.Hash()) { @@ -232,8 +244,8 @@ func (consensus *Consensus) getConsensusLeaderPrivateKey() (*bls.PrivateKeyWrapp return consensus.getLeaderPrivateKey(consensus.LeaderPubKey.Object) } -// SetBlockVerifier sets the block verifier -func (consensus *Consensus) SetBlockVerifier(verifier VerifyBlockFunc) { +// setBlockVerifier sets the block verifier +func (consensus *Consensus) setBlockVerifier(verifier VerifyBlockFunc) { consensus.mutex.Lock() defer consensus.mutex.Unlock() consensus.BlockVerifier = verifier @@ -288,7 +300,6 @@ func New( // the blockchain during initialization as it was // displayed on explorer as Height right now consensus.SetCurBlockViewID(0) - consensus.ShardID = shard consensus.SlashChan = make(chan slash.Record) consensus.readySignal = make(chan ProposalType) consensus.commitSigChannel = make(chan []byte) @@ -297,6 +308,8 @@ func New( consensus.IgnoreViewIDCheck = abool.NewBool(false) // Make Sure Verifier is not null consensus.vc = newViewChange() + // TODO: reference to blockchain/beaconchain should be removed. + consensus.setBlockVerifier(VerifyNewBlock(registry.GetWebHooks(), consensus.Blockchain(), consensus.Beaconchain())) // init prometheus metrics initMetrics() diff --git a/consensus/consensus_service.go b/consensus/consensus_service.go index e8d7e1645..2b80ecd8b 100644 --- a/consensus/consensus_service.go +++ b/consensus/consensus_service.go @@ -5,9 +5,11 @@ import ( "sync/atomic" "time" + "github.com/harmony-one/harmony/core" "github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/crypto/bls" "github.com/harmony-one/harmony/multibls" + "github.com/harmony-one/harmony/webhooks" "github.com/ethereum/go-ethereum/common" protobuf "github.com/golang/protobuf/proto" @@ -590,7 +592,7 @@ func (consensus *Consensus) selfCommit(payload []byte) error { consensus.switchPhase("selfCommit", FBFTCommit) consensus.aggregatedPrepareSig = aggSig consensus.prepareBitmap = mask - commitPayload := signature.ConstructCommitPayload(consensus.Blockchain(), + commitPayload := signature.ConstructCommitPayload(consensus.ChainReader().Config(), block.Epoch(), block.Hash(), block.NumberU64(), block.Header().ViewID().Uint64()) for i, key := range consensus.priKey { if err := consensus.commitBitmap.SetKey(key.Pub.Bytes, true); err != nil { @@ -658,3 +660,35 @@ func (consensus *Consensus) getLogger() *zerolog.Logger { Logger() return &logger } + +// VerifyNewBlock is called by consensus participants to verify the block (account model) they are +// running consensus on. +func VerifyNewBlock(hooks *webhooks.Hooks, blockChain core.BlockChain, beaconChain core.BlockChain) func(*types.Block) error { + return func(newBlock *types.Block) error { + if err := blockChain.ValidateNewBlock(newBlock, beaconChain); err != nil { + if hooks := hooks; hooks != nil { + if p := hooks.ProtocolIssues; p != nil { + url := p.OnCannotCommit + go func() { + webhooks.DoPost(url, map[string]interface{}{ + "bad-header": newBlock.Header(), + "reason": err.Error(), + }) + }() + } + } + utils.Logger().Error(). + Str("blockHash", newBlock.Hash().Hex()). + Int("numTx", len(newBlock.Transactions())). + Int("numStakingTx", len(newBlock.StakingTransactions())). + Err(err). + Msg("[VerifyNewBlock] Cannot Verify New Block!!!") + return errors.Errorf( + "[VerifyNewBlock] Cannot Verify New Block!!! block-hash %s txn-count %d", + newBlock.Hash().Hex(), + len(newBlock.Transactions()), + ) + } + return nil + } +} diff --git a/consensus/consensus_service_test.go b/consensus/consensus_service_test.go index dd2fca7ab..00b8bd346 100644 --- a/consensus/consensus_service_test.go +++ b/consensus/consensus_service_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/harmony-one/harmony/crypto/bls" + "github.com/harmony-one/harmony/internal/registry" msg_pb "github.com/harmony-one/harmony/api/proto/message" "github.com/harmony-one/harmony/consensus/quorum" @@ -25,7 +26,8 @@ func TestSignAndMarshalConsensusMessage(t *testing.T) { } decider := quorum.NewDecider(quorum.SuperMajorityVote, shard.BeaconChainShardID) blsPriKey := bls.RandPrivateKey() - consensus, err := New(host, shard.BeaconChainShardID, multibls.GetPrivateKeys(blsPriKey), nil, decider, 3, false) + reg := registry.New() + consensus, err := New(host, shard.BeaconChainShardID, multibls.GetPrivateKeys(blsPriKey), reg, decider, 3, false) if err != nil { t.Fatalf("Cannot craeate consensus: %v", err) } @@ -57,8 +59,9 @@ func TestSetViewID(t *testing.T) { quorum.SuperMajorityVote, shard.BeaconChainShardID, ) blsPriKey := bls.RandPrivateKey() + reg := registry.New() consensus, err := New( - host, shard.BeaconChainShardID, multibls.GetPrivateKeys(blsPriKey), nil, decider, 3, false, + host, shard.BeaconChainShardID, multibls.GetPrivateKeys(blsPriKey), reg, decider, 3, false, ) if err != nil { t.Fatalf("Cannot craeate consensus: %v", err) diff --git a/consensus/consensus_v2.go b/consensus/consensus_v2.go index 41d5b2d26..262cbe37d 100644 --- a/consensus/consensus_v2.go +++ b/consensus/consensus_v2.go @@ -608,7 +608,7 @@ func (consensus *Consensus) verifyLastCommitSig(lastCommitSig []byte, blk *types } aggPubKey := consensus.commitBitmap.AggregatePublic - commitPayload := signature.ConstructCommitPayload(consensus.Blockchain(), + commitPayload := signature.ConstructCommitPayload(consensus.Blockchain().Config(), blk.Epoch(), blk.Hash(), blk.NumberU64(), blk.Header().ViewID().Uint64()) if !aggSig.VerifyHash(aggPubKey, commitPayload) { diff --git a/consensus/construct_test.go b/consensus/construct_test.go index 1add32219..7188ebea6 100644 --- a/consensus/construct_test.go +++ b/consensus/construct_test.go @@ -10,6 +10,7 @@ import ( msg_pb "github.com/harmony-one/harmony/api/proto/message" "github.com/harmony-one/harmony/consensus/quorum" "github.com/harmony-one/harmony/crypto/bls" + "github.com/harmony-one/harmony/internal/registry" "github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/multibls" "github.com/harmony-one/harmony/p2p" @@ -31,7 +32,8 @@ func TestConstructAnnounceMessage(test *testing.T) { quorum.SuperMajorityVote, shard.BeaconChainShardID, ) blsPriKey := bls.RandPrivateKey() - consensus, err := New(host, shard.BeaconChainShardID, multibls.GetPrivateKeys(blsPriKey), nil, decider, 3, false) + reg := registry.New() + consensus, err := New(host, shard.BeaconChainShardID, multibls.GetPrivateKeys(blsPriKey), reg, decider, 3, false) if err != nil { test.Fatalf("Cannot create consensus: %v", err) } @@ -63,7 +65,8 @@ func TestConstructPreparedMessage(test *testing.T) { quorum.SuperMajorityVote, shard.BeaconChainShardID, ) blsPriKey := bls.RandPrivateKey() - consensus, err := New(host, shard.BeaconChainShardID, multibls.GetPrivateKeys(blsPriKey), nil, decider, 3, false) + reg := registry.New() + consensus, err := New(host, shard.BeaconChainShardID, multibls.GetPrivateKeys(blsPriKey), reg, decider, 3, false) if err != nil { test.Fatalf("Cannot craeate consensus: %v", err) } @@ -143,7 +146,7 @@ func TestConstructPrepareMessage(test *testing.T) { ) consensus, err := New( - host, shard.BeaconChainShardID, multibls.GetPrivateKeys(blsPriKey1), nil, decider, 3, false, + host, shard.BeaconChainShardID, multibls.GetPrivateKeys(blsPriKey1), registry.New(), decider, 3, false, ) if err != nil { test.Fatalf("Cannot create consensus: %v", err) @@ -234,7 +237,7 @@ func TestConstructCommitMessage(test *testing.T) { quorum.SuperMajorityStake, shard.BeaconChainShardID, ) - consensus, err := New(host, shard.BeaconChainShardID, multibls.GetPrivateKeys(blsPriKey1), nil, decider, 3, false) + consensus, err := New(host, shard.BeaconChainShardID, multibls.GetPrivateKeys(blsPriKey1), registry.New(), decider, 3, false) if err != nil { test.Fatalf("Cannot create consensus: %v", err) } @@ -316,7 +319,7 @@ func TestPopulateMessageFields(t *testing.T) { quorum.SuperMajorityVote, shard.BeaconChainShardID, ) consensus, err := New( - host, shard.BeaconChainShardID, multibls.GetPrivateKeys(blsPriKey), nil, decider, 3, false, + host, shard.BeaconChainShardID, multibls.GetPrivateKeys(blsPriKey), registry.New(), decider, 3, false, ) if err != nil { t.Fatalf("Cannot craeate consensus: %v", err) diff --git a/consensus/downloader.go b/consensus/downloader.go index 8442ed534..26755bbd2 100644 --- a/consensus/downloader.go +++ b/consensus/downloader.go @@ -114,7 +114,14 @@ func (consensus *Consensus) spinUpStateSync() { v.Stop() } } else { - consensus.spinLegacyStateSync() + select { + case consensus.BlockNumLowChan <- struct{}{}: + consensus.current.SetMode(Syncing) + for _, v := range consensus.consensusTimeout { + v.Stop() + } + default: + } } } diff --git a/consensus/leader.go b/consensus/leader.go index 2f7766e19..1b10c9608 100644 --- a/consensus/leader.go +++ b/consensus/leader.go @@ -235,7 +235,7 @@ func (consensus *Consensus) onCommit(recvMsg *FBFTMessage) { Msg("[OnCommit] Failed finding a matching block for committed message") return } - commitPayload := signature.ConstructCommitPayload(consensus.Blockchain(), + commitPayload := signature.ConstructCommitPayload(consensus.Blockchain().Config(), blockObj.Epoch(), blockObj.Hash(), blockObj.NumberU64(), blockObj.Header().ViewID().Uint64()) logger = logger.With(). Uint64("MsgViewID", recvMsg.ViewID). diff --git a/consensus/signature/signature.go b/consensus/signature/signature.go index 3c419b03b..20226a381 100644 --- a/consensus/signature/signature.go +++ b/consensus/signature/signature.go @@ -8,18 +8,14 @@ import ( "github.com/harmony-one/harmony/internal/params" ) -type signatureChainReader interface { - Config() *params.ChainConfig -} - // ConstructCommitPayload returns the commit payload for consensus signatures. func ConstructCommitPayload( - chain signatureChainReader, epoch *big.Int, blockHash common.Hash, blockNum, viewID uint64, + config *params.ChainConfig, epoch *big.Int, blockHash common.Hash, blockNum, viewID uint64, ) []byte { blockNumBytes := make([]byte, 8) binary.LittleEndian.PutUint64(blockNumBytes, blockNum) commitPayload := append(blockNumBytes, blockHash.Bytes()...) - if !chain.Config().IsStaking(epoch) { + if !config.IsStaking(epoch) { return commitPayload } viewIDBytes := make([]byte, 8) diff --git a/consensus/threshold.go b/consensus/threshold.go index ecb54980a..11e65709e 100644 --- a/consensus/threshold.go +++ b/consensus/threshold.go @@ -46,7 +46,7 @@ func (consensus *Consensus) didReachPrepareQuorum() error { Msg("[didReachPrepareQuorum] Unparseable block data") return err } - commitPayload := signature.ConstructCommitPayload(consensus.Blockchain(), + commitPayload := signature.ConstructCommitPayload(consensus.Blockchain().Config(), blockObj.Epoch(), blockObj.Hash(), blockObj.NumberU64(), blockObj.Header().ViewID().Uint64()) // so by this point, everyone has committed to the blockhash of this block diff --git a/consensus/validator.go b/consensus/validator.go index 92008a91e..c67765cc8 100644 --- a/consensus/validator.go +++ b/consensus/validator.go @@ -164,7 +164,7 @@ func (consensus *Consensus) sendCommitMessages(blockObj *types.Block) { priKeys := consensus.getPriKeysInCommittee() // Sign commit signature on the received block and construct the p2p messages - commitPayload := signature.ConstructCommitPayload(consensus.Blockchain(), + commitPayload := signature.ConstructCommitPayload(consensus.Blockchain().Config(), blockObj.Epoch(), blockObj.Hash(), blockObj.NumberU64(), blockObj.Header().ViewID().Uint64()) p2pMsgs := consensus.constructP2pMessages(msg_pb.MessageType_COMMIT, commitPayload, priKeys) diff --git a/core/blockchain.go b/core/blockchain.go index 8afe622c7..facb9ed2c 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -255,13 +255,6 @@ type BlockChain interface { ReadValidatorStats( addr common.Address, ) (*types2.ValidatorStats, error) - // UpdateValidatorVotingPower writes the voting power for the committees. - UpdateValidatorVotingPower( - batch rawdb.DatabaseWriter, - block *types.Block, - newEpochSuperCommittee, currentEpochSuperCommittee *shard.State, - state *state.DB, - ) (map[common.Address]*types2.ValidatorStats, error) // ComputeAndUpdateAPR ... ComputeAndUpdateAPR( block *types.Block, now *big.Int, diff --git a/core/blockchain_impl.go b/core/blockchain_impl.go index f1d096842..4774b795f 100644 --- a/core/blockchain_impl.go +++ b/core/blockchain_impl.go @@ -2654,8 +2654,8 @@ func (bc *BlockChainImpl) ReadValidatorStats( return rawdb.ReadValidatorStats(bc.db, addr) } -func (bc *BlockChainImpl) UpdateValidatorVotingPower( - batch rawdb.DatabaseWriter, +func UpdateValidatorVotingPower( + bc BlockChain, block *types.Block, newEpochSuperCommittee, currentEpochSuperCommittee *shard.State, state *state.DB, @@ -2681,7 +2681,7 @@ func (bc *BlockChainImpl) UpdateValidatorVotingPower( // bc.db, currentValidator, currentEpochSuperCommittee.Epoch, // ) // rawdb.DeleteValidatorStats(bc.db, currentValidator) - stats, err := rawdb.ReadValidatorStats(bc.db, currentValidator) + stats, err := rawdb.ReadValidatorStats(bc.ChainDb(), currentValidator) if err != nil { stats = staking.NewEmptyStats() } @@ -2731,7 +2731,7 @@ func (bc *BlockChainImpl) UpdateValidatorVotingPower( networkWide := votepower.AggregateRosters(rosters) for key, value := range networkWide { - stats, err := rawdb.ReadValidatorStats(bc.db, key) + stats, err := rawdb.ReadValidatorStats(bc.ChainDb(), key) if err != nil { stats = staking.NewEmptyStats() } diff --git a/core/offchain.go b/core/offchain.go index 3f08b4f81..6ce7794e4 100644 --- a/core/offchain.go +++ b/core/offchain.go @@ -205,8 +205,8 @@ func (bc *BlockChainImpl) CommitOffChainData( if shardState, err := shard.DecodeWrapper( header.ShardState(), ); err == nil { - if stats, err := bc.UpdateValidatorVotingPower( - batch, block, shardState, currentSuperCommittee, state, + if stats, err := UpdateValidatorVotingPower( + bc, block, shardState, currentSuperCommittee, state, ); err != nil { utils.Logger(). Err(err). diff --git a/internal/chain/engine.go b/internal/chain/engine.go index 6e018dccf..71bb0d305 100644 --- a/internal/chain/engine.go +++ b/internal/chain/engine.go @@ -632,7 +632,7 @@ func payloadArgsFromCrossLink(cl types.CrossLink) payloadArgs { } func (args payloadArgs) constructPayload(chain engine.ChainReader) []byte { - return signature.ConstructCommitPayload(chain, args.epoch, args.blockHash, args.number, args.viewID) + return signature.ConstructCommitPayload(chain.Config(), args.epoch, args.blockHash, args.number, args.viewID) } type sigArgs struct { diff --git a/internal/chain/engine_test.go b/internal/chain/engine_test.go index 5a842088c..067b265ca 100644 --- a/internal/chain/engine_test.go +++ b/internal/chain/engine_test.go @@ -275,7 +275,7 @@ func (kp blsKeyPair) Pub() bls.SerializedPublicKey { func (kp blsKeyPair) Sign(block *types.Block) []byte { chain := &fakeBlockChain{config: *params.LocalnetChainConfig} - msg := consensus_sig.ConstructCommitPayload(chain, block.Epoch(), block.Hash(), + msg := consensus_sig.ConstructCommitPayload(chain.Config(), block.Epoch(), block.Hash(), block.Number().Uint64(), block.Header().ViewID().Uint64()) sig := kp.pri.SignHash(msg) diff --git a/internal/registry/registry.go b/internal/registry/registry.go index 98b69a3ef..448e14866 100644 --- a/internal/registry/registry.go +++ b/internal/registry/registry.go @@ -4,13 +4,16 @@ import ( "sync" "github.com/harmony-one/harmony/core" + "github.com/harmony-one/harmony/webhooks" ) // Registry consolidates services at one place. type Registry struct { - mu sync.Mutex - blockchain core.BlockChain - txPool *core.TxPool + mu sync.Mutex + blockchain core.BlockChain + beaconchain core.BlockChain + webHooks *webhooks.Hooks + txPool *core.TxPool } // New creates a new registry. @@ -35,6 +38,40 @@ func (r *Registry) GetBlockchain() core.BlockChain { return r.blockchain } +// SetBeaconchain sets the beaconchain to registry. +func (r *Registry) SetBeaconchain(bc core.BlockChain) *Registry { + r.mu.Lock() + defer r.mu.Unlock() + + r.beaconchain = bc + return r +} + +// GetBeaconchain gets the beaconchain from registry. +func (r *Registry) GetBeaconchain() core.BlockChain { + r.mu.Lock() + defer r.mu.Unlock() + + return r.beaconchain +} + +// SetWebHooks sets the webhooks to registry. +func (r *Registry) SetWebHooks(hooks *webhooks.Hooks) *Registry { + r.mu.Lock() + defer r.mu.Unlock() + + r.webHooks = hooks + return r +} + +// GetWebHooks gets the webhooks from registry. +func (r *Registry) GetWebHooks() *webhooks.Hooks { + r.mu.Lock() + defer r.mu.Unlock() + + return r.webHooks +} + // SetTxPool sets the txpool to registry. func (r *Registry) SetTxPool(txPool *core.TxPool) *Registry { r.mu.Lock() diff --git a/node/node_explorer.go b/node/node_explorer.go index d1c78d612..0dd731976 100644 --- a/node/node_explorer.go +++ b/node/node_explorer.go @@ -68,7 +68,7 @@ func (node *Node) explorerMessageHandler(ctx context.Context, msg *msg_pb.Messag return errBlockBeforeCommit } - commitPayload := signature.ConstructCommitPayload(node.Blockchain(), + commitPayload := signature.ConstructCommitPayload(node.Blockchain().Config(), block.Epoch(), block.Hash(), block.Number().Uint64(), block.Header().ViewID().Uint64()) if !aggSig.VerifyHash(mask.AggregatePublic, commitPayload) { utils.Logger(). diff --git a/node/node_handler.go b/node/node_handler.go index acc4afc26..a7e496e98 100644 --- a/node/node_handler.go +++ b/node/node_handler.go @@ -25,7 +25,6 @@ import ( "github.com/harmony-one/harmony/staking/slash" staking "github.com/harmony-one/harmony/staking/types" "github.com/harmony-one/harmony/webhooks" - "github.com/pkg/errors" ) const p2pMsgPrefixSize = 5 @@ -328,38 +327,6 @@ func getCrosslinkHeadersForShards(shardChain core.BlockChain, curBlock *types.Bl return headers, nil } -// VerifyNewBlock is called by consensus participants to verify the block (account model) they are -// running consensus on. -func VerifyNewBlock(nodeConfig *nodeconfig.ConfigType, blockChain core.BlockChain, beaconChain core.BlockChain) func(*types.Block) error { - return func(newBlock *types.Block) error { - if err := blockChain.ValidateNewBlock(newBlock, beaconChain); err != nil { - if hooks := nodeConfig.WebHooks.Hooks; hooks != nil { - if p := hooks.ProtocolIssues; p != nil { - url := p.OnCannotCommit - go func() { - webhooks.DoPost(url, map[string]interface{}{ - "bad-header": newBlock.Header(), - "reason": err.Error(), - }) - }() - } - } - utils.Logger().Error(). - Str("blockHash", newBlock.Hash().Hex()). - Int("numTx", len(newBlock.Transactions())). - Int("numStakingTx", len(newBlock.StakingTransactions())). - Err(err). - Msg("[VerifyNewBlock] Cannot Verify New Block!!!") - return errors.Errorf( - "[VerifyNewBlock] Cannot Verify New Block!!! block-hash %s txn-count %d", - newBlock.Hash().Hex(), - len(newBlock.Transactions()), - ) - } - return nil - } -} - // PostConsensusProcessing is called by consensus participants, after consensus is done, to: // 1. [leader] send new block to the client // 2. [leader] send cross shard tx receipts to destination shard @@ -373,6 +340,7 @@ func (node *Node) PostConsensusProcessing(newBlock *types.Block) error { node.BroadcastCXReceipts(newBlock) } else { if node.Consensus.Mode() != consensus.Listening { + numSignatures := node.Consensus.NumSignaturesIncludedInBlock(newBlock) utils.Logger().Info(). Uint64("blockNum", newBlock.NumberU64()). Uint64("epochNum", newBlock.Epoch().Uint64()). @@ -380,11 +348,10 @@ func (node *Node) PostConsensusProcessing(newBlock *types.Block) error { Str("blockHash", newBlock.Hash().String()). Int("numTxns", len(newBlock.Transactions())). Int("numStakingTxns", len(newBlock.StakingTransactions())). - Uint32("numSignatures", node.Consensus.NumSignaturesIncludedInBlock(newBlock)). + Uint32("numSignatures", numSignatures). Msg("BINGO !!! Reached Consensus") - numSig := float64(node.Consensus.NumSignaturesIncludedInBlock(newBlock)) - node.Consensus.UpdateValidatorMetrics(numSig, float64(newBlock.NumberU64())) + node.Consensus.UpdateValidatorMetrics(float64(numSignatures), float64(newBlock.NumberU64())) // 1% of the validator also need to do broadcasting rnd := rand.Intn(100) diff --git a/node/node_handler_test.go b/node/node_handler_test.go index 25d966f46..3de291839 100644 --- a/node/node_handler_test.go +++ b/node/node_handler_test.go @@ -103,7 +103,7 @@ func TestVerifyNewBlock(t *testing.T) { t.Fatal("cannot get blockchain") } reg := registry.New().SetBlockchain(blockchain) - consensus, err := consensus.New( + consensusObj, err := consensus.New( host, shard.BeaconChainShardID, multibls.GetPrivateKeys(blsKey), reg, decider, 3, false, ) if err != nil { @@ -112,7 +112,7 @@ func TestVerifyNewBlock(t *testing.T) { archiveMode := make(map[uint32]bool) archiveMode[0] = true archiveMode[1] = false - node := New(host, consensus, engine, collection, nil, nil, nil, archiveMode, nil, reg) + node := New(host, consensusObj, engine, collection, nil, nil, nil, archiveMode, nil, reg) txs := make(map[common.Address]types.Transactions) stks := staking.StakingTransactions{} @@ -129,7 +129,7 @@ func TestVerifyNewBlock(t *testing.T) { // work around vrf verification as it's tested in another test. node.Blockchain().Config().VRFEpoch = big.NewInt(2) - if err := VerifyNewBlock(nil, node.Blockchain(), node.Beaconchain())(block); err != nil { + if err := consensus.VerifyNewBlock(nil, node.Blockchain(), node.Beaconchain())(block); err != nil { t.Error("New block is not verified successfully:", err) } } diff --git a/node/node_newblock_test.go b/node/node_newblock_test.go index 492175b1d..39affacab 100644 --- a/node/node_newblock_test.go +++ b/node/node_newblock_test.go @@ -46,14 +46,15 @@ func TestFinalizeNewBlockAsync(t *testing.T) { decider := quorum.NewDecider( quorum.SuperMajorityVote, shard.BeaconChainShardID, ) - consensus, err := consensus.New( - host, shard.BeaconChainShardID, multibls.GetPrivateKeys(blsKey), nil, decider, 3, false, + reg := registry.New().SetBlockchain(blockchain).SetBeaconchain(blockchain) + consensusObj, err := consensus.New( + host, shard.BeaconChainShardID, multibls.GetPrivateKeys(blsKey), reg, decider, 3, false, ) if err != nil { t.Fatalf("Cannot craeate consensus: %v", err) } - node := New(host, consensus, engine, collection, nil, nil, nil, nil, nil, registry.New().SetBlockchain(blockchain)) + node := New(host, consensusObj, engine, collection, nil, nil, nil, nil, nil, registry.New().SetBlockchain(blockchain)) node.Worker.UpdateCurrent() @@ -71,7 +72,7 @@ func TestFinalizeNewBlockAsync(t *testing.T) { commitSigs, func() uint64 { return 0 }, common.Address{}, nil, nil, ) - if err := VerifyNewBlock(nil, blockchain, nil)(block); err != nil { + if err := consensus.VerifyNewBlock(nil, blockchain, nil)(block); err != nil { t.Error("New block is not verified successfully:", err) } diff --git a/staking/slash/double-sign.go b/staking/slash/double-sign.go index 6c871f992..aaaea0130 100644 --- a/staking/slash/double-sign.go +++ b/staking/slash/double-sign.go @@ -248,7 +248,7 @@ func Verify( publicKey.Add(publicKeyObj) } // slash verification only happens in staking era, therefore want commit payload for staking epoch - commitPayload := consensus_sig.ConstructCommitPayload(chain, + commitPayload := consensus_sig.ConstructCommitPayload(chain.Config(), candidate.Evidence.Epoch, ballot.BlockHeaderHash, candidate.Evidence.Height, candidate.Evidence.ViewID) utils.Logger().Debug(). Uint64("epoch", candidate.Evidence.Epoch.Uint64()). diff --git a/staking/slash/double-sign_test.go b/staking/slash/double-sign_test.go index 470a8ae1d..7bed53b94 100644 --- a/staking/slash/double-sign_test.go +++ b/staking/slash/double-sign_test.go @@ -1151,8 +1151,7 @@ func (kp blsKeyPair) Pub() bls.SerializedPublicKey { } func (kp blsKeyPair) Sign(block *types.Block) []byte { - chain := &fakeBlockChain{config: *params.LocalnetChainConfig} - msg := consensus_sig.ConstructCommitPayload(chain, block.Epoch(), block.Hash(), + msg := consensus_sig.ConstructCommitPayload(params.LocalnetChainConfig, block.Epoch(), block.Hash(), block.Number().Uint64(), block.Header().ViewID().Uint64()) sig := kp.pri.SignHash(msg) diff --git a/staking/verify/verify.go b/staking/verify/verify.go index 38783d4db..efc7e18ce 100644 --- a/staking/verify/verify.go +++ b/staking/verify/verify.go @@ -1,54 +1 @@ package verify - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/harmony-one/bls/ffi/go/bls" - "github.com/harmony-one/harmony/consensus/quorum" - "github.com/harmony-one/harmony/consensus/signature" - "github.com/harmony-one/harmony/core" - bls_cosi "github.com/harmony-one/harmony/crypto/bls" - "github.com/harmony-one/harmony/shard" - "github.com/pkg/errors" -) - -var ( - errQuorumVerifyAggSign = errors.New("insufficient voting power to verify aggregate sig") - errAggregateSigFail = errors.New("could not verify hash of aggregate signature") -) - -// AggregateSigForCommittee .. -func AggregateSigForCommittee( - chain core.BlockChain, - committee *shard.Committee, - decider quorum.Decider, - aggSignature *bls.Sign, - hash common.Hash, - blockNum, viewID uint64, - epoch *big.Int, - bitmap []byte, -) error { - committerKeys, err := committee.BLSPublicKeys() - if err != nil { - return err - } - mask, err := bls_cosi.NewMask(committerKeys, nil) - if err != nil { - return err - } - if err := mask.SetMask(bitmap); err != nil { - return err - } - - if !decider.IsQuorumAchievedByMask(mask) { - return errQuorumVerifyAggSign - } - - commitPayload := signature.ConstructCommitPayload(chain, epoch, hash, blockNum, viewID) - if !aggSignature.VerifyHash(mask.AggregatePublic, commitPayload) { - return errAggregateSigFail - } - - return nil -}