diff options
author | Jimmy Hu <jimmy.hu@dexon.org> | 2019-04-15 18:19:46 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-15 18:19:46 +0800 |
commit | 4a8d6480f7ab074bc032d68df6ee8df5876ef3cc (patch) | |
tree | 54fdb27d6254ecc56f27b7819e9e554c2b1e9f63 /core | |
parent | d77c1aa22cb6f2b76af3edf4995159b843838441 (diff) | |
download | dexon-4a8d6480f7ab074bc032d68df6ee8df5876ef3cc.tar dexon-4a8d6480f7ab074bc032d68df6ee8df5876ef3cc.tar.gz dexon-4a8d6480f7ab074bc032d68df6ee8df5876ef3cc.tar.bz2 dexon-4a8d6480f7ab074bc032d68df6ee8df5876ef3cc.tar.lz dexon-4a8d6480f7ab074bc032d68df6ee8df5876ef3cc.tar.xz dexon-4a8d6480f7ab074bc032d68df6ee8df5876ef3cc.tar.zst dexon-4a8d6480f7ab074bc032d68df6ee8df5876ef3cc.zip |
core: implement DKG success (#362)
* vendor: sync to latest core
* core: implmenet dkg success
* cmd: govtool: add DKGSuccess
Diffstat (limited to 'core')
-rw-r--r-- | core/governance.go | 9 | ||||
-rw-r--r-- | core/vm/oracle_contract_abi.go | 47 | ||||
-rw-r--r-- | core/vm/oracle_contracts.go | 175 | ||||
-rw-r--r-- | core/vm/oracle_contracts_test.go | 16 |
4 files changed, 215 insertions, 32 deletions
diff --git a/core/governance.go b/core/governance.go index 39b2704e6..277b3bb89 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 @@ -24,6 +24,25 @@ const GovernanceABIJSON = ` [ { "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "dkgSuccesses", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, "inputs": [], "name": "notarySetSize", "outputs": [ @@ -191,6 +210,20 @@ const GovernanceABIJSON = ` }, { "constant": true, + "inputs": [], + "name": "dkgSuccessesCount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, "inputs": [ { "name": "", @@ -1030,6 +1063,20 @@ const GovernanceABIJSON = ` "constant": false, "inputs": [ { + "name": "Success", + "type": "bytes" + } + ], + "name": "addDKGSuccess", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "name": "PublicKey", "type": "bytes" }, diff --git a/core/vm/oracle_contracts.go b/core/vm/oracle_contracts.go index 4878fd325..b36a05d15 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))) @@ -1357,6 +1390,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) { @@ -1628,6 +1663,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() { @@ -1974,9 +2043,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) @@ -1991,37 +2060,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 + } } } @@ -2046,7 +2120,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 } @@ -2058,19 +2134,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) @@ -2124,6 +2198,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 { @@ -2266,6 +2346,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 { @@ -2632,6 +2730,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 269421717..4fb05a34e 100644 --- a/core/vm/oracle_contracts_test.go +++ b/core/vm/oracle_contracts_test.go @@ -985,6 +985,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))) } @@ -1034,6 +1036,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 } @@ -1050,6 +1055,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)) + } } } @@ -1089,7 +1098,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) @@ -1115,6 +1124,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()) |