aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWei-Ning Huang <w@dexon.org>2019-03-26 11:16:22 +0800
committerGitHub <noreply@github.com>2019-03-26 11:16:22 +0800
commit54ab3efcd95426d2f126a7b0fe99dd0a4751b944 (patch)
tree3490a2f367a6a51dff2d89fdd8a8610d20ca98a0
parent6031f16bddde8913b774c9583e750012a8d83743 (diff)
downloaddexon-54ab3efcd95426d2f126a7b0fe99dd0a4751b944.tar
dexon-54ab3efcd95426d2f126a7b0fe99dd0a4751b944.tar.gz
dexon-54ab3efcd95426d2f126a7b0fe99dd0a4751b944.tar.bz2
dexon-54ab3efcd95426d2f126a7b0fe99dd0a4751b944.tar.lz
dexon-54ab3efcd95426d2f126a7b0fe99dd0a4751b944.tar.xz
dexon-54ab3efcd95426d2f126a7b0fe99dd0a4751b944.tar.zst
dexon-54ab3efcd95426d2f126a7b0fe99dd0a4751b944.zip
core: set extended round block reward to zero (#298)
To discourage DKG set from prolonging the round indefinitely, we set the block reward of the extended round to 0. The gas fee is send to the DEXON governance owner for safe keeping and later used by the foundation.
-rw-r--r--consensus/dexcon/dexcon.go52
-rw-r--r--consensus/dexcon/dexcon_test.go2
-rw-r--r--core/chain_makers.go1
-rw-r--r--core/state_transition.go66
-rw-r--r--eth/tracers/tracers_test.go1
5 files changed, 102 insertions, 20 deletions
diff --git a/consensus/dexcon/dexcon.go b/consensus/dexcon/dexcon.go
index 3e520438b..0b6fa192f 100644
--- a/consensus/dexcon/dexcon.go
+++ b/consensus/dexcon/dexcon.go
@@ -111,8 +111,21 @@ func (d *Dexcon) Prepare(chain consensus.ChainReader, header *types.Header) erro
return nil
}
-func (d *Dexcon) calculateBlockReward(round int64, state *state.StateDB) *big.Int {
- gs := d.govStateFetcer.GetStateForConfigAtRound(uint64(round))
+func (d *Dexcon) inExtendedRound(header *types.Header, state *state.StateDB) bool {
+ gs := vm.GovernanceState{state}
+ rgs := d.govStateFetcer.GetStateForConfigAtRound(header.Round)
+
+ roundEnd := gs.RoundHeight(new(big.Int).SetUint64(header.Round)).Uint64() + rgs.RoundLength().Uint64()
+
+ // Round 0 starts and height 0 instead of height 1.
+ if header.Round == 0 {
+ roundEnd += 1
+ }
+ return header.Number.Uint64() >= roundEnd
+}
+
+func (d *Dexcon) calculateBlockReward(round uint64) *big.Int {
+ gs := d.govStateFetcer.GetStateForConfigAtRound(round)
config := gs.Configuration()
blocksPerRound := config.RoundLength
@@ -177,24 +190,27 @@ func (d *Dexcon) Finalize(chain consensus.ChainReader, header *types.Header, sta
}
// Distribute block reward and halving condition.
- if header.Coinbase == (common.Address{}) {
- header.Reward = new(big.Int)
- } else {
- reward := d.calculateBlockReward(int64(header.Round), state)
- state.AddBalance(header.Coinbase, reward)
- header.Reward = reward
- gs.IncTotalSupply(reward)
-
- // Record last proposed height.
- gs.PutLastProposedHeight(header.Coinbase, header.Number)
-
- // Check if halving checkpoint reached.
- config := gs.Configuration()
- if gs.TotalSupply().Cmp(config.NextHalvingSupply) >= 0 {
- gs.MiningHalved()
- }
+ reward := new(big.Int)
+
+ // If this is not an empty block and we are not in extended round, calculate
+ // the block reward.
+ if header.Coinbase != (common.Address{}) && !d.inExtendedRound(header, state) {
+ reward = d.calculateBlockReward(header.Round)
+ }
+
+ header.Reward = reward
+ state.AddBalance(header.Coinbase, reward)
+ gs.IncTotalSupply(reward)
+
+ // Check if halving checkpoint reached.
+ config := gs.Configuration()
+ if gs.TotalSupply().Cmp(config.NextHalvingSupply) >= 0 {
+ gs.MiningHalved()
}
+ // Record last proposed height.
+ gs.PutLastProposedHeight(header.Coinbase, header.Number)
+
header.Root = state.IntermediateRoot(true)
return types.NewBlock(header, txs, uncles, receipts), nil
}
diff --git a/consensus/dexcon/dexcon_test.go b/consensus/dexcon/dexcon_test.go
index 0181a80f3..bfded8db8 100644
--- a/consensus/dexcon/dexcon_test.go
+++ b/consensus/dexcon/dexcon_test.go
@@ -96,7 +96,7 @@ func (d *DexconTestSuite) TestBlockRewardCalculation() {
// blockReard = miningVelocity * totalStaked * roundInterval / aYear / numBlocksInCurRound
// 0.1875 * 1e18 * 3600 * 1000 / (86400 * 1000 * 365 * 3600) = 5945585996.96
- d.Require().Equal(big.NewInt(5945585996), consensus.calculateBlockReward(0, d.stateDB))
+ d.Require().Equal(big.NewInt(5945585996), consensus.calculateBlockReward(0))
}
func TestDexcon(t *testing.T) {
diff --git a/core/chain_makers.go b/core/chain_makers.go
index 2566e382c..99f23c58d 100644
--- a/core/chain_makers.go
+++ b/core/chain_makers.go
@@ -86,6 +86,7 @@ func (b *BlockGen) SetNonce(nonce types.BlockNonce) {
// added. Notably, contract code relying on the BLOCKHASH instruction
// will panic during execution.
func (b *BlockGen) AddTx(tx *types.Transaction) {
+ TestingMode = true
b.AddTxWithChain(nil, tx)
}
diff --git a/core/state_transition.go b/core/state_transition.go
index 02d58575b..f5ac9bde6 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -21,7 +21,9 @@ import (
"flag"
"math"
"math/big"
+ "sync/atomic"
+ dexCore "github.com/dexon-foundation/dexon-consensus/core"
"github.com/dexon-foundation/dexon/common"
"github.com/dexon-foundation/dexon/core/vm"
"github.com/dexon-foundation/dexon/log"
@@ -29,11 +31,19 @@ import (
)
var legacyEvm = flag.Bool("legacy-evm", false, "make evm run origin logic")
+var TestingMode = false
var (
errInsufficientBalanceForGas = errors.New("insufficient balance to pay for gas")
)
+var lastInExtendedRoundResultCache atomic.Value
+
+type lastInExtendedRoundResultType struct {
+ Height uint64
+ Result bool
+}
+
/*
The State Transitioning Model
@@ -180,6 +190,53 @@ func (st *StateTransition) preCheck() error {
return st.buyGas()
}
+func (st *StateTransition) inExtendedRound() bool {
+ // If we are running tests with chian_makers.go, there will be no valid
+ // blockchain instance for st.evm.StateAtNumber to work correctly. Simply
+ // return false in this case.
+ if TestingMode {
+ return false
+ }
+
+ if h := lastInExtendedRoundResultCache.Load(); h != nil {
+ res := h.(*lastInExtendedRoundResultType)
+ if res.Height == st.evm.BlockNumber.Uint64() {
+ return res.Result
+ }
+ }
+
+ gs := vm.GovernanceState{st.state}
+
+ round := st.evm.Round.Uint64()
+ if round < dexCore.ConfigRoundShift {
+ round = 0
+ } else {
+ round -= dexCore.ConfigRoundShift
+ }
+
+ configHeight := gs.RoundHeight(new(big.Int).SetUint64(round))
+ state, err := st.evm.StateAtNumber(configHeight.Uint64())
+ if err != nil {
+ panic(err)
+ }
+ rgs := vm.GovernanceState{state}
+
+ roundEnd := gs.RoundHeight(st.evm.Round).Uint64() + rgs.RoundLength().Uint64()
+
+ // Round 0 starts and height 0 instead of height 1.
+ if round == 0 {
+ roundEnd += 1
+ }
+
+ res := st.evm.BlockNumber.Uint64() >= roundEnd
+
+ lastInExtendedRoundResultCache.Store(&lastInExtendedRoundResultType{
+ Height: st.evm.BlockNumber.Uint64(),
+ Result: res,
+ })
+ return res
+}
+
// TransitionDb will transition the state by applying the current message and
// returning the result including the used gas. It returns an error if failed.
// An error indicates a consensus issue.
@@ -230,7 +287,14 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
} else {
st.dexonRefundGas()
}
- st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice))
+
+ receiver := st.evm.Coinbase
+ if !*legacyEvm && st.inExtendedRound() {
+ gs := vm.GovernanceState{st.state}
+ receiver = gs.Owner()
+ }
+
+ st.state.AddBalance(receiver, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice))
return ret, st.gasUsed(), vmerr != nil, err
}
diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go
index 2d6b0023b..1436cc67f 100644
--- a/eth/tracers/tracers_test.go
+++ b/eth/tracers/tracers_test.go
@@ -180,6 +180,7 @@ func TestPrestateTracerCreate2(t *testing.T) {
t.Fatalf("failed to prepare transaction for tracing: %v", err)
}
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
+ core.TestingMode = true
if _, _, _, err = st.TransitionDb(); err != nil {
t.Fatalf("failed to execute transaction: %v", err)
}