aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorJimmy Hu <jimmy.hu@dexon.org>2019-02-25 18:27:34 +0800
committerWei-Ning Huang <w@dexon.org>2019-04-09 21:32:57 +0800
commit5832a21db625bfa98a3b7909bb6996dd1fd2e4d3 (patch)
tree73f5de74fa6aa753349f00e11e989533de8a45ef /core
parent6e66efc9f69d59a011215f88a0de03508d9c56ab (diff)
downloaddexon-5832a21db625bfa98a3b7909bb6996dd1fd2e4d3.tar.gz
dexon-5832a21db625bfa98a3b7909bb6996dd1fd2e4d3.tar.zst
dexon-5832a21db625bfa98a3b7909bb6996dd1fd2e4d3.zip
core: Fixed gas price (#205)
* core/vm: update abi * core/vm: add MinGasPrice to gov * params: Add MinGasPrice to Config * dex: SuggestPrice from Governance * test: add minGasPrice to genesis.json * core: check underpriced tx * dex: verify with gas price
Diffstat (limited to 'core')
-rw-r--r--core/governance.go4
-rw-r--r--core/tx_pool.go44
-rw-r--r--core/tx_pool_test.go4
-rw-r--r--core/vm/oracle_contract_abi.go18
-rw-r--r--core/vm/oracle_contracts.go16
-rw-r--r--core/vm/oracle_contracts_test.go12
6 files changed, 96 insertions, 2 deletions
diff --git a/core/governance.go b/core/governance.go
index 12124760e..9929867c9 100644
--- a/core/governance.go
+++ b/core/governance.go
@@ -134,3 +134,7 @@ func (g *Governance) IsDKGFinal(round uint64) bool {
count := headHelper.DKGFinalizedsCount(big.NewInt(int64(round))).Uint64()
return count >= threshold
}
+
+func (g *Governance) MinGasPrice(round uint64) *big.Int {
+ return g.GetGovStateHelperAtRound(round).MinGasPrice()
+}
diff --git a/core/tx_pool.go b/core/tx_pool.go
index 871b50be1..0a1b3f132 100644
--- a/core/tx_pool.go
+++ b/core/tx_pool.go
@@ -24,10 +24,13 @@ import (
"sync"
"time"
+ dexCore "github.com/dexon-foundation/dexon-consensus/core"
+
"github.com/dexon-foundation/dexon/common"
"github.com/dexon-foundation/dexon/common/prque"
"github.com/dexon-foundation/dexon/core/state"
"github.com/dexon-foundation/dexon/core/types"
+ "github.com/dexon-foundation/dexon/core/vm"
"github.com/dexon-foundation/dexon/event"
"github.com/dexon-foundation/dexon/log"
"github.com/dexon-foundation/dexon/metrics"
@@ -115,6 +118,7 @@ const (
type blockChain interface {
CurrentBlock() *types.Block
GetBlock(hash common.Hash, number uint64) *types.Block
+ GetBlockByNumber(number uint64) *types.Block
StateAt(root common.Hash) (*state.StateDB, error)
SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription
@@ -206,6 +210,7 @@ type TxPool struct {
chainconfig *params.ChainConfig
chain blockChain
gasPrice *big.Int
+ govGasPrice *big.Int
txFeed event.Feed
scope event.SubscriptionScope
chainHeadCh chan ChainHeadEvent
@@ -385,6 +390,28 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
pool.currentState = statedb
pool.pendingState = state.ManageState(statedb)
pool.currentMaxGas = newHead.GasLimit
+ if oldHead == nil || oldHead.Round != newHead.Round {
+ round := newHead.Round
+ if round < dexCore.ConfigRoundShift {
+ round = 0
+ } else {
+ round -= dexCore.ConfigRoundShift
+ }
+ state := &vm.GovernanceStateHelper{StateDB: statedb}
+ height := state.RoundHeight(new(big.Int).SetUint64((round))).Uint64()
+ block := pool.chain.GetBlockByNumber(height)
+ if block == nil {
+ log.Error("Failed to get block", "round", round, "height", height)
+ panic("cannot get config for new round's min gas price")
+ }
+ configState, err := pool.chain.StateAt(block.Header().Root)
+ if err != nil {
+ log.Error("Failed to get txpool state for min gas price", "err", err)
+ panic("cannot get state for new round's min gas price")
+ }
+ govState := &vm.GovernanceStateHelper{StateDB: configState}
+ pool.setGovPrice(govState.MinGasPrice())
+ }
// validate the pool of pending transactions, this will remove
// any transactions that have been included in the block or
@@ -438,10 +465,21 @@ func (pool *TxPool) SetGasPrice(price *big.Int) {
defer pool.mu.Unlock()
pool.gasPrice = price
+ pool.removeUnderpricedTx(price)
+ log.Info("Transaction pool price threshold updated", "price", price)
+}
+
+// setGovPrice updates the minimum price required by the transaction pool for a
+// new transaction, and drops all transactions below this threshold.
+func (pool *TxPool) setGovPrice(price *big.Int) {
+ pool.govGasPrice = price
+ pool.removeUnderpricedTx(price)
+}
+
+func (pool *TxPool) removeUnderpricedTx(price *big.Int) {
for _, tx := range pool.priced.Cap(price, pool.locals) {
pool.removeTx(tx.Hash(), false)
}
- log.Info("Transaction pool price threshold updated", "price", price)
}
// State returns the virtual managed state of the transaction pool.
@@ -551,6 +589,10 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
if err != nil {
return ErrInvalidSender
}
+ // Drop all transactions under governance minimum gas price.
+ if pool.govGasPrice.Cmp(tx.GasPrice()) > 0 {
+ return ErrUnderpriced
+ }
// Drop non-local transactions under our own minimal accepted gas price
local = local || pool.locals.contains(from) // account may be local even if the transaction arrived from the network
if !local && pool.gasPrice.Cmp(tx.GasPrice()) > 0 {
diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go
index 96151850d..70d4a351a 100644
--- a/core/tx_pool_test.go
+++ b/core/tx_pool_test.go
@@ -61,6 +61,10 @@ func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block
return bc.CurrentBlock()
}
+func (bc *testBlockChain) GetBlockByNumber(uint64) *types.Block {
+ return bc.CurrentBlock()
+}
+
func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) {
return bc.statedb, nil
}
diff --git a/core/vm/oracle_contract_abi.go b/core/vm/oracle_contract_abi.go
index fde973203..ff4a94b29 100644
--- a/core/vm/oracle_contract_abi.go
+++ b/core/vm/oracle_contract_abi.go
@@ -566,6 +566,20 @@ const GovernanceABIJSON = `
{
"constant": true,
"inputs": [],
+ "name": "minGasPrice",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
"name": "lockupPeriod",
"outputs": [
{
@@ -855,6 +869,10 @@ const GovernanceABIJSON = `
{
"name": "FineValues",
"type": "uint256[]"
+ },
+ {
+ "name": "MinGasPrice",
+ "type": "uint256"
}
],
"name": "updateConfiguration",
diff --git a/core/vm/oracle_contracts.go b/core/vm/oracle_contracts.go
index 1eeb57a5a..826e0396c 100644
--- a/core/vm/oracle_contracts.go
+++ b/core/vm/oracle_contracts.go
@@ -83,6 +83,7 @@ const (
fineValuesLoc
finedRecordsLoc
dkgResetCountLoc
+ minGasPriceLoc
)
func publicKeyToNodeID(pkBytes []byte) (Bytes32, error) {
@@ -894,6 +895,11 @@ func (s *GovernanceStateHelper) IncDKGResetCount(round *big.Int) {
s.setStateBigInt(loc, new(big.Int).Add(count, big.NewInt(1)))
}
+// uint256 public minGasPrice;
+func (s *GovernanceStateHelper) MinGasPrice() *big.Int {
+ return s.getStateBigInt(big.NewInt(minGasPriceLoc))
+}
+
// Stake is a helper function for creating genesis state.
func (s *GovernanceStateHelper) Stake(
addr common.Address, publicKey []byte, staked *big.Int,
@@ -948,6 +954,7 @@ func (s *GovernanceStateHelper) Configuration() *params.DexconConfig {
RoundLength: s.getStateBigInt(big.NewInt(roundLengthLoc)).Uint64(),
MinBlockInterval: s.getStateBigInt(big.NewInt(minBlockIntervalLoc)).Uint64(),
FineValues: s.FineValues(),
+ MinGasPrice: s.getStateBigInt(big.NewInt(minGasPriceLoc)),
}
}
@@ -966,6 +973,7 @@ func (s *GovernanceStateHelper) UpdateConfiguration(cfg *params.DexconConfig) {
s.setStateBigInt(big.NewInt(roundLengthLoc), big.NewInt(int64(cfg.RoundLength)))
s.setStateBigInt(big.NewInt(minBlockIntervalLoc), big.NewInt(int64(cfg.MinBlockInterval)))
s.SetFineValues(cfg.FineValues)
+ s.setStateBigInt(big.NewInt(minGasPriceLoc), cfg.MinGasPrice)
}
type rawConfigStruct struct {
@@ -979,6 +987,7 @@ type rawConfigStruct struct {
RoundLength *big.Int
MinBlockInterval *big.Int
FineValues []*big.Int
+ MinGasPrice *big.Int
}
// UpdateConfigurationRaw updates system configuration.
@@ -993,6 +1002,7 @@ func (s *GovernanceStateHelper) UpdateConfigurationRaw(cfg *rawConfigStruct) {
s.setStateBigInt(big.NewInt(roundLengthLoc), cfg.RoundLength)
s.setStateBigInt(big.NewInt(minBlockIntervalLoc), cfg.MinBlockInterval)
s.SetFineValues(cfg.FineValues)
+ s.setStateBigInt(big.NewInt(minGasPriceLoc), cfg.MinGasPrice)
}
// event ConfigurationChanged();
@@ -2227,6 +2237,12 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re
return nil, errExecutionReverted
}
return res, nil
+ case "minGasPrice":
+ res, err := method.Outputs.Pack(g.state.MinGasPrice())
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
case "miningVelocity":
res, err := method.Outputs.Pack(g.state.MiningVelocity())
if err != nil {
diff --git a/core/vm/oracle_contracts_test.go b/core/vm/oracle_contracts_test.go
index dd17dddea..4980d4b77 100644
--- a/core/vm/oracle_contracts_test.go
+++ b/core/vm/oracle_contracts_test.go
@@ -654,7 +654,8 @@ func (g *OracleContractsTestSuite) TestUpdateConfiguration() {
big.NewInt(4),
big.NewInt(600),
big.NewInt(900),
- []*big.Int{big.NewInt(1), big.NewInt(1), big.NewInt(1)})
+ []*big.Int{big.NewInt(1), big.NewInt(1), big.NewInt(1)},
+ big.NewInt(2e9))
g.Require().NoError(err)
// Call with non-owner.
@@ -770,6 +771,15 @@ func (g *OracleContractsTestSuite) TestConfigurationReading() {
err = GovernanceABI.ABI.Unpack(&value, "minBlockInterval", res)
g.Require().NoError(err)
g.Require().Equal(g.config.MinBlockInterval, value.Uint64())
+
+ // MinGasPrice.
+ input, err = GovernanceABI.ABI.Pack("minGasPrice")
+ g.Require().NoError(err)
+ res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
+ g.Require().NoError(err)
+ err = GovernanceABI.ABI.Unpack(&value, "minGasPrice", res)
+ g.Require().NoError(err)
+ g.Require().Equal(g.config.MinGasPrice, value)
}
func (g *OracleContractsTestSuite) TestReportForkVote() {