aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWei-Ning Huang <w@byzantine-lab.io>2019-07-25 20:41:46 +0800
committerWei-Ning Huang <w@byzantine-lab.io>2019-09-17 16:57:31 +0800
commit174f6bfcdf4e2c7fea3a071653908b477ad9a3b3 (patch)
tree7990bd656bd9cc7ef3014534ad2fee5163da3790
parenta9a85fa746c727063015d6e70881426ce8b3a3fb (diff)
downloadgo-tangerine-174f6bfcdf4e2c7fea3a071653908b477ad9a3b3.tar
go-tangerine-174f6bfcdf4e2c7fea3a071653908b477ad9a3b3.tar.gz
go-tangerine-174f6bfcdf4e2c7fea3a071653908b477ad9a3b3.tar.bz2
go-tangerine-174f6bfcdf4e2c7fea3a071653908b477ad9a3b3.tar.lz
go-tangerine-174f6bfcdf4e2c7fea3a071653908b477ad9a3b3.tar.xz
go-tangerine-174f6bfcdf4e2c7fea3a071653908b477ad9a3b3.tar.zst
go-tangerine-174f6bfcdf4e2c7fea3a071653908b477ad9a3b3.zip
core: add GovUtil to unify governance state related access
Add GovUtil so we could use the same logic in everywhere that requires access to governance state, such as configuration and CRS.
-rw-r--r--consensus/dexcon/dexcon.go19
-rw-r--r--consensus/dexcon/dexcon_test.go4
-rw-r--r--core/governance.go138
-rw-r--r--core/headerchain.go5
-rw-r--r--core/state_transition.go27
-rw-r--r--core/tx_pool.go36
-rw-r--r--core/vm/oracle.go2
-rw-r--r--core/vm/oracle_contracts.go102
-rw-r--r--core/vm/oracle_contracts_test.go4
-rw-r--r--core/vm/utils.go92
-rw-r--r--dex/api_backend.go6
-rw-r--r--dex/app.go41
-rw-r--r--dex/app_test.go13
-rw-r--r--dex/downloader/testchain_test.go8
-rw-r--r--dex/governance.go10
15 files changed, 302 insertions, 205 deletions
diff --git a/consensus/dexcon/dexcon.go b/consensus/dexcon/dexcon.go
index e47a8a8e2..8ececb469 100644
--- a/consensus/dexcon/dexcon.go
+++ b/consensus/dexcon/dexcon.go
@@ -32,7 +32,7 @@ import (
)
type GovernanceStateFetcher interface {
- GetStateForConfigAtRound(round uint64) *vm.GovernanceState
+ GetConfigState(round uint64) (*vm.GovernanceState, error)
DKGSetNodeKeyAddresses(round uint64) (map[common.Address]struct{}, error)
}
@@ -114,7 +114,10 @@ func (d *Dexcon) Prepare(chain consensus.ChainReader, header *types.Header) erro
func (d *Dexcon) inExtendedRound(header *types.Header, state *state.StateDB) bool {
gs := vm.GovernanceState{state}
- rgs := d.govStateFetcer.GetStateForConfigAtRound(header.Round)
+ rgs, err := d.govStateFetcer.GetConfigState(header.Round)
+ if err != nil {
+ panic(err)
+ }
roundEnd := gs.RoundHeight(new(big.Int).SetUint64(header.Round)).Uint64() + rgs.RoundLength().Uint64()
@@ -126,7 +129,10 @@ func (d *Dexcon) inExtendedRound(header *types.Header, state *state.StateDB) boo
}
func (d *Dexcon) calculateBlockReward(round uint64) *big.Int {
- gs := d.govStateFetcer.GetStateForConfigAtRound(round)
+ gs, err := d.govStateFetcer.GetConfigState(round)
+ if err != nil {
+ panic(err)
+ }
config := gs.Configuration()
blocksPerRound := config.RoundLength
@@ -169,7 +175,10 @@ func (d *Dexcon) Finalize(chain consensus.ChainReader, header *types.Header, sta
panic(err)
}
- gcs := d.govStateFetcer.GetStateForConfigAtRound(header.Round - 1)
+ gcs, err := d.govStateFetcer.GetConfigState(header.Round - 1)
+ if err != nil {
+ panic(err)
+ }
for addr := range addrs {
offset := gcs.NodesOffsetByNodeKeyAddress(addr)
@@ -182,7 +191,7 @@ func (d *Dexcon) Finalize(chain consensus.ChainReader, header *types.Header, sta
prevRoundHeight := gs.RoundHeight(big.NewInt(int64(header.Round - 1)))
if lastHeight.Uint64() < prevRoundHeight.Uint64() {
- log.Info("Disqualify node", "round", header.Round, "nodePubKey", hex.EncodeToString(node.PublicKey))
+ log.Debug("Disqualify node", "round", header.Round, "nodePubKey", hex.EncodeToString(node.PublicKey))
err = gs.Disqualify(node)
if err != nil {
log.Error("Failed to disqualify node", "err", err)
diff --git a/consensus/dexcon/dexcon_test.go b/consensus/dexcon/dexcon_test.go
index 09b7281ef..3478b911b 100644
--- a/consensus/dexcon/dexcon_test.go
+++ b/consensus/dexcon/dexcon_test.go
@@ -35,8 +35,8 @@ type govStateFetcher struct {
statedb *state.StateDB
}
-func (g *govStateFetcher) GetStateForConfigAtRound(_ uint64) *vm.GovernanceState {
- return &vm.GovernanceState{g.statedb}
+func (g *govStateFetcher) GetConfigState(_ uint64) (*vm.GovernanceState, error) {
+ return &vm.GovernanceState{g.statedb}, nil
}
func (g *govStateFetcher) DKGSetNodeKeyAddresses(round uint64) (map[common.Address]struct{}, error) {
diff --git a/core/governance.go b/core/governance.go
index 792c94621..8bad0ca98 100644
--- a/core/governance.go
+++ b/core/governance.go
@@ -19,7 +19,6 @@ import (
"github.com/tangerine-network/go-tangerine/common"
"github.com/tangerine-network/go-tangerine/core/state"
"github.com/tangerine-network/go-tangerine/core/vm"
- "github.com/tangerine-network/go-tangerine/crypto"
"github.com/tangerine-network/go-tangerine/log"
)
@@ -64,6 +63,7 @@ type Governance struct {
nodeSetCache *dexCore.NodeSetCache
dkgCache *simplelru.LRU
dkgCacheMu sync.RWMutex
+ util vm.GovUtil
}
func NewGovernance(db GovernanceStateDB) *Governance {
@@ -77,113 +77,84 @@ func NewGovernance(db GovernanceStateDB) *Governance {
dkgCache: cache,
}
g.nodeSetCache = dexCore.NewNodeSetCache(g)
+ g.util = vm.GovUtil{g}
return g
}
-func (g *Governance) GetHeadState() *vm.GovernanceState {
+func (g *Governance) GetHeadGovState() (*vm.GovernanceState, error) {
headState, err := g.db.State()
if err != nil {
log.Error("Governance head state not ready", "err", err)
- panic(err)
+ return nil, err
}
- return &vm.GovernanceState{StateDB: headState}
+ return &vm.GovernanceState{StateDB: headState}, nil
}
-func (g *Governance) getHelperAtRound(round uint64) *vm.GovernanceState {
- height := g.GetRoundHeight(round)
-
- // Sanity check
- if round != 0 && height == 0 {
- log.Error("Governance state incorrect", "round", round, "got height", height)
- panic("round != 0 but height == 0")
- }
-
- s, err := g.db.StateAt(height)
- if err != nil {
- log.Error("Governance state not ready", "round", round, "height", height, "err", err)
- panic(err)
- }
- return &vm.GovernanceState{StateDB: s}
+func (g *Governance) StateAt(height uint64) (*state.StateDB, error) {
+ return g.db.StateAt(height)
}
-func (g *Governance) GetStateForConfigAtRound(round uint64) *vm.GovernanceState {
- if round < dexCore.ConfigRoundShift {
- round = 0
- } else {
- round -= dexCore.ConfigRoundShift
- }
- return g.getHelperAtRound(round)
+func (g *Governance) GetConfigState(round uint64) (*vm.GovernanceState, error) {
+ return g.util.GetConfigState(round)
}
-func (g *Governance) GetStateAtRound(round uint64) *vm.GovernanceState {
- height := g.GetRoundHeight(round)
- s, err := g.db.StateAt(height)
+func (g *Governance) GetStateForDKGAtRound(round uint64) (*vm.GovernanceState, error) {
+ gs, err := g.GetHeadGovState()
if err != nil {
- log.Error("Governance state not ready", "round", round, "height", height, "err", err)
- panic(err)
+ return nil, err
}
- return &vm.GovernanceState{StateDB: s}
-}
-
-func (g *Governance) GetStateForDKGAtRound(round uint64) *vm.GovernanceState {
- dkgRound := g.GetHeadState().DKGRound().Uint64()
+ dkgRound := gs.DKGRound().Uint64()
if round > dkgRound {
- return nil
+ return nil, fmt.Errorf("invalid round input: %d, dkgRound: %d", round, dkgRound)
}
if round == dkgRound {
- return g.GetHeadState()
+ return gs, nil
}
- return g.GetStateAtRound(round)
+ return g.util.GetStateAtRound(round)
}
func (g *Governance) CRSRound() uint64 {
- return g.GetHeadState().CRSRound().Uint64()
+ gs, err := g.GetHeadGovState()
+ if err != nil {
+ log.Error("Failed to get head governance state", "err", err)
+ return 0
+ }
+ return gs.CRSRound().Uint64()
}
// CRS returns the CRS for a given round.
func (g *Governance) CRS(round uint64) coreCommon.Hash {
- if round <= dexCore.DKGDelayRound {
- s := g.GetStateAtRound(0)
- crs := s.CRS()
- for i := uint64(0); i < round; i++ {
- crs = crypto.Keccak256Hash(crs[:])
- }
- return coreCommon.Hash(crs)
- }
- if round > g.CRSRound() {
- return coreCommon.Hash{}
- }
- var s *vm.GovernanceState
- if round == g.CRSRound() {
- s = g.GetHeadState()
- } else {
- s = g.GetStateAtRound(round)
- }
- return coreCommon.Hash(s.CRS())
+ return coreCommon.Hash(g.util.CRS(round))
+}
+
+func (g *Governance) GetRoundHeight(round uint64) uint64 {
+ return g.util.GetRoundHeight(round)
}
func (g *Governance) Configuration(round uint64) *coreTypes.Config {
- configHelper := g.GetStateForConfigAtRound(round)
- c := configHelper.Configuration()
+ s, err := g.util.GetConfigState(round)
+ if err != nil {
+ panic(err)
+ }
+ c := s.Configuration()
return &coreTypes.Config{
LambdaBA: time.Duration(c.LambdaBA) * time.Millisecond,
LambdaDKG: time.Duration(c.LambdaDKG) * time.Millisecond,
- NotarySetSize: uint32(configHelper.NotarySetSize().Uint64()),
+ NotarySetSize: uint32(s.NotarySetSize().Uint64()),
RoundLength: c.RoundLength,
MinBlockInterval: time.Duration(c.MinBlockInterval) * time.Millisecond,
}
}
-func (g *Governance) GetRoundHeight(round uint64) uint64 {
- return g.GetHeadState().RoundHeight(big.NewInt(int64(round))).Uint64()
-}
-
// NodeSet returns the current node set.
func (g *Governance) NodeSet(round uint64) []coreCrypto.PublicKey {
- s := g.GetStateForConfigAtRound(round)
- var pks []coreCrypto.PublicKey
+ configState, err := g.util.GetConfigState(round)
+ if err != nil {
+ panic(err)
+ }
- for _, n := range s.QualifiedNodes() {
+ var pks []coreCrypto.PublicKey
+ for _, n := range configState.QualifiedNodes() {
pk, err := coreEcdsa.NewPublicKeyFromByteSlice(n.PublicKey)
if err != nil {
panic(err)
@@ -233,9 +204,9 @@ func (g *Governance) DKGSetNodeKeyAddresses(round uint64) (map[common.Address]st
}
func (g *Governance) getOrUpdateDKGCache(round uint64) *dkgCacheItem {
- s := g.GetStateForDKGAtRound(round)
- if s == nil {
- log.Error("Failed to get DKG state", "round", round)
+ s, err := g.GetStateForDKGAtRound(round)
+ if err != nil {
+ log.Error("Failed to get DKG state", "round", round, "err", err)
return nil
}
reset := s.DKGResetCount(new(big.Int).SetUint64(round))
@@ -289,8 +260,9 @@ func (g *Governance) DKGMasterPublicKeys(round uint64) []*dkgTypes.MasterPublicK
}
func (g *Governance) IsDKGMPKReady(round uint64) bool {
- s := g.GetStateForDKGAtRound(round)
- if s == nil {
+ s, err := g.GetStateForDKGAtRound(round)
+ if err != nil {
+ log.Error("Failed to get state for DKG", "round", round, "err", err)
return false
}
config := g.Configuration(round)
@@ -300,8 +272,9 @@ func (g *Governance) IsDKGMPKReady(round uint64) bool {
}
func (g *Governance) IsDKGFinal(round uint64) bool {
- s := g.GetStateForDKGAtRound(round)
- if s == nil {
+ s, err := g.GetStateForDKGAtRound(round)
+ if err != nil {
+ log.Error("Failed to get state for DKG", "round", round, "err", err)
return false
}
config := g.Configuration(round)
@@ -311,18 +284,19 @@ func (g *Governance) IsDKGFinal(round uint64) bool {
}
func (g *Governance) IsDKGSuccess(round uint64) bool {
- s := g.GetStateForDKGAtRound(round)
- if s == nil {
+ s, err := g.GetStateForDKGAtRound(round)
+ if err != nil {
+ log.Error("Failed to get state for DKG", "round", round, "err", err)
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()
-}
-
func (g *Governance) DKGResetCount(round uint64) uint64 {
- return g.GetHeadState().DKGResetCount(big.NewInt(int64(round))).Uint64()
+ gs, err := g.GetHeadGovState()
+ if err != nil {
+ log.Error("Failed to get head governance state", "err", err)
+ }
+ return gs.DKGResetCount(big.NewInt(int64(round))).Uint64()
}
diff --git a/core/headerchain.go b/core/headerchain.go
index 7714f568c..7f48a5f57 100644
--- a/core/headerchain.go
+++ b/core/headerchain.go
@@ -425,7 +425,10 @@ func (c *headerVerifierCache) state(round uint64) *vm.GovernanceState {
if state, exist := c.stateCache.Get(round); exist {
return state.(*vm.GovernanceState)
}
- state := c.gov.GetStateForConfigAtRound(round)
+ state, err := c.gov.GetConfigState(round)
+ if err != nil {
+ panic(err)
+ }
c.stateCache.Add(round, state)
return state
}
diff --git a/core/state_transition.go b/core/state_transition.go
index 1b8a85655..c03ba3110 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -24,10 +24,10 @@ import (
"sync/atomic"
"github.com/tangerine-network/go-tangerine/common"
+ "github.com/tangerine-network/go-tangerine/core/state"
"github.com/tangerine-network/go-tangerine/core/vm"
"github.com/tangerine-network/go-tangerine/log"
"github.com/tangerine-network/go-tangerine/params"
- dexCore "github.com/tangerine-network/tangerine-consensus/core"
)
var legacyEvm = flag.Bool("legacy-evm", false, "make evm run origin logic")
@@ -190,6 +190,14 @@ func (st *StateTransition) preCheck() error {
return st.buyGas()
}
+func (st *StateTransition) GetHeadGovState() (*vm.GovernanceState, error) {
+ return &vm.GovernanceState{st.state}, nil
+}
+
+func (st *StateTransition) StateAt(height uint64) (*state.StateDB, error) {
+ return st.evm.StateAtNumber(height)
+}
+
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
@@ -205,25 +213,18 @@ func (st *StateTransition) inExtendedRound() bool {
}
}
- 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())
+ gs := vm.GovernanceState{st.state}
+ rgs, err := vm.GovUtil{st}.GetConfigState(round)
if err != nil {
- panic(err)
+ log.Error("Failed to get config state", "round", round, "err", err)
+ return false
}
- rgs := vm.GovernanceState{state}
roundEnd := gs.RoundHeight(st.evm.Round).Uint64() + rgs.RoundLength().Uint64()
- // Round 0 starts and height 0 instead of height 1.
+ // Round 0 starts at height 0 instead of height 1.
if round == 0 {
roundEnd += 1
}
diff --git a/core/tx_pool.go b/core/tx_pool.go
index 115a915b4..0f6b8d7e6 100644
--- a/core/tx_pool.go
+++ b/core/tx_pool.go
@@ -24,8 +24,6 @@ import (
"sync"
"time"
- dexCore "github.com/tangerine-network/tangerine-consensus/core"
-
"github.com/tangerine-network/go-tangerine/common"
"github.com/tangerine-network/go-tangerine/common/prque"
"github.com/tangerine-network/go-tangerine/core/state"
@@ -375,6 +373,18 @@ func (pool *TxPool) lockedReset(oldHead, newHead *types.Header) {
pool.reset(oldHead, newHead)
}
+func (pool *TxPool) GetHeadGovState() (*vm.GovernanceState, error) {
+ return &vm.GovernanceState{pool.currentState}, nil
+}
+
+func (pool *TxPool) StateAt(height uint64) (*state.StateDB, error) {
+ block := pool.chain.GetBlockByNumber(height)
+ if block == nil {
+ return nil, fmt.Errorf("Failed to get block, height = %d", height)
+ }
+ return pool.chain.StateAt(block.Header().Root)
+}
+
// reset retrieves the current state of the blockchain and ensures the content
// of the transaction pool is valid with regard to the chain state.
func (pool *TxPool) reset(oldHead, newHead *types.Header) {
@@ -391,26 +401,12 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
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.GovernanceState{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)
+ gs, err := vm.GovUtil{pool}.GetConfigState(newHead.Round)
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")
+ log.Error("Failed to get config state", "round", newHead.Round, "err", err)
+ panic(err)
}
- govState := &vm.GovernanceState{StateDB: configState}
- pool.setGovPrice(govState.MinGasPrice())
+ pool.setGovPrice(gs.MinGasPrice())
}
// validate the pool of pending transactions, this will remove
diff --git a/core/vm/oracle.go b/core/vm/oracle.go
index ee28343ae..8c8a3006c 100644
--- a/core/vm/oracle.go
+++ b/core/vm/oracle.go
@@ -45,7 +45,7 @@ type OracleContract interface {
var OracleContracts = map[common.Address]func() OracleContract{
GovernanceContractAddress: func() OracleContract {
return &GovernanceContract{
- coreDKGUtils: &defaultCoreDKGUtils{},
+ coreDKGUtil: &defaultCoreDKGUtil{},
}
},
RandomContractAddress: func() OracleContract {
diff --git a/core/vm/oracle_contracts.go b/core/vm/oracle_contracts.go
index e850811ff..a2c7d7814 100644
--- a/core/vm/oracle_contracts.go
+++ b/core/vm/oracle_contracts.go
@@ -29,6 +29,7 @@ import (
"github.com/tangerine-network/go-tangerine/accounts/abi"
"github.com/tangerine-network/go-tangerine/common"
+ "github.com/tangerine-network/go-tangerine/core/state"
"github.com/tangerine-network/go-tangerine/core/types"
"github.com/tangerine-network/go-tangerine/crypto"
"github.com/tangerine-network/go-tangerine/params"
@@ -529,6 +530,16 @@ func (s *GovernanceState) QualifiedNodes() []*nodeInfo {
}
return nodes
}
+func (s *GovernanceState) FinedNodes() []*nodeInfo {
+ var nodes []*nodeInfo
+ for i := int64(0); i < int64(s.LenNodes().Uint64()); i++ {
+ node := s.Node(big.NewInt(i))
+ if node.Fined.Cmp(big.NewInt(0)) > 0 {
+ nodes = append(nodes, node)
+ }
+ }
+ return nodes
+}
// mapping(address => uint256) public nodesOffsetByAddress;
func (s *GovernanceState) NodesOffsetByAddress(addr common.Address) *big.Int {
@@ -1274,47 +1285,19 @@ func (s *GovernanceState) emitDKGReset(round *big.Int, blockHeight *big.Int) {
})
}
-func getRoundState(evm *EVM, round *big.Int) (*GovernanceState, error) {
- gs := &GovernanceState{evm.StateDB}
- height := gs.RoundHeight(round).Uint64()
- if round.Uint64() > dexCore.ConfigRoundShift {
- if height == 0 {
- return nil, errExecutionReverted
- }
- }
- statedb, err := evm.StateAtNumber(height)
- return &GovernanceState{statedb}, err
-}
-
-func getConfigState(evm *EVM, round *big.Int) (*GovernanceState, error) {
- configRound := big.NewInt(0)
- if round.Uint64() > dexCore.ConfigRoundShift {
- configRound = new(big.Int).Sub(round, big.NewInt(int64(dexCore.ConfigRoundShift)))
- }
- return getRoundState(evm, configRound)
-}
-
-type coreDKGUtils interface {
+type coreDKGUtil interface {
NewGroupPublicKey(*GovernanceState, *big.Int, int) (tsigVerifierIntf, error)
}
type tsigVerifierIntf interface {
VerifySignature(coreCommon.Hash, coreCrypto.Signature) bool
}
-// GovernanceContract represents the governance contract of DEXCON.
-type GovernanceContract struct {
- evm *EVM
- state GovernanceState
- contract *Contract
- coreDKGUtils coreDKGUtils
-}
-
-// defaultCoreDKGUtils implements coreDKGUtils.
-type defaultCoreDKGUtils struct {
+// defaultCoreDKGUtil implements coreDKGUtil.
+type defaultCoreDKGUtil struct {
gpk atomic.Value
}
-func (c *defaultCoreDKGUtils) NewGroupPublicKey(
+func (c *defaultCoreDKGUtil) NewGroupPublicKey(
state *GovernanceState, round *big.Int, threshold int) (tsigVerifierIntf, error) {
var gpk *dkgTypes.GroupPublicKey
var err error
@@ -1337,6 +1320,23 @@ func (c *defaultCoreDKGUtils) NewGroupPublicKey(
return gpk, nil
}
+// GovernanceContract represents the governance contract of DEXCON.
+type GovernanceContract struct {
+ evm *EVM
+ state GovernanceState
+ contract *Contract
+ coreDKGUtil coreDKGUtil
+ util GovUtil
+}
+
+func (g *GovernanceContract) StateAt(height uint64) (*state.StateDB, error) {
+ return g.evm.StateAtNumber(height)
+}
+
+func (g *GovernanceContract) GetHeadGovState() (*GovernanceState, error) {
+ return &g.state, nil
+}
+
func (g *GovernanceContract) Address() common.Address {
return GovernanceContractAddress
}
@@ -1358,7 +1358,7 @@ func (g *GovernanceContract) useGas(gas uint64) ([]byte, error) {
}
func (g *GovernanceContract) configNotarySetSize(round *big.Int) *big.Int {
- s, err := getConfigState(g.evm, round)
+ s, err := g.util.GetConfigState(round.Uint64())
if err != nil {
return big.NewInt(0)
}
@@ -1366,34 +1366,15 @@ func (g *GovernanceContract) configNotarySetSize(round *big.Int) *big.Int {
}
func (g *GovernanceContract) getNotarySet(round *big.Int) map[coreTypes.NodeID]struct{} {
- crsRound := g.state.CRSRound()
- var crs common.Hash
- cmp := round.Cmp(crsRound)
- if round.Cmp(big.NewInt(int64(dexCore.DKGDelayRound))) <= 0 {
- state, err := getRoundState(g.evm, big.NewInt(0))
- if err != nil {
- return map[coreTypes.NodeID]struct{}{}
- }
- crs = state.CRS()
- for i := uint64(0); i < round.Uint64(); i++ {
- crs = crypto.Keccak256Hash(crs[:])
- }
- } else if cmp > 0 {
+ crs := g.util.CRS(round.Uint64())
+ if crs == (common.Hash{}) {
return map[coreTypes.NodeID]struct{}{}
- } else if cmp == 0 {
- crs = g.state.CRS()
- } else {
- state, err := getRoundState(g.evm, round)
- if err != nil {
- return map[coreTypes.NodeID]struct{}{}
- }
- crs = state.CRS()
}
target := coreTypes.NewNotarySetTarget(coreCommon.Hash(crs))
ns := coreTypes.NewNodeSet()
- state, err := getConfigState(g.evm, round)
+ state, err := g.util.GetConfigState(round.Uint64())
if err != nil {
return map[coreTypes.NodeID]struct{}{}
}
@@ -2000,7 +1981,7 @@ func (g *GovernanceContract) proposeCRS(nextRound *big.Int, signedCRS []byte) ([
threshold := coreUtils.GetDKGThreshold(&coreTypes.Config{
NotarySetSize: uint32(g.state.NotarySetSize().Uint64())})
- dkgGPK, err := g.coreDKGUtils.NewGroupPublicKey(&g.state, nextRound, threshold)
+ dkgGPK, err := g.coreDKGUtil.NewGroupPublicKey(&g.state, nextRound, threshold)
if err != nil {
return nil, errExecutionReverted
}
@@ -2137,7 +2118,7 @@ func (g *GovernanceContract) resetDKG(newSignedCRS []byte) ([]byte, error) {
new(big.Int).Mul(big.NewInt(100), resetCount))
roundHeight := g.state.RoundHeight(round)
- gs, err := getConfigState(g.evm, round)
+ gs, err := g.util.GetConfigState(round.Uint64())
if err != nil {
return nil, err
}
@@ -2167,7 +2148,7 @@ func (g *GovernanceContract) resetDKG(newSignedCRS []byte) ([]byte, error) {
// 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)
+ gpk, err := g.coreDKGUtil.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())}) {
@@ -2191,7 +2172,7 @@ func (g *GovernanceContract) resetDKG(newSignedCRS []byte) ([]byte, error) {
g.fineFailStopDKG(tsigThreshold)
// Update CRS.
- state, err := getRoundState(g.evm, round)
+ state, err := g.util.GetStateAtRound(round.Uint64())
if err != nil {
return nil, errExecutionReverted
}
@@ -2208,7 +2189,7 @@ func (g *GovernanceContract) resetDKG(newSignedCRS []byte) ([]byte, error) {
prevCRS = crypto.Keccak256Hash(prevCRS[:])
}
- dkgGPK, err := g.coreDKGUtils.NewGroupPublicKey(state, round,
+ dkgGPK, err := g.coreDKGUtil.NewGroupPublicKey(state, round,
coreUtils.GetDKGThreshold(&coreTypes.Config{
NotarySetSize: uint32(g.configNotarySetSize(round).Uint64())}))
if err != nil {
@@ -2251,6 +2232,7 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re
g.evm = evm
g.state = GovernanceState{evm.StateDB}
g.contract = contract
+ g.util = GovUtil{g}
// Parse input.
method, exists := GovernanceABI.Sig2Method[string(input[:4])]
diff --git a/core/vm/oracle_contracts_test.go b/core/vm/oracle_contracts_test.go
index ef6b9bde8..f0b045ac8 100644
--- a/core/vm/oracle_contracts_test.go
+++ b/core/vm/oracle_contracts_test.go
@@ -237,7 +237,7 @@ func (g *GovernanceContractTestSuite) SetupTest() {
func (g *GovernanceContractTestSuite) TearDownTest() {
OracleContracts[GovernanceContractAddress] = func() OracleContract {
return &GovernanceContract{
- coreDKGUtils: &defaultCoreDKGUtils{},
+ coreDKGUtil: &defaultCoreDKGUtil{},
}
}
}
@@ -1176,7 +1176,7 @@ func (g *GovernanceContractTestSuite) TestResetDKG() {
}
OracleContracts[GovernanceContractAddress] = func() OracleContract {
return &GovernanceContract{
- coreDKGUtils: mock,
+ coreDKGUtil: mock,
}
}
diff --git a/core/vm/utils.go b/core/vm/utils.go
new file mode 100644
index 000000000..0cc6343cc
--- /dev/null
+++ b/core/vm/utils.go
@@ -0,0 +1,92 @@
+package vm
+
+import (
+ "errors"
+ "math/big"
+
+ "github.com/tangerine-network/go-tangerine/common"
+ "github.com/tangerine-network/go-tangerine/core/state"
+ "github.com/tangerine-network/go-tangerine/crypto"
+ "github.com/tangerine-network/go-tangerine/log"
+ dexCore "github.com/tangerine-network/tangerine-consensus/core"
+)
+
+type GovUtilInterface interface {
+ GetHeadGovState() (*GovernanceState, error)
+ StateAt(height uint64) (*state.StateDB, error)
+}
+
+type GovUtil struct {
+ Intf GovUtilInterface
+}
+
+func (g GovUtil) GetRoundHeight(round uint64) uint64 {
+ gs, err := g.Intf.GetHeadGovState()
+ if err != nil {
+ return 0
+ }
+ return gs.RoundHeight(big.NewInt(int64(round))).Uint64()
+}
+
+func (g GovUtil) GetStateAtRound(round uint64) (*GovernanceState, error) {
+ height := g.GetRoundHeight(round)
+
+ if round != 0 && height == 0 {
+ log.Error("Governance state incorrect", "round", round, "got height", height)
+ return nil, errors.New("incorrect governance state")
+ }
+
+ s, err := g.Intf.StateAt(height)
+ if err != nil {
+ return nil, err
+ }
+ return &GovernanceState{StateDB: s}, nil
+}
+
+func (g GovUtil) GetConfigState(round uint64) (*GovernanceState, error) {
+ if round < dexCore.ConfigRoundShift {
+ round = 0
+ } else {
+ round -= dexCore.ConfigRoundShift
+ }
+ return g.GetStateAtRound(round)
+}
+
+func (g *GovUtil) CRSRound() uint64 {
+ gs, err := g.Intf.GetHeadGovState()
+ if err != nil {
+ return 0
+ }
+ return gs.CRSRound().Uint64()
+}
+
+func (g GovUtil) CRS(round uint64) common.Hash {
+ if round <= dexCore.DKGDelayRound {
+ s, err := g.GetStateAtRound(0)
+ if err != nil {
+ return common.Hash{}
+ }
+ crs := s.CRS()
+ for i := uint64(0); i < round; i++ {
+ crs = crypto.Keccak256Hash(crs[:])
+ }
+ return crs
+ }
+ if round > g.CRSRound() {
+ return common.Hash{}
+ }
+ var s *GovernanceState
+ var err error
+ if round == g.CRSRound() {
+ s, err = g.Intf.GetHeadGovState()
+ if err != nil {
+ return common.Hash{}
+ }
+ } else {
+ s, err = g.GetStateAtRound(round)
+ if err != nil {
+ return common.Hash{}
+ }
+ }
+ return s.CRS()
+}
diff --git a/dex/api_backend.go b/dex/api_backend.go
index 39c34550b..31b5a650e 100644
--- a/dex/api_backend.go
+++ b/dex/api_backend.go
@@ -187,7 +187,11 @@ func (b *DexAPIBackend) ProtocolVersion() int {
}
func (b *DexAPIBackend) SuggestPrice(ctx context.Context) (*big.Int, error) {
- return b.dex.governance.MinGasPrice(b.dex.blockchain.CurrentBlock().Round()), nil
+ gs, err := b.dex.governance.GetConfigState(b.dex.blockchain.CurrentBlock().Round())
+ if err != nil {
+ return nil, err
+ }
+ return gs.MinGasPrice(), nil
}
func (b *DexAPIBackend) ChainDb() ethdb.Database {
diff --git a/dex/app.go b/dex/app.go
index fb8ffa46d..10f977c2f 100644
--- a/dex/app.go
+++ b/dex/app.go
@@ -102,9 +102,14 @@ func (d *DexconApp) validateNonce(txs types.Transactions) (map[common.Address]ui
// validateGasPrice checks if no gas price is lower than minGasPrice defined in
// governance contract.
func (d *DexconApp) validateGasPrice(txs types.Transactions, round uint64) bool {
- minGasPrice := d.gov.MinGasPrice(round)
+ config, err := d.gov.RawConfiguration(round)
+ if err != nil {
+ log.Error("Failed to get configuration", "err", err)
+ return false
+ }
+
for _, tx := range txs {
- if minGasPrice.Cmp(tx.GasPrice()) > 0 {
+ if config.MinGasPrice.Cmp(tx.GasPrice()) > 0 {
return false
}
}
@@ -180,8 +185,12 @@ func (d *DexconApp) preparePayload(ctx context.Context, position coreTypes.Posit
return
}
- blockGasLimit := new(big.Int).SetUint64(d.gov.DexconConfiguration(position.Round).BlockGasLimit)
- minGasPrice := d.gov.DexconConfiguration(position.Round).MinGasPrice
+ config, err := d.gov.RawConfiguration(position.Round)
+ if err != nil {
+ return
+ }
+
+ blockGasLimit := new(big.Int).SetUint64(config.BlockGasLimit)
blockGasUsed := new(big.Int)
allTxs := make([]*types.Transaction, 0, 10000)
@@ -217,8 +226,8 @@ addressMap:
// Warning: the pending tx will also affect by syncing, so startIndex maybe negative
for i := startIndex; i >= 0 && i < len(txs); i++ {
tx := txs[i]
- if minGasPrice.Cmp(tx.GasPrice()) > 0 {
- log.Error("Invalid gas price minGas(%v) > get(%v)", minGasPrice, tx.GasPrice())
+ if config.MinGasPrice.Cmp(tx.GasPrice()) > 0 {
+ log.Error("Invalid gas price minGas(%v) > get(%v)", config.MinGasPrice, tx.GasPrice())
break
}
@@ -372,8 +381,14 @@ func (d *DexconApp) VerifyBlock(block *coreTypes.Block) coreTypes.BlockVerifySta
}
}
+ config, err := d.gov.RawConfiguration(block.Position.Round)
+ if err != nil {
+ log.Error("Failed to get raw configuration", "err", err)
+ return coreTypes.VerifyRetryLater
+ }
+
// Validate if balance is enough for TXs in this block.
- blockGasLimit := new(big.Int).SetUint64(d.gov.DexconConfiguration(block.Position.Round).BlockGasLimit)
+ blockGasLimit := new(big.Int).SetUint64(config.BlockGasLimit)
blockGasUsed := new(big.Int)
for _, tx := range transactions {
@@ -436,7 +451,10 @@ func (d *DexconApp) BlockDelivered(
var owner common.Address
if !block.IsEmpty() {
- gs := d.gov.GetStateForConfigAtRound(block.Position.Round)
+ gs, err := d.gov.GetConfigState(block.Position.Round)
+ if err != nil {
+ panic(err)
+ }
node, err := gs.GetNodeByID(block.ProposerID)
if err != nil {
panic(err)
@@ -444,11 +462,16 @@ func (d *DexconApp) BlockDelivered(
owner = node.Owner
}
+ config, err := d.gov.RawConfiguration(block.Position.Round)
+ if err != nil {
+ panic(err)
+ }
+
newBlock := types.NewBlock(&types.Header{
Number: new(big.Int).SetUint64(block.Position.Height),
Time: uint64(block.Timestamp.UnixNano() / 1000000),
Coinbase: owner,
- GasLimit: d.gov.DexconConfiguration(block.Position.Round).BlockGasLimit,
+ GasLimit: config.BlockGasLimit,
Difficulty: big.NewInt(1),
Round: block.Position.Round,
DexconMeta: dexconMeta,
diff --git a/dex/app_test.go b/dex/app_test.go
index 22b85b766..db9feb228 100644
--- a/dex/app_test.go
+++ b/dex/app_test.go
@@ -471,7 +471,12 @@ func (t *ppBlockLimitTester) ValidateResults(results []reflect.Value) error {
}
app := t.App.(*DexconApp)
- blockLimit := app.gov.DexconConfiguration(t.round).BlockGasLimit
+ config, err := app.gov.RawConfiguration(t.round)
+ if err != nil {
+ return fmt.Errorf("unable to get raw configuration: %v", err)
+ }
+
+ blockLimit := config.BlockGasLimit
totalGas := uint64(0)
for _, tx := range txs {
totalGas += tx.Gas()
@@ -2161,7 +2166,11 @@ func (f *TxFactory) Run() {
blockchain := f.App.(*DexconApp).blockchain
txPool := f.App.(*DexconApp).txPool
for {
- gasPrice := f.App.(*DexconApp).gov.GetHeadState().MinGasPrice()
+ hs, err := f.App.(*DexconApp).gov.GetHeadGovState()
+ if err != nil {
+ panic(err)
+ }
+ gasPrice := hs.MinGasPrice()
for i, key := range f.keys {
go func(at int, nonce uint64, key *ecdsa.PrivateKey) {
f.stopTimeMu.RLock()
diff --git a/dex/downloader/testchain_test.go b/dex/downloader/testchain_test.go
index 9595dc212..32e6110c4 100644
--- a/dex/downloader/testchain_test.go
+++ b/dex/downloader/testchain_test.go
@@ -332,15 +332,15 @@ func (g *govStateFetcher) SnapshotRound(round uint64, root common.Hash) {
g.rootByRound[round] = root
}
-func (g *govStateFetcher) GetStateForConfigAtRound(round uint64) *vm.GovernanceState {
+func (g *govStateFetcher) GetConfigState(round uint64) (*vm.GovernanceState, error) {
if root, ok := g.rootByRound[round]; ok {
s, err := state.New(root, g.db)
if err != nil {
- panic(err)
+ return nil, err
}
- return &vm.GovernanceState{s}
+ return &vm.GovernanceState{s}, nil
}
- return nil
+ return nil, nil
}
func (g *govStateFetcher) DKGSetNodeKeyAddresses(round uint64) (map[common.Address]struct{}, error) {
diff --git a/dex/governance.go b/dex/governance.go
index 1ca94e1dc..50de31a0e 100644
--- a/dex/governance.go
+++ b/dex/governance.go
@@ -58,9 +58,13 @@ func NewDexconGovernance(backend *DexAPIBackend, chainConfig *params.ChainConfig
return g
}
-// DexconConfiguration return raw config in state.
-func (d *DexconGovernance) DexconConfiguration(round uint64) *params.DexconConfig {
- return d.GetStateForConfigAtRound(round).Configuration()
+// RawConfiguration return raw config in state.
+func (d *DexconGovernance) RawConfiguration(round uint64) (*params.DexconConfig, error) {
+ gs, err := d.GetConfigState(round)
+ if err != nil {
+ return nil, err
+ }
+ return gs.Configuration(), nil
}
func (d *DexconGovernance) sendGovTx(ctx context.Context, data []byte) error {