From 7c664ca090d90815db23644c209d4f5cdf0ff594 Mon Sep 17 00:00:00 2001 From: Wei-Ning Huang Date: Sun, 13 Jan 2019 16:21:17 +0800 Subject: consensus: implement DEXON cryptoeconomics v4.0 (#145) --- core/blockchain_test.go | 2 +- core/governance.go | 4 +- core/vm/governance.go | 102 ++++++++++++++++++++++++++++++++------------- core/vm/governance_abi.go | 60 ++++++++++++++++++-------- core/vm/governance_test.go | 42 +++++++++++++++---- 5 files changed, 153 insertions(+), 57 deletions(-) (limited to 'core') diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 6468e984d..a902f0032 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -1650,7 +1650,7 @@ func TestProcessPendingBlock(t *testing.T) { } engine := &dexconTest{ - blockReward: chainConfig.Dexcon.BlockReward, + blockReward: big.NewInt(1e18), numChains: chainConfig.Dexcon.NumChains, } chain, err := NewBlockChain(db, nil, chainConfig, engine, vm.Config{}, nil) diff --git a/core/governance.go b/core/governance.go index 45594fb64..538cd2b96 100644 --- a/core/governance.go +++ b/core/governance.go @@ -74,7 +74,7 @@ func (g *Governance) getHelperAtRound(round uint64) *vm.GovernanceStateHelper { return &vm.GovernanceStateHelper{StateDB: s} } -func (g *Governance) GetConfigHelper(round uint64) *vm.GovernanceStateHelper { +func (g *Governance) GetGovStateHelperAtRound(round uint64) *vm.GovernanceStateHelper { if round < dexCore.ConfigRoundShift { round = 0 } else { @@ -88,7 +88,7 @@ func (g *Governance) GetRoundHeight(round uint64) uint64 { } func (g *Governance) Configuration(round uint64) *coreTypes.Config { - configHelper := g.GetConfigHelper(round) + configHelper := g.GetGovStateHelperAtRound(round) c := configHelper.Configuration() return &coreTypes.Config{ NumChains: c.NumChains, diff --git a/core/vm/governance.go b/core/vm/governance.go index bebc26e03..e77519c58 100644 --- a/core/vm/governance.go +++ b/core/vm/governance.go @@ -242,12 +242,6 @@ func RunGovernanceContract(evm *EVM, input []byte, contract *Contract) (ret []by return nil, errExecutionReverted } return res, nil - case "blockReward": - res, err := method.Outputs.Pack(g.state.BlockReward()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil case "crs": round := new(big.Int) if err := method.Inputs.Unpack(&round, arguments); err != nil { @@ -406,6 +400,12 @@ func RunGovernanceContract(evm *EVM, input []byte, contract *Contract) (ret []by return nil, errExecutionReverted } return res, nil + case "lastHalvedAmount": + res, err := method.Outputs.Pack(g.state.LastHalvedAmount()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil case "lockupPeriod": res, err := method.Outputs.Pack(g.state.LockupPeriod()) if err != nil { @@ -418,12 +418,24 @@ func RunGovernanceContract(evm *EVM, input []byte, contract *Contract) (ret []by return nil, errExecutionReverted } return res, nil + case "miningVelocity": + res, err := method.Outputs.Pack(g.state.MiningVelocity()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil case "minStake": res, err := method.Outputs.Pack(g.state.MinStake()) if err != nil { return nil, errExecutionReverted } return res, nil + case "nextHalvingSupply": + res, err := method.Outputs.Pack(g.state.NextHalvingSupply()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil case "numChains": res, err := method.Outputs.Pack(g.state.NumChains()) if err != nil { @@ -533,7 +545,9 @@ const ( ownerLoc minStakeLoc lockupPeriodLoc - blockRewardLoc + miningVelocityLoc + nextHalvingSupplyLoc + lastHalvedAmountLoc blockGasLimitLoc numChainsLoc lambdaBALoc @@ -1160,9 +1174,37 @@ func (s *GovernanceStateHelper) LockupPeriod() *big.Int { return s.getStateBigInt(big.NewInt(lockupPeriodLoc)) } -// uint256 public blockReward; -func (s *GovernanceStateHelper) BlockReward() *big.Int { - return s.getStateBigInt(big.NewInt(blockRewardLoc)) +// uint256 public miningVelocity; +func (s *GovernanceStateHelper) MiningVelocity() *big.Int { + return s.getStateBigInt(big.NewInt(miningVelocityLoc)) +} +func (s *GovernanceStateHelper) HalfMiningVelocity() { + s.setStateBigInt(big.NewInt(miningVelocityLoc), + new(big.Int).Div(s.MiningVelocity(), big.NewInt(2))) +} + +// uint256 public nextHalvingSupply; +func (s *GovernanceStateHelper) NextHalvingSupply() *big.Int { + return s.getStateBigInt(big.NewInt(nextHalvingSupplyLoc)) +} +func (s *GovernanceStateHelper) IncNextHalvingSupply(amount *big.Int) { + s.setStateBigInt(big.NewInt(nextHalvingSupplyLoc), + new(big.Int).Add(s.NextHalvingSupply(), amount)) +} + +// uint256 public lastHalvedAmount; +func (s *GovernanceStateHelper) LastHalvedAmount() *big.Int { + return s.getStateBigInt(big.NewInt(lastHalvedAmountLoc)) +} +func (s *GovernanceStateHelper) HalfLastHalvedAmount() { + s.setStateBigInt(big.NewInt(lastHalvedAmountLoc), + new(big.Int).Div(s.LastHalvedAmount(), big.NewInt(2))) +} + +func (s *GovernanceStateHelper) MiningHalved() { + s.HalfMiningVelocity() + s.HalfLastHalvedAmount() + s.IncNextHalvingSupply(s.LastHalvedAmount()) } // uint256 public blockGasLimit; @@ -1290,25 +1332,27 @@ func (s *GovernanceStateHelper) Stake( s.IncTotalStaked(staked) } -const phiRatioMultiplier = 1000000.0 +const decimalMultiplier = 100000000.0 // Configuration returns the current configuration. func (s *GovernanceStateHelper) Configuration() *params.DexconConfig { return ¶ms.DexconConfig{ - MinStake: s.getStateBigInt(big.NewInt(minStakeLoc)), - LockupPeriod: s.getStateBigInt(big.NewInt(lockupPeriodLoc)).Uint64(), - BlockReward: s.getStateBigInt(big.NewInt(blockRewardLoc)), - BlockGasLimit: s.getStateBigInt(big.NewInt(blockGasLimitLoc)).Uint64(), - NumChains: uint32(s.getStateBigInt(big.NewInt(numChainsLoc)).Uint64()), - LambdaBA: s.getStateBigInt(big.NewInt(lambdaBALoc)).Uint64(), - LambdaDKG: s.getStateBigInt(big.NewInt(lambdaDKGLoc)).Uint64(), - K: uint32(s.getStateBigInt(big.NewInt(kLoc)).Uint64()), - PhiRatio: float32(s.getStateBigInt(big.NewInt(phiRatioLoc)).Uint64()) / phiRatioMultiplier, - NotarySetSize: uint32(s.getStateBigInt(big.NewInt(notarySetSizeLoc)).Uint64()), - DKGSetSize: uint32(s.getStateBigInt(big.NewInt(dkgSetSizeLoc)).Uint64()), - RoundInterval: s.getStateBigInt(big.NewInt(roundIntervalLoc)).Uint64(), - MinBlockInterval: s.getStateBigInt(big.NewInt(minBlockIntervalLoc)).Uint64(), - FineValues: s.FineValues(), + MinStake: s.getStateBigInt(big.NewInt(minStakeLoc)), + LockupPeriod: s.getStateBigInt(big.NewInt(lockupPeriodLoc)).Uint64(), + MiningVelocity: float32(s.getStateBigInt(big.NewInt(miningVelocityLoc)).Uint64()) / decimalMultiplier, + NextHalvingSupply: s.getStateBigInt(big.NewInt(nextHalvingSupplyLoc)), + LastHalvedAmount: s.getStateBigInt(big.NewInt(lastHalvedAmountLoc)), + BlockGasLimit: s.getStateBigInt(big.NewInt(blockGasLimitLoc)).Uint64(), + NumChains: uint32(s.getStateBigInt(big.NewInt(numChainsLoc)).Uint64()), + LambdaBA: s.getStateBigInt(big.NewInt(lambdaBALoc)).Uint64(), + LambdaDKG: s.getStateBigInt(big.NewInt(lambdaDKGLoc)).Uint64(), + K: uint32(s.getStateBigInt(big.NewInt(kLoc)).Uint64()), + PhiRatio: float32(s.getStateBigInt(big.NewInt(phiRatioLoc)).Uint64()) / decimalMultiplier, + NotarySetSize: uint32(s.getStateBigInt(big.NewInt(notarySetSizeLoc)).Uint64()), + DKGSetSize: uint32(s.getStateBigInt(big.NewInt(dkgSetSizeLoc)).Uint64()), + RoundInterval: s.getStateBigInt(big.NewInt(roundIntervalLoc)).Uint64(), + MinBlockInterval: s.getStateBigInt(big.NewInt(minBlockIntervalLoc)).Uint64(), + FineValues: s.FineValues(), } } @@ -1316,13 +1360,15 @@ func (s *GovernanceStateHelper) Configuration() *params.DexconConfig { func (s *GovernanceStateHelper) UpdateConfiguration(cfg *params.DexconConfig) { s.setStateBigInt(big.NewInt(minStakeLoc), cfg.MinStake) s.setStateBigInt(big.NewInt(lockupPeriodLoc), big.NewInt(int64(cfg.LockupPeriod))) - s.setStateBigInt(big.NewInt(blockRewardLoc), cfg.BlockReward) + s.setStateBigInt(big.NewInt(miningVelocityLoc), big.NewInt(int64(cfg.MiningVelocity*decimalMultiplier))) + s.setStateBigInt(big.NewInt(nextHalvingSupplyLoc), cfg.NextHalvingSupply) + s.setStateBigInt(big.NewInt(lastHalvedAmountLoc), cfg.LastHalvedAmount) s.setStateBigInt(big.NewInt(blockGasLimitLoc), big.NewInt(int64(cfg.BlockGasLimit))) s.setStateBigInt(big.NewInt(numChainsLoc), big.NewInt(int64(cfg.NumChains))) s.setStateBigInt(big.NewInt(lambdaBALoc), big.NewInt(int64(cfg.LambdaBA))) s.setStateBigInt(big.NewInt(lambdaDKGLoc), big.NewInt(int64(cfg.LambdaDKG))) s.setStateBigInt(big.NewInt(kLoc), big.NewInt(int64(cfg.K))) - s.setStateBigInt(big.NewInt(phiRatioLoc), big.NewInt(int64(cfg.PhiRatio*phiRatioMultiplier))) + s.setStateBigInt(big.NewInt(phiRatioLoc), big.NewInt(int64(cfg.PhiRatio*decimalMultiplier))) s.setStateBigInt(big.NewInt(notarySetSizeLoc), big.NewInt(int64(cfg.NotarySetSize))) s.setStateBigInt(big.NewInt(dkgSetSizeLoc), big.NewInt(int64(cfg.DKGSetSize))) s.setStateBigInt(big.NewInt(roundIntervalLoc), big.NewInt(int64(cfg.RoundInterval))) @@ -1333,7 +1379,6 @@ func (s *GovernanceStateHelper) UpdateConfiguration(cfg *params.DexconConfig) { type rawConfigStruct struct { MinStake *big.Int LockupPeriod *big.Int - BlockReward *big.Int BlockGasLimit *big.Int NumChains *big.Int LambdaBA *big.Int @@ -1351,7 +1396,6 @@ type rawConfigStruct struct { func (s *GovernanceStateHelper) UpdateConfigurationRaw(cfg *rawConfigStruct) { s.setStateBigInt(big.NewInt(minStakeLoc), cfg.MinStake) s.setStateBigInt(big.NewInt(lockupPeriodLoc), cfg.LockupPeriod) - s.setStateBigInt(big.NewInt(blockRewardLoc), cfg.BlockReward) s.setStateBigInt(big.NewInt(blockGasLimitLoc), cfg.BlockGasLimit) s.setStateBigInt(big.NewInt(numChainsLoc), cfg.NumChains) s.setStateBigInt(big.NewInt(lambdaBALoc), cfg.LambdaBA) diff --git a/core/vm/governance_abi.go b/core/vm/governance_abi.go index 1b700ac32..f139ac7a8 100644 --- a/core/vm/governance_abi.go +++ b/core/vm/governance_abi.go @@ -45,20 +45,6 @@ const GovernanceABIJSON = ` "stateMutability": "view", "type": "function" }, - { - "constant": true, - "inputs": [], - "name": "blockReward", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, { "constant": true, "inputs": [ @@ -171,6 +157,20 @@ const GovernanceABIJSON = ` "stateMutability": "view", "type": "function" }, + { + "constant": true, + "inputs": [], + "name": "miningVelocity", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { "constant": true, "inputs": [], @@ -385,6 +385,20 @@ const GovernanceABIJSON = ` "stateMutability": "view", "type": "function" }, + { + "constant": true, + "inputs": [], + "name": "nextHalvingSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { "constant": true, "inputs": [], @@ -399,6 +413,20 @@ const GovernanceABIJSON = ` "stateMutability": "view", "type": "function" }, + { + "constant": true, + "inputs": [], + "name": "lastHalvedAmount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { "constant": true, "inputs": [ @@ -780,10 +808,6 @@ const GovernanceABIJSON = ` "name": "LockupPeriod", "type": "uint256" }, - { - "name": "BlockReward", - "type": "uint256" - }, { "name": "BlockGasLimit", "type": "uint256" diff --git a/core/vm/governance_test.go b/core/vm/governance_test.go index 8566d6537..55d4ebb8b 100644 --- a/core/vm/governance_test.go +++ b/core/vm/governance_test.go @@ -112,6 +112,9 @@ func (g *GovernanceContractTestSuite) SetupTest() { config := params.TestnetChainConfig.Dexcon config.LockupPeriod = 1000 + config.NextHalvingSupply = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2.5e9)) + config.LastHalvedAmount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1.5e9)) + config.MiningVelocity = 0.1875 g.config = config @@ -598,9 +601,18 @@ func (g *GovernanceContractTestSuite) TestUpdateConfiguration() { _, addr := g.newPrefundAccount() input, err := abiObject.Pack("updateConfiguration", - new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e5)), big.NewInt(1000), - big.NewInt(1e18), big.NewInt(8000000), big.NewInt(6), big.NewInt(250), big.NewInt(2500), - big.NewInt(0), big.NewInt(667000), big.NewInt(4), big.NewInt(4), big.NewInt(600000), big.NewInt(900), + new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e5)), + big.NewInt(1000), + big.NewInt(8000000), + big.NewInt(6), + big.NewInt(250), + big.NewInt(2500), + big.NewInt(0), + big.NewInt(667000), + big.NewInt(4), + big.NewInt(4), + big.NewInt(600000), + big.NewInt(900), []*big.Int{big.NewInt(1), big.NewInt(1), big.NewInt(1)}) g.Require().NoError(err) @@ -687,13 +699,13 @@ func (g *GovernanceContractTestSuite) TestConfigurationReading() { g.Require().Equal(g.config.MinStake.String(), value.String()) // BlockReward. - input, err = abiObject.Pack("blockReward") + input, err = abiObject.Pack("miningVelocity") g.Require().NoError(err) res, err = g.call(addr, input, big.NewInt(0)) g.Require().NoError(err) - err = abiObject.Unpack(&value, "blockReward", res) + err = abiObject.Unpack(&value, "miningVelocity", res) g.Require().NoError(err) - g.Require().Equal(g.config.BlockReward.String(), value.String()) + g.Require().Equal(g.config.MiningVelocity, float32(value.Uint64())/decimalMultiplier) // BlockGasLimit. input, err = abiObject.Pack("blockGasLimit") @@ -747,7 +759,7 @@ func (g *GovernanceContractTestSuite) TestConfigurationReading() { g.Require().NoError(err) err = abiObject.Unpack(&value, "phiRatio", res) g.Require().NoError(err) - g.Require().Equal(g.config.PhiRatio, float32(value.Uint64())/phiRatioMultiplier) + g.Require().Equal(g.config.PhiRatio, float32(value.Uint64())/decimalMultiplier) // NotarySetSize. input, err = abiObject.Pack("notarySetSize") @@ -1024,6 +1036,22 @@ func (g *GovernanceContractTestSuite) TestMiscVariableReading() { g.Require().NoError(err) } +func (g *GovernanceContractTestSuite) TestHalvingCondition() { + // TotalSupply 2.5B reached + g.s.MiningHalved() + g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3.25e9)).String(), + g.s.NextHalvingSupply().String()) + g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(0.75e9)).String(), + g.s.LastHalvedAmount().String()) + + // TotalSupply 3.25B reached + g.s.MiningHalved() + g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3.625e9)).String(), + g.s.NextHalvingSupply().String()) + g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(0.375e9)).String(), + g.s.LastHalvedAmount().String()) +} + func TestGovernanceContract(t *testing.T) { suite.Run(t, new(GovernanceContractTestSuite)) } -- cgit v1.2.3