From 073064170c874bb19741108d0833b1bf019b439b Mon Sep 17 00:00:00 2001 From: Jimmy Hu Date: Mon, 15 Apr 2019 18:19:46 +0800 Subject: core: implement DKG success (#362) * vendor: sync to latest core * core: implmenet dkg success * cmd: govtool: add DKGSuccess --- .gitignore | 4 + cmd/govtool/main.go | 10 ++ core/governance.go | 9 ++ core/vm/oracle_contract_abi.go | 47 ++++++ core/vm/oracle_contracts.go | 175 +++++++++++++++++---- core/vm/oracle_contracts_test.go | 16 +- dex/governance.go | 14 ++ params/config.go | 8 +- .../dexon-consensus/core/agreement-mgr.go | 12 +- .../dexon-consensus/core/blockchain.go | 7 + .../dexon-consensus/core/configuration-chain.go | 1 + .../dexon-consensus/core/consensus.go | 20 +++ .../dexon-consensus/core/dkg-tsig-protocol.go | 18 ++- .../dexon-consensus/core/interfaces.go | 6 + .../dexon-consensus/core/types/dkg/dkg.go | 34 +++- .../dexon-consensus/core/utils/crypto.go | 27 ++++ .../dexon-consensus/core/utils/round-event.go | 2 +- .../dexon-consensus/core/utils/signer.go | 7 + vendor/vendor.json | 46 +++--- 19 files changed, 391 insertions(+), 72 deletions(-) diff --git a/.gitignore b/.gitignore index f3ec219c7..1e62cbb81 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,7 @@ profile.cov test/Dexon.* test/*.log dex/transactions.rlp + +# consensus +vendor/github.com/dexon-foundation/mcl/lib/*.dylib +vendor/github.com/dexon-foundation/bls/lib/*.dylib diff --git a/cmd/govtool/main.go b/cmd/govtool/main.go index 239c95003..1425b9faf 100644 --- a/cmd/govtool/main.go +++ b/cmd/govtool/main.go @@ -90,6 +90,16 @@ func decodeInput(ctx *cli.Context) error { utils.Fatalf("%s", err) } fmt.Println(finalize) + case "addDKGSuccess": + var Success []byte + if err := method.Inputs.Unpack(&Success, arguments); err != nil { + utils.Fatalf("%s", err) + } + var success dkgTypes.Success + if err := rlp.DecodeBytes(Success, &success); err != nil { + utils.Fatalf("%s", err) + } + fmt.Println(success) case "report": args := struct { Type *big.Int diff --git a/core/governance.go b/core/governance.go index 23e528a2f..c67b53f27 100644 --- a/core/governance.go +++ b/core/governance.go @@ -310,6 +310,15 @@ func (g *Governance) IsDKGFinal(round uint64) bool { return count >= threshold } +func (g *Governance) IsDKGSuccess(round uint64) bool { + s := g.GetStateForDKGAtRound(round) + if s == nil { + return false + } + return s.DKGSuccessesCount().Uint64() >= + uint64(coreUtils.GetDKGValidThreshold(g.Configuration(round))) +} + func (g *Governance) MinGasPrice(round uint64) *big.Int { return g.GetStateForConfigAtRound(round).MinGasPrice() } diff --git a/core/vm/oracle_contract_abi.go b/core/vm/oracle_contract_abi.go index bd99c0cc7..dc44552a2 100644 --- a/core/vm/oracle_contract_abi.go +++ b/core/vm/oracle_contract_abi.go @@ -22,6 +22,25 @@ package vm const GovernanceABIJSON = ` [ + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "dkgSuccesses", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { "constant": true, "inputs": [], @@ -189,6 +208,20 @@ const GovernanceABIJSON = ` "stateMutability": "view", "type": "function" }, + { + "constant": true, + "inputs": [], + "name": "dkgSuccessesCount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { "constant": true, "inputs": [ @@ -1026,6 +1059,20 @@ const GovernanceABIJSON = ` "stateMutability": "nonpayable", "type": "function" }, + { + "constant": false, + "inputs": [ + { + "name": "Success", + "type": "bytes" + } + ], + "name": "addDKGSuccess", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { "constant": false, "inputs": [ diff --git a/core/vm/oracle_contracts.go b/core/vm/oracle_contracts.go index 832195f0e..aef1ab72b 100644 --- a/core/vm/oracle_contracts.go +++ b/core/vm/oracle_contracts.go @@ -78,6 +78,8 @@ const ( dkgReadysCountLoc dkgFinalizedLoc dkgFinalizedsCountLoc + dkgSuccessLoc + dkgSuccessesCountLoc ownerLoc minStakeLoc lockupPeriodLoc @@ -766,6 +768,37 @@ func (s *GovernanceState) ResetDKGFinalizedsCount() { s.setStateBigInt(big.NewInt(dkgFinalizedsCountLoc), big.NewInt(0)) } +// mapping(address => bool) public dkgSuccesses; +func (s *GovernanceState) DKGSuccess(addr common.Address) bool { + mapLoc := s.getMapLoc(big.NewInt(dkgSuccessLoc), addr.Bytes()) + return s.getStateBigInt(mapLoc).Cmp(big.NewInt(0)) != 0 +} +func (s *GovernanceState) PutDKGSuccess(addr common.Address, success bool) { + mapLoc := s.getMapLoc(big.NewInt(dkgSuccessLoc), addr.Bytes()) + res := big.NewInt(0) + if success { + res = big.NewInt(1) + } + s.setStateBigInt(mapLoc, res) +} +func (s *GovernanceState) ClearDKGSuccesses(dkgSet map[coreTypes.NodeID]struct{}) { + for id := range dkgSet { + s.PutDKGSuccess(IdToAddress(id), false) + } +} + +// uint256 public dkgSuccessesCount; +func (s *GovernanceState) DKGSuccessesCount() *big.Int { + return s.getStateBigInt(big.NewInt(dkgSuccessesCountLoc)) +} +func (s *GovernanceState) IncDKGSuccessesCount() { + s.setStateBigInt(big.NewInt(dkgSuccessesCountLoc), + new(big.Int).Add(s.getStateBigInt(big.NewInt(dkgSuccessesCountLoc)), big.NewInt(1))) +} +func (s *GovernanceState) ResetDKGSuccessesCount() { + s.setStateBigInt(big.NewInt(dkgSuccessesCountLoc), big.NewInt(0)) +} + // address public owner; func (s *GovernanceState) Owner() common.Address { val := s.getState(common.BigToHash(big.NewInt(ownerLoc))) @@ -1355,6 +1388,8 @@ func (g *GovernanceContract) clearDKG() { g.state.ResetDKGMPKReadysCount() g.state.ClearDKGFinalizeds(dkgSet) g.state.ResetDKGFinalizedsCount() + g.state.ClearDKGSuccesses(dkgSet) + g.state.ResetDKGSuccessesCount() } func (g *GovernanceContract) fineFailStopDKG(threshold int) { @@ -1626,6 +1661,40 @@ func (g *GovernanceContract) addDKGFinalize(finalize []byte) ([]byte, error) { return g.useGas(GovernanceActionGasCost) } +func (g *GovernanceContract) addDKGSuccess(success []byte) ([]byte, error) { + caller := g.contract.Caller() + + var dkgSuccess dkgTypes.Success + if err := rlp.DecodeBytes(success, &dkgSuccess); err != nil { + return nil, errExecutionReverted + } + round := big.NewInt(int64(dkgSuccess.Round)) + if round.Uint64() != g.evm.Round.Uint64()+1 { + return nil, errExecutionReverted + } + + if dkgSuccess.Reset != g.state.DKGResetCount(round).Uint64() { + return nil, errExecutionReverted + } + + // DKGFInalize must belongs to someone in DKG set. + if !g.inNotarySet(round, dkgSuccess.ProposerID) { + return nil, errExecutionReverted + } + + verified, _ := coreUtils.VerifyDKGSuccessSignature(&dkgSuccess) + if !verified { + return nil, errExecutionReverted + } + + if !g.state.DKGSuccess(caller) { + g.state.PutDKGSuccess(caller, true) + g.state.IncDKGSuccessesCount() + } + + return g.useGas(GovernanceActionGasCost) +} + func (g *GovernanceContract) updateConfiguration(cfg *rawConfigStruct) ([]byte, error) { // Only owner can update configuration. if g.contract.Caller() != g.state.Owner() { @@ -1972,9 +2041,9 @@ func (g *GovernanceContract) resetDKG(newSignedCRS []byte) ([]byte, error) { } // Extend the the current round. - // target = (80 + 100 * DKGResetCount)% + // target = (85 + 100 * DKGResetCount)% target := new(big.Int).Add( - big.NewInt(80), + big.NewInt(85), new(big.Int).Mul(big.NewInt(100), resetCount)) roundHeight := g.state.RoundHeight(round) @@ -1989,37 +2058,42 @@ func (g *GovernanceContract) resetDKG(newSignedCRS []byte) ([]byte, error) { targetBlockNum.Quo(targetBlockNum, big.NewInt(100)) targetBlockNum.Add(targetBlockNum, roundHeight) - // Check if current block over 80% of current round. + // Check if current block over 85%of current round. blockHeight := g.evm.Context.BlockNumber if blockHeight.Cmp(targetBlockNum) < 0 { return nil, errExecutionReverted } - // Check if next DKG did not success. - // Calculate 2f + 1 - threshold := 2*g.configNotarySetSize(g.evm.Round).Uint64()/3 + 1 tsigThreshold := coreUtils.GetDKGThreshold(&coreTypes.Config{ - NotarySetSize: uint32(g.configNotarySetSize(g.evm.Round).Uint64())}) - - // If 2f + 1 of DKG set is finalized, check if DKG succeeded. - if g.state.DKGFinalizedsCount().Uint64() >= threshold { - gpk, err := g.coreDKGUtils.NewGroupPublicKey(&g.state, nextRound, tsigThreshold) - if gpk, ok := gpk.(*dkgTypes.GroupPublicKey); ok { - nextRound := new(big.Int).Add(g.evm.Round, big.NewInt(1)) - if len(gpk.QualifyNodeIDs) < coreUtils.GetDKGValidThreshold(&coreTypes.Config{ - NotarySetSize: uint32(g.configNotarySetSize(nextRound).Uint64())}) { - err = dkgTypes.ErrNotReachThreshold + NotarySetSize: uint32(g.configNotarySetSize(nextRound).Uint64())}) + // Check if next DKG has not enough of success. + if g.state.DKGSuccessesCount().Uint64() >= + uint64(coreUtils.GetDKGValidThreshold(&coreTypes.Config{ + NotarySetSize: uint32(g.configNotarySetSize(nextRound).Uint64()), + })) { + // Check if next DKG did not success. + // Calculate 2f + 1 + threshold := 2*g.configNotarySetSize(nextRound).Uint64()/3 + 1 + + // If 2f + 1 of DKG set is finalized, check if DKG succeeded. + if g.state.DKGFinalizedsCount().Uint64() >= threshold { + gpk, err := g.coreDKGUtils.NewGroupPublicKey(&g.state, nextRound, tsigThreshold) + if gpk, ok := gpk.(*dkgTypes.GroupPublicKey); ok { + if len(gpk.QualifyNodeIDs) < coreUtils.GetDKGValidThreshold(&coreTypes.Config{ + NotarySetSize: uint32(g.configNotarySetSize(nextRound).Uint64())}) { + err = dkgTypes.ErrNotReachThreshold + } } - } - // DKG success. - if err == nil { - return nil, errExecutionReverted - } - switch err { - case dkgTypes.ErrNotReachThreshold, dkgTypes.ErrInvalidThreshold: - default: - return nil, errExecutionReverted + // DKG success. + if err == nil { + return nil, errExecutionReverted + } + switch err { + case dkgTypes.ErrNotReachThreshold, dkgTypes.ErrInvalidThreshold: + default: + return nil, errExecutionReverted + } } } @@ -2044,7 +2118,9 @@ func (g *GovernanceContract) resetDKG(newSignedCRS []byte) ([]byte, error) { prevCRS = crypto.Keccak256Hash(prevCRS[:]) } - dkgGPK, err := g.coreDKGUtils.NewGroupPublicKey(state, round, tsigThreshold) + dkgGPK, err := g.coreDKGUtils.NewGroupPublicKey(state, round, + coreUtils.GetDKGThreshold(&coreTypes.Config{ + NotarySetSize: uint32(g.configNotarySetSize(round).Uint64())})) if err != nil { return nil, errExecutionReverted } @@ -2056,19 +2132,17 @@ func (g *GovernanceContract) resetDKG(newSignedCRS []byte) ([]byte, error) { return nil, errExecutionReverted } - newRound := new(big.Int).Add(g.evm.Round, big.NewInt(1)) - // Clear DKG states for next round. g.clearDKG() - g.state.SetDKGRound(newRound) + g.state.SetDKGRound(nextRound) // Save new CRS into state and increase round. newCRS := crypto.Keccak256(newSignedCRS) crs := common.BytesToHash(newCRS) g.state.SetCRS(crs) - g.state.SetCRSRound(newRound) - g.state.emitCRSProposed(newRound, crs) + g.state.SetCRSRound(nextRound) + g.state.emitCRSProposed(nextRound, crs) // Increase reset count. g.state.IncDKGResetCount(nextRound) @@ -2122,6 +2196,12 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re return nil, errExecutionReverted } return g.addDKGFinalize(Finalize) + case "addDKGSuccess": + var Success []byte + if err := method.Inputs.Unpack(&Success, arguments); err != nil { + return nil, errExecutionReverted + } + return g.addDKGSuccess(Success) case "nodesLength": res, err := method.Outputs.Pack(g.state.LenNodes()) if err != nil { @@ -2264,6 +2344,24 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re return nil, errExecutionReverted } return res, nil + case "dkgSuccesses": + addr := common.Address{} + if err := method.Inputs.Unpack(&addr, arguments); err != nil { + return nil, errExecutionReverted + } + finalized := g.state.DKGSuccess(addr) + res, err := method.Outputs.Pack(finalized) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "dkgSuccessesCount": + count := g.state.DKGSuccessesCount() + res, err := method.Outputs.Pack(count) + if err != nil { + return nil, errExecutionReverted + } + return res, nil case "dkgMasterPublicKeys": offset := new(big.Int) if err := method.Inputs.Unpack(&offset, arguments); err != nil { @@ -2630,6 +2728,21 @@ func PackAddDKGFinalize(final *dkgTypes.Finalize) ([]byte, error) { return data, nil } +func PackAddDKGSuccess(final *dkgTypes.Success) ([]byte, error) { + method := GovernanceABI.Name2Method["addDKGSuccess"] + encoded, err := rlp.EncodeToBytes(final) + if err != nil { + return nil, err + } + + res, err := method.Inputs.Pack(encoded) + if err != nil { + return nil, err + } + data := append(method.Id(), res...) + return data, nil +} + func PackReportForkVote(vote1, vote2 *coreTypes.Vote) ([]byte, error) { method := GovernanceABI.Name2Method["report"] diff --git a/core/vm/oracle_contracts_test.go b/core/vm/oracle_contracts_test.go index 6b6eebb9e..bcb6eb01b 100644 --- a/core/vm/oracle_contracts_test.go +++ b/core/vm/oracle_contracts_test.go @@ -984,6 +984,8 @@ func (g *OracleContractsTestSuite) TestResetDKG() { g.s.ResetDKGMPKReadysCount() g.s.ClearDKGFinalizeds(dkgSet) g.s.ResetDKGFinalizedsCount() + g.s.ClearDKGSuccesses(dkgSet) + g.s.ResetDKGSuccessesCount() g.s.SetDKGRound(big.NewInt(int64(round))) } @@ -1033,6 +1035,9 @@ func (g *OracleContractsTestSuite) TestResetDKG() { // Prepare Finalized. g.s.PutDKGFinalized(addr, true) g.s.IncDKGFinalizedsCount() + // Prepare Success. + g.s.PutDKGSuccess(addr, true) + g.s.IncDKGSuccessesCount() } i += 1 } @@ -1049,6 +1054,10 @@ func (g *OracleContractsTestSuite) TestResetDKG() { for _, addr := range addrs[round] { g.Require().True(g.s.DKGFinalized(addr)) } + g.Require().Equal(int64(dkgSetSize), g.s.DKGSuccessesCount().Int64()) + for _, addr := range addrs[round] { + g.Require().True(g.s.DKGSuccess(addr)) + } } } @@ -1088,7 +1097,7 @@ func (g *OracleContractsTestSuite) TestResetDKG() { g.s.IncDKGFinalizedsCount() g.context.BlockNumber = big.NewInt( - roundHeight*int64(round) + roundHeight*int64(r) + roundHeight*80/100) + roundHeight*int64(round) + roundHeight*int64(r) + roundHeight*85/100) _, addr := newPrefundAccount(g.stateDB) newCRS := randomBytes(common.HashLength, common.HashLength) input, err := GovernanceABI.ABI.Pack("resetDKG", newCRS) @@ -1114,6 +1123,11 @@ func (g *OracleContractsTestSuite) TestResetDKG() { for _, addr := range addrs[round+1] { g.Require().False(g.s.DKGFinalized(addr)) } + // Test if Success is purged. + g.Require().Equal(int64(0), g.s.DKGSuccessesCount().Int64()) + for _, addr := range addrs[round+1] { + g.Require().False(g.s.DKGSuccess(addr)) + } g.Require().Equal(int64(r+1), g.s.DKGResetCount(roundPlusOne).Int64()) diff --git a/dex/governance.go b/dex/governance.go index b8dcf1589..ec09969b0 100644 --- a/dex/governance.go +++ b/dex/governance.go @@ -177,6 +177,20 @@ func (d *DexconGovernance) AddDKGFinalize(final *dkgTypes.Finalize) { } } +// AddDKGSuccess adds a DKG success message. +func (d *DexconGovernance) AddDKGSuccess(success *dkgTypes.Success) { + data, err := vm.PackAddDKGSuccess(success) + if err != nil { + log.Error("Failed to pack addDKGSuccess input", "err", err) + return + } + + err = d.sendGovTx(context.Background(), data) + if err != nil { + log.Error("Failed to send addDKGSuccess tx", "err", err) + } +} + // ReportForkVote reports a node for forking votes. func (d *DexconGovernance) ReportForkVote(vote1, vote2 *coreTypes.Vote) { data, err := vm.PackReportForkVote(vote1, vote2) diff --git a/params/config.go b/params/config.go index 0fde3b2ee..eef23c215 100644 --- a/params/config.go +++ b/params/config.go @@ -26,10 +26,10 @@ import ( // Genesis hashes to enforce below configs on. var ( - MainnetGenesisHash = common.HexToHash("0x55f87cf5428a78a015d06088cb76b4f50afa7b081a45a25dbf0ae7ffb2366b98") - TestnetGenesisHash = common.HexToHash("0xd3fdd64dfeed341be98d39732f65c8b31dbb72a703c1b91083b6d2bf2f8f184f") - TaipeiGenesisHash = common.HexToHash("0xec0bff2d28a4cb4a2b6a689ee71f450ec56d0438d0fcb4ef18c4c6a231dc8df4") - YilanGenesisHash = common.HexToHash("0x6618f722c32f044ecd9ce09f02efc9757744762a6d7e12c4bd0aedc6b83ae92b") + MainnetGenesisHash = common.HexToHash("0xc8f6f69570e8eb740f3d74995702f4fc4dfa613ec56a0cebf941cc035606099b") + TestnetGenesisHash = common.HexToHash("0x7d8700a7a731162880adff4f21398a901c0b75d907bec8f4eac51460f94cb846") + TaipeiGenesisHash = common.HexToHash("0x5929cb70fe4ba22dce821b2efca737a1874a0f5a34f3ffb9a1e157516622e20b") + YilanGenesisHash = common.HexToHash("0xdcdafc044c24d728c6149ecfada746d8de6e59fc5d18063caf7950badc1df12e") ) // TrustedCheckpoints associates each known checkpoint with the genesis hash of diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go index 4597fe92b..f65903d25 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go @@ -564,11 +564,13 @@ func (mgr *agreementMgr) baRoutineForOneRound( default: } nextHeight, nextTime = mgr.bcModule.nextBlock() - if isStop(restartPos) { - break - } - if nextHeight > restartPos.Height { - break + if nextHeight != notReadyHeight { + if isStop(restartPos) { + break + } + if nextHeight > restartPos.Height { + break + } } mgr.logger.Debug("BlockChain not ready!!!", "old", oldPos, "restart", restartPos, "next", nextHeight) diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/blockchain.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/blockchain.go index 1efd867e7..4fae221c7 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/blockchain.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/blockchain.go @@ -21,6 +21,7 @@ import ( "bytes" "errors" "fmt" + "math" "sort" "sync" "time" @@ -49,6 +50,8 @@ var ( ErrMissingRandomness = errors.New("missing block randomness") ) +const notReadyHeight uint64 = math.MaxUint64 + type pendingBlockRecord struct { position types.Position block *types.Block @@ -384,6 +387,10 @@ func (bc *blockChain) nextBlock() (uint64, time.Time) { if tip == nil { return types.GenesisHeight, bc.dMoment } + if tip != bc.lastDelivered { + // If tip is not delivered, we should not proceed to next block. + return notReadyHeight, time.Time{} + } return tip.Position.Height + 1, tip.Timestamp.Add(config.minBlockInterval) } diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/configuration-chain.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/configuration-chain.go index e9e04a28c..4e70ff087 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/configuration-chain.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/configuration-chain.go @@ -400,6 +400,7 @@ func (cc *configurationChain) runDKGPhaseNine(round uint64, reset uint64) error cc.db.PutDKGPrivateKey(round, reset, *signer.privateKey); err != nil { return err } + cc.dkg.proposeSuccess() cc.dkgResult.Lock() defer cc.dkgResult.Unlock() cc.dkgSigner[round] = signer diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go index 968b90e99..ba7d8fd60 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go @@ -496,6 +496,16 @@ func (recv *consensusDKGReceiver) ProposeDKGFinalize(final *typesDKG.Finalize) { recv.gov.AddDKGFinalize(final) } +// ProposeDKGSuccess propose a DKGSuccess message. +func (recv *consensusDKGReceiver) ProposeDKGSuccess(success *typesDKG.Success) { + if err := recv.signer.SignDKGSuccess(success); err != nil { + recv.logger.Error("Failed to sign DKG successize", "error", err) + return + } + recv.logger.Debug("Calling Governance.AddDKGSuccess", "success", success) + recv.gov.AddDKGSuccess(success) +} + // Consensus implements DEXON Consensus algorithm. type Consensus struct { // Node Info. @@ -818,6 +828,12 @@ func (con *Consensus) prepare(initBlock *types.Block) (err error) { "reset", e.Reset) return false } + if !con.gov.IsDKGSuccess(nextRound) { + con.logger.Error("Next DKG is not success, reset it", + "round", e.Round, + "reset", e.Reset) + return false + } gpk, err := typesDKG.NewGroupPublicKey( nextRound, con.gov.DKGMasterPublicKeys(nextRound), @@ -1132,6 +1148,10 @@ func (con *Consensus) generateBlockRandomness(blocks []*types.Block) { "block", block, "result", result) con.network.BroadcastAgreementResult(result) + if err := con.deliverFinalizedBlocks(); err != nil { + con.logger.Error("Failed to deliver finalized block", + "error", err) + } } }(block) } diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/dkg-tsig-protocol.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/dkg-tsig-protocol.go index 0612bda4b..8383ad118 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/dkg-tsig-protocol.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/dkg-tsig-protocol.go @@ -102,6 +102,9 @@ type dkgReceiver interface { // ProposeDKGFinalize propose a DKGFinalize message. ProposeDKGFinalize(final *typesDKG.Finalize) + + // ProposeDKGSuccess propose a DKGSuccess message. + ProposeDKGSuccess(final *typesDKG.Success) } type dkgProtocol struct { @@ -487,10 +490,13 @@ func (d *dkgProtocol) processPrivateShare( if _, exist := d.antiComplaintReceived[prvShare.ReceiverID]; !exist { d.antiComplaintReceived[prvShare.ReceiverID] = make(map[types.NodeID]struct{}) + } + if _, exist := + d.antiComplaintReceived[prvShare.ReceiverID][prvShare.ProposerID]; !exist { d.recv.ProposeDKGAntiNackComplaint(prvShare) + d.antiComplaintReceived[prvShare.ReceiverID][prvShare.ProposerID] = + struct{}{} } - d.antiComplaintReceived[prvShare.ReceiverID][prvShare.ProposerID] = - struct{}{} } return nil } @@ -511,6 +517,14 @@ func (d *dkgProtocol) proposeFinalize() { }) } +func (d *dkgProtocol) proposeSuccess() { + d.recv.ProposeDKGSuccess(&typesDKG.Success{ + ProposerID: d.ID, + Round: d.round, + Reset: d.reset, + }) +} + func (d *dkgProtocol) recoverShareSecret(qualifyIDs dkg.IDs) ( *dkgShareSecret, error) { if len(qualifyIDs) < d.threshold { diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/interfaces.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/interfaces.go index c16c624e3..c88b3dcb4 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/interfaces.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/interfaces.go @@ -141,6 +141,12 @@ type Governance interface { // IsDKGFinal checks if DKG is final. IsDKGFinal(round uint64) bool + // AddDKGSuccess adds a DKG success message. + AddDKGSuccess(success *typesDKG.Success) + + // IsDKGSuccess checks if DKG is success. + IsDKGSuccess(round uint64) bool + // ReportForkVote reports a node for forking votes. ReportForkVote(vote1, vote2 *types.Vote) diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/dkg/dkg.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/types/dkg/dkg.go index 868f0da17..cb921e586 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/dkg/dkg.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/types/dkg/dkg.go @@ -242,6 +242,11 @@ func (c *Complaint) DecodeRLP(s *rlp.Stream) error { return nil } +// IsNack returns true if it's a nack complaint in DKG protocol. +func (c *Complaint) IsNack() bool { + return len(c.PrivateShare.Signature.Signature) == 0 +} + // PartialSignature describe a partial signature in DKG protocol. type PartialSignature struct { ProposerID types.NodeID `json:"proposer_id"` @@ -251,7 +256,7 @@ type PartialSignature struct { Signature crypto.Signature `json:"signature"` } -// MPKReady describe a dig ready message in DKG protocol. +// MPKReady describe a dkg ready message in DKG protocol. type MPKReady struct { ProposerID types.NodeID `json:"proposer_id"` Round uint64 `json:"round"` @@ -275,7 +280,7 @@ func (ready *MPKReady) Equal(other *MPKReady) bool { bytes.Compare(ready.Signature.Signature, other.Signature.Signature) == 0 } -// Finalize describe a dig finalize message in DKG protocol. +// Finalize describe a dkg finalize message in DKG protocol. type Finalize struct { ProposerID types.NodeID `json:"proposer_id"` Round uint64 `json:"round"` @@ -299,9 +304,28 @@ func (final *Finalize) Equal(other *Finalize) bool { bytes.Compare(final.Signature.Signature, other.Signature.Signature) == 0 } -// IsNack returns true if it's a nack complaint in DKG protocol. -func (c *Complaint) IsNack() bool { - return len(c.PrivateShare.Signature.Signature) == 0 +// Success describe a dkg success message in DKG protocol. +type Success struct { + ProposerID types.NodeID `json:"proposer_id"` + Round uint64 `json:"round"` + Reset uint64 `json:"reset"` + Signature crypto.Signature `json:"signature"` +} + +func (s *Success) String() string { + return fmt.Sprintf("DKGSuccess{SP:%s Round:%d Reset:%d}", + s.ProposerID.String()[:6], + s.Round, + s.Reset) +} + +// Equal check equality of two Success instances. +func (s *Success) Equal(other *Success) bool { + return s.ProposerID.Equal(other.ProposerID) && + s.Round == other.Round && + s.Reset == other.Reset && + s.Signature.Type == other.Signature.Type && + bytes.Compare(s.Signature.Signature, other.Signature.Signature) == 0 } // GroupPublicKey is the result of DKG protocol. diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/crypto.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/crypto.go index 496944dab..42ee6122e 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/crypto.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/crypto.go @@ -325,6 +325,19 @@ func hashDKGFinalize(final *typesDKG.Finalize) common.Hash { ) } +func hashDKGSuccess(success *typesDKG.Success) common.Hash { + binaryRound := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryRound, success.Round) + binaryReset := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryReset, success.Reset) + + return crypto.Keccak256Hash( + success.ProposerID.Hash[:], + binaryRound, + binaryReset, + ) +} + // VerifyDKGFinalizeSignature verifies DKGFinalize signature. func VerifyDKGFinalizeSignature( final *typesDKG.Finalize) (bool, error) { @@ -339,6 +352,20 @@ func VerifyDKGFinalizeSignature( return true, nil } +// VerifyDKGSuccessSignature verifies DKGSuccess signature. +func VerifyDKGSuccessSignature( + success *typesDKG.Success) (bool, error) { + hash := hashDKGSuccess(success) + pubKey, err := crypto.SigToPub(hash, success.Signature) + if err != nil { + return false, err + } + if success.ProposerID != types.NewNodeID(pubKey) { + return false, nil + } + return true, nil +} + // Rehash hashes the hash again and again and again... func Rehash(hash common.Hash, count uint) common.Hash { result := hash diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/round-event.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/round-event.go index 602d2da16..b1d4d230e 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/round-event.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/round-event.go @@ -84,7 +84,7 @@ func (e RoundEventParam) NextTouchNodeSetCacheHeight() uint64 { // NextDKGResetHeight returns the height to reset DKG for next period. func (e RoundEventParam) NextDKGResetHeight() uint64 { - return e.BeginHeight + e.Config.RoundLength*8/10 + return e.BeginHeight + e.Config.RoundLength*85/100 } // NextDKGRegisterHeight returns the height to register DKG. diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/signer.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/signer.go index 9904410c4..ff767437f 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/signer.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/signer.go @@ -145,3 +145,10 @@ func (s *Signer) SignDKGFinalize(final *typesDKG.Finalize) (err error) { final.Signature, err = s.prvKey.Sign(hashDKGFinalize(final)) return } + +// SignDKGSuccess signs a DKG success message. +func (s *Signer) SignDKGSuccess(success *typesDKG.Success) (err error) { + success.ProposerID = s.proposerID + success.Signature, err = s.prvKey.Sign(hashDKGSuccess(success)) + return +} diff --git a/vendor/vendor.json b/vendor/vendor.json index eac81e0b8..3480eec30 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -141,16 +141,16 @@ { "checksumSHA1": "In6vBHYUsX7DUIGiFN2hQggBgvI=", "path": "github.com/dexon-foundation/dexon-consensus/common", - "revision": "2d26246247e2f7e616cc3d13b9d61308580e7d67", - "revisionTime": "2019-04-13T15:07:46Z", + "revision": "e9a1d3bca8353ee206d262ab1fad2d7e3e0b24a5", + "revisionTime": "2019-04-15T04:12:22Z", "version": "master", "versionExact": "master" }, { - "checksumSHA1": "6anh4sqNQZY5ZD+cZoTIB+N4PRc=", + "checksumSHA1": "1RGs5z/8Kq82E69C8aRUAZT3U24=", "path": "github.com/dexon-foundation/dexon-consensus/core", - "revision": "2d26246247e2f7e616cc3d13b9d61308580e7d67", - "revisionTime": "2019-04-13T15:07:46Z", + "revision": "e9a1d3bca8353ee206d262ab1fad2d7e3e0b24a5", + "revisionTime": "2019-04-15T04:12:22Z", "version": "master", "versionExact": "master" }, @@ -165,64 +165,64 @@ { "checksumSHA1": "tQSbYCu5P00lUhKsx3IbBZCuSLY=", "path": "github.com/dexon-foundation/dexon-consensus/core/crypto", - "revision": "2d26246247e2f7e616cc3d13b9d61308580e7d67", - "revisionTime": "2019-04-13T15:07:46Z", + "revision": "e9a1d3bca8353ee206d262ab1fad2d7e3e0b24a5", + "revisionTime": "2019-04-15T04:12:22Z", "version": "master", "versionExact": "master" }, { "checksumSHA1": "4besQaa0rm8jRUAJjpEaLZ/ZOYs=", "path": "github.com/dexon-foundation/dexon-consensus/core/crypto/dkg", - "revision": "2d26246247e2f7e616cc3d13b9d61308580e7d67", - "revisionTime": "2019-04-13T15:07:46Z", + "revision": "e9a1d3bca8353ee206d262ab1fad2d7e3e0b24a5", + "revisionTime": "2019-04-15T04:12:22Z", "version": "master", "versionExact": "master" }, { "checksumSHA1": "BhLKK8RveoLaeXc9UyUKMwQqchU=", "path": "github.com/dexon-foundation/dexon-consensus/core/crypto/ecdsa", - "revision": "2d26246247e2f7e616cc3d13b9d61308580e7d67", - "revisionTime": "2019-04-13T15:07:46Z", + "revision": "e9a1d3bca8353ee206d262ab1fad2d7e3e0b24a5", + "revisionTime": "2019-04-15T04:12:22Z", "version": "master", "versionExact": "master" }, { "checksumSHA1": "3Ludp/1V4dMBZH/c1oIVjHj0CqY=", "path": "github.com/dexon-foundation/dexon-consensus/core/db", - "revision": "2d26246247e2f7e616cc3d13b9d61308580e7d67", - "revisionTime": "2019-04-13T15:07:46Z", + "revision": "e9a1d3bca8353ee206d262ab1fad2d7e3e0b24a5", + "revisionTime": "2019-04-15T04:12:22Z", "version": "master", "versionExact": "master" }, { "checksumSHA1": "sO5twEFTdLvkMuQo+I3vyzm9T3o=", "path": "github.com/dexon-foundation/dexon-consensus/core/syncer", - "revision": "2d26246247e2f7e616cc3d13b9d61308580e7d67", - "revisionTime": "2019-04-13T15:07:46Z", + "revision": "e9a1d3bca8353ee206d262ab1fad2d7e3e0b24a5", + "revisionTime": "2019-04-15T04:12:22Z", "version": "master", "versionExact": "master" }, { "checksumSHA1": "0BY+E0E2cM7IHIMqunXwoolDS5Y=", "path": "github.com/dexon-foundation/dexon-consensus/core/types", - "revision": "2d26246247e2f7e616cc3d13b9d61308580e7d67", - "revisionTime": "2019-04-13T15:07:46Z", + "revision": "e9a1d3bca8353ee206d262ab1fad2d7e3e0b24a5", + "revisionTime": "2019-04-15T04:12:22Z", "version": "master", "versionExact": "master" }, { - "checksumSHA1": "lbG7yqVgzo2CV/CQPYjG78xp5jg=", + "checksumSHA1": "yEPSfn48GaJmDbd2OFY+QRhjJ0w=", "path": "github.com/dexon-foundation/dexon-consensus/core/types/dkg", - "revision": "2d26246247e2f7e616cc3d13b9d61308580e7d67", - "revisionTime": "2019-04-13T15:07:46Z", + "revision": "e9a1d3bca8353ee206d262ab1fad2d7e3e0b24a5", + "revisionTime": "2019-04-15T04:12:22Z", "version": "master", "versionExact": "master" }, { - "checksumSHA1": "C2r/uE8K53WIIA0FYYHIfR2xhng=", + "checksumSHA1": "7Ib134BAyLF1M/kREou4Zm7UUS4=", "path": "github.com/dexon-foundation/dexon-consensus/core/utils", - "revision": "2d26246247e2f7e616cc3d13b9d61308580e7d67", - "revisionTime": "2019-04-13T15:07:46Z", + "revision": "e9a1d3bca8353ee206d262ab1fad2d7e3e0b24a5", + "revisionTime": "2019-04-15T04:12:22Z", "version": "master", "versionExact": "master" }, -- cgit