aboutsummaryrefslogblamecommitdiffstats
path: root/core/vm/oracle_contracts_test.go
blob: 80bc9a73f2e21f774a73f9039466ab3ef590fe93 (plain) (tree)
1
2
3
4
5
6
7
8
9

                                                    
  
                                                                        



                                                                               
                                                                         




                                                                           
                                                      





                                  
                      

                   
              


                 
                                                                       
                                                                  


                                                                                 
                                                                             

                                                                          

                                                      
                                                  
                                                 
                                                  
                                               







                                                     



                                                                






                                                 










                                                                                  
                                      

                   

                                

 
                                                




                                                       
                           
                                       




                                                                                   

 
                                                              






                                                               


                                         






                                                               





                                         






                                                                
                 







                                                                                 


         
























                                                                                                      

                                                   
 
 
                                      

                   
                       


                                    
                                

 
                                                






                                                                          
                                       

                                                  
                                  


                                                                                        
                             
 






                                                                                                             
                       










                                          
 
                            

















                                                                                                              


                                                                       


                                           


                                                   




                                                                            

 





                                                                                                           
                                                                                         


                       
                                                            
                                               
 
                                                                       
                                

                               
                                                                              


                               
                                                                                        
                                


                                            
                                                                
                                                     










                                                                                                                       
                                                  





                                                                             
                                                    









                                                                                                    

                           
                                                       










                                                                                                                       

 
                                                           
                                                     

                                                     

                                                                     
                                                        
                                                                                                                       
                                
                                                                       
                                
 
                                                          
                                                       
                                                                
                                                                      




                                                                                                                   
                                         
                                                                       

                              






                                                                                                                      













                                                                                                

                   
                                                              
                                
                                                                              
                                
                                                       
                                                                      
 




                                                                              
 

                                              















                                                                              
                                
                                                                              
                                
 
                                                       

                                                          



                                                                             
                                                                
                                                                    

                          
                                                       
                                                       
                                                                                                                       
                                
                                                                        
                                
                                                                
                                                                          

                          
                                                                                                                      
                                
                                                                       
                                
 
                                                          
                                                       
                                                                                                       
 
                            
                                                              
                                
                                                                               
                                
 
                                      
                                             
                                                                       
                                                       
                                                                      
 
                                   
                                                       
                                
                                                                               
                                
 
                                                       

                                                                
                                                                           

                            
                                                              
                                
                                                                              
                                
                                                       

                                                                             
                                   
                                                       
                                
                                                                              
                                
 
                                                          
                                                                          






                                                                                         
                                               
                                                     


                                                     
                                                                                                                       
                                
                                                                          
                                                                            
                                
                                                       

                                                                      
                                                    
                                                                     

                                                   
                                                            
                                
                                                                            


                               
                                                









                                                        

                                                                      
                                
                                                                                   



                                                     
                                                            
                                
                                                                               


                               
                                                            
                                
                                                                            



                                                       

 
                                                              
                                               
 
                                                                   
                                                                    
                                 
                                
                                    

                                 

                                                          
                                
                                
                                                                        
                                

                               
                                                                              


                               
                                                                                        
                                

 
                                                               
                                               

               
                                                   
                                
                                                                                 
                                
                         
                                                         
                                







                                                                                

                 
                                                    
                                
                                                                                
                                
                                
                                                            
                                


                                                
                                                       
                                
                                                                                
                                
                          
                                                               
                                


                                                                     
                                                             
                                
                                                                                
                                
                                                                     
                                
                                                                                             

                         
                                                            
                                
                                                                                
                                
                                                                    
                                

                                                                 
                    
                                                       
                                
                                                                                
                                
                                                               
                                


                                                            
                                                        
                                
                                                                                
                                
                                                                
                                

                                                             
                         
                                                            
                                
                                                                                
                                
                                                                    
                                
                                                    
 











                                                                                
                      
                                                         
                                
                                                                                
                                
                                                                 
                                
                                                    
 

                                                          
                                
                                                                                
                                
                                                                  
                                
                                                               

                            
                                                               
                                
                                                                                
                                
                                                                       
                                
                                                                    








                                                                                

 
                                                         
                                                 


                                                      
                                                                     
                                                                                                                            
                                
                                                                       





















                                                                                            
                                                                                            
                                
                                                                              

                              
                                                                                            
                                
                                                                              





                                                                   
                                                                                            
                                
                                                                              






                                                          
                                                                 
                                
                                                                                 


                                
                                                                   



                                
                                                          
                                                 


                                                      
                                                                     
                                                                                                                                    
                                
                                                                       
































                                                                           
                                                                                              
                                
                                                                              

                              
                                                                                              
                                
                                                                              





                                                                   
                                                                                              
                                
                                                                              






                                                          
                                                                 
                                
                                                                                 


                                
                                                                   



                                
                                                              
                                                     

                                                     
                                                           
                                
                                                                                 

                                
                                                          
                                
                                                                                

                                
                 
                                                                     
                                                                                                                              
                                
                                                                       
                                
 
                                                                   
                                
                                                                                
                                
 
                                                          
                                
                                                                                
                                
                          
                                                                  
                                

                                                 
                                                                         
                                
                                                                                
                                
                                                                           


                                                 
                                                 
                                
                                                                                
                                
                                                                                
                                
                                                                                  
                                

                                                 
                                                                        
                                
                                                                                
                                

 
                                                           














                                                                                           




                            
                                                                                                     















                                                                                            
                                                             



                                                                             
                                                                                                                               






                                                                               











                                                                                                           
                                                             
                                                      
                                                       
                                                
                                                     
                                                    
                                                      



                                                                 
                                                 
                                                                               










                                                                                    
                                       

                                        
                                                                                  




                                                                





                                                       
                                             





                                                      


                                                                 

                                                      

                                                     

                                                               


                                         


                                                                                     
                                                   
                                                               
                 
 
                          
                                                                                              
                                                           
                                                                        

                         
 

         


                                 




                                                                            
 
                                         
                                                  
                                               
                                     

                                                      



                                                                               
 
                                       
         




                                                                   

                                     

                                                            

                                                            
 

                                                                                             
                                                       







                                                                                      
                                                        

                                         
                                                             
                                              
                                                                            
                                                     
                                                                

                                               
                                                       
                                               
                                                                             
                                                     
                                                                 

                 


                                                                                      


         
                                        
                                                   
 
// Copyright 2018 The dexon-consensus Authors
// This file is part of the dexon-consensus library.
//
// The dexon-consensus library is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// The dexon-consensus library is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
// General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the dexon-consensus library. If not, see
// <http://www.gnu.org/licenses/>.

package vm

import (
    "bytes"
    "crypto/ecdsa"
    "math/big"
    "math/rand"
    "sort"
    "testing"
    "time"

    coreCommon "github.com/dexon-foundation/dexon-consensus/common"
    dexCore "github.com/dexon-foundation/dexon-consensus/core"
    coreCrypto "github.com/dexon-foundation/dexon-consensus/core/crypto"
    coreEcdsa "github.com/dexon-foundation/dexon-consensus/core/crypto/ecdsa"
    coreTypes "github.com/dexon-foundation/dexon-consensus/core/types"
    dkgTypes "github.com/dexon-foundation/dexon-consensus/core/types/dkg"
    coreUtils "github.com/dexon-foundation/dexon-consensus/core/utils"

    "github.com/dexon-foundation/dexon/common"
    "github.com/dexon-foundation/dexon/core/state"
    "github.com/dexon-foundation/dexon/crypto"
    "github.com/dexon-foundation/dexon/ethdb"
    "github.com/dexon-foundation/dexon/params"
    "github.com/dexon-foundation/dexon/rlp"
    "github.com/stretchr/testify/suite"
)

func init() {
    rand.Seed(time.Now().UnixNano())
}

func randomBytes(minLength, maxLength int32) []byte {
    length := minLength
    if maxLength != minLength {
        length += rand.Int31() % (maxLength - minLength)
    }
    b := make([]byte, length)
    for i := range b {
        b[i] = byte(65 + rand.Int31()%60)
    }
    return b
}

func newPrefundAccount(s *state.StateDB) (*ecdsa.PrivateKey, common.Address) {
    privKey, err := crypto.GenerateKey()
    if err != nil {
        panic(err)
    }
    address := crypto.PubkeyToAddress(privKey.PublicKey)

    s.AddBalance(address, new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2e6)))
    return privKey, address
}

type GovernanceStateTestSuite struct {
    suite.Suite

    stateDB *state.StateDB
    s       *GovernanceState
}

func (g *GovernanceStateTestSuite) SetupTest() {
    db := state.NewDatabase(ethdb.NewMemDatabase())
    statedb, err := state.New(common.Hash{}, db)
    if err != nil {
        panic(err)
    }
    g.stateDB = statedb
    g.s = &GovernanceState{statedb}

    config := params.TestnetChainConfig.Dexcon
    g.s.Initialize(config, new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e7)))

    statedb.Commit(true)
}

func (g *GovernanceStateTestSuite) TestReadWriteEraseBytes() {
    for i := 0; i < 100; i++ {
        // Short bytes.
        loc := big.NewInt(rand.Int63())
        data := randomBytes(3, 32)
        g.s.writeBytes(loc, data)
        read := g.s.readBytes(loc)
        g.Require().Equal(0, bytes.Compare(data, read))
        g.s.eraseBytes(loc)
        read = g.s.readBytes(loc)
        g.Require().Len(read, 0)

        // long bytes.
        loc = big.NewInt(rand.Int63())
        data = randomBytes(33, 2560)
        g.s.writeBytes(loc, data)
        read = g.s.readBytes(loc)
        g.Require().Equal(0, bytes.Compare(data, read))
        g.s.eraseBytes(loc)
        read = g.s.readBytes(loc)
        g.Require().Len(read, 0)
    }
}

func (g *GovernanceStateTestSuite) TestReadWriteErase1DArray() {
    for j := 0; j < 50; j++ {
        idx := big.NewInt(int64(j))
        data := make([][]byte, 30)
        for key := range data {
            data[key] = randomBytes(3, 32)
            g.s.appendTo1DByteArray(idx, data[key])
        }
        read := g.s.read1DByteArray(idx)
        g.Require().Len(read, len(data))
        for key := range data {
            g.Require().Equal(0, bytes.Compare(data[key], read[key]))
        }
        g.s.erase1DByteArray(idx)
        read = g.s.read1DByteArray(idx)
        g.Require().Len(read, 0)
    }
}

func (g *GovernanceStateTestSuite) TestDisqualify() {
    privKey, addr := newPrefundAccount(g.stateDB)
    pk := crypto.FromECDSAPub(&privKey.PublicKey)

    g.s.Register(addr, pk, "Test", "test@dexon.org", "Taipei", "https://test.com", g.s.MinStake())

    node := g.s.Node(big.NewInt(0))
    g.Require().Equal(uint64(0), node.Fined.Uint64())

    // Disqualify
    g.s.Disqualify(node)
    node = g.s.Node(big.NewInt(0))
    g.Require().Equal(uint64(1), node.Fined.Uint64())

    // Disqualify again should change nothing.
    g.s.Disqualify(node)
    node = g.s.Node(big.NewInt(0))
    g.Require().Equal(uint64(1), node.Fined.Uint64())

    // Disqualify none exist node should return error.
    privKey2, _ := newPrefundAccount(g.stateDB)
    node.PublicKey = crypto.FromECDSAPub(&privKey2.PublicKey)
    g.Require().Error(g.s.Disqualify(node))
}

func TestGovernanceState(t *testing.T) {
    suite.Run(t, new(GovernanceStateTestSuite))
}

type OracleContractsTestSuite struct {
    suite.Suite

    context Context
    config  *params.DexconConfig
    memDB   *ethdb.MemDatabase
    stateDB *state.StateDB
    s       *GovernanceState
}

func (g *OracleContractsTestSuite) SetupTest() {
    memDB := ethdb.NewMemDatabase()
    stateDB, err := state.New(common.Hash{}, state.NewDatabase(memDB))
    if err != nil {
        panic(err)
    }
    g.memDB = memDB
    g.stateDB = stateDB
    g.s = &GovernanceState{stateDB}

    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
    config.DKGSetSize = 7

    g.config = config

    // Give governance contract balance so it will not be deleted because of being an empty state object.
    stateDB.AddBalance(GovernanceContractAddress, big.NewInt(1))

    // Genesis CRS.
    crs := crypto.Keccak256Hash([]byte(config.GenesisCRSText))
    g.s.SetCRS(crs)

    // Round 0 height.
    g.s.PushRoundHeight(big.NewInt(0))

    // Owner.
    g.s.SetOwner(g.config.Owner)

    // Governance configuration.
    g.s.UpdateConfiguration(config)

    g.stateDB.Commit(true)

    g.context = Context{
        CanTransfer: func(db StateDB, addr common.Address, amount *big.Int) bool {
            return db.GetBalance(addr).Cmp(amount) >= 0
        },
        Transfer: func(db StateDB, sender common.Address, recipient common.Address, amount *big.Int) {
            db.SubBalance(sender, amount)
            db.AddBalance(recipient, amount)
        },
        GetRoundHeight: func(round uint64) (uint64, bool) {
            switch round {
            case 0:
                return 0, true
            case 1:
                return 1000, true
            case 2:
                return 2000, true
            }
            return 0, false
        },
        StateAtNumber: func(n uint64) (*state.StateDB, error) {
            return g.stateDB, nil
        },
        BlockNumber: big.NewInt(0),
    }

}

func (g *OracleContractsTestSuite) TearDownTest() {
    OracleContracts[GovernanceContractAddress] = func() OracleContract {
        return &GovernanceContract{
            coreDKGUtils: &defaultCoreDKGUtils{},
        }
    }
}

func (g *OracleContractsTestSuite) call(
    contractAddr common.Address, caller common.Address, input []byte, value *big.Int) ([]byte, error) {

    g.context.Time = big.NewInt(time.Now().UnixNano() / 1000000)

    evm := NewEVM(g.context, g.stateDB, params.TestChainConfig, Config{IsBlockProposer: true})
    ret, _, err := evm.Call(AccountRef(caller), contractAddr, input, 10000000, value)
    return ret, err
}

func (g *OracleContractsTestSuite) TestTransferOwnership() {
    _, addr := newPrefundAccount(g.stateDB)

    input, err := GovernanceABI.ABI.Pack("transferOwnership", addr)
    g.Require().NoError(err)

    // Call with non-owner.
    _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NotNil(err)

    // Call with owner.
    _, err = g.call(GovernanceContractAddress, g.config.Owner, input, big.NewInt(0))
    g.Require().NoError(err)
    g.Require().Equal(addr, g.s.Owner())
}

func (g *OracleContractsTestSuite) TestTransferNodeOwnership() {
    privKey, addr := newPrefundAccount(g.stateDB)
    pk := crypto.FromECDSAPub(&privKey.PublicKey)
    nodeKeyAddr := crypto.PubkeyToAddress(privKey.PublicKey)

    amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6))
    input, err := GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org")
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr, input, amount)
    g.Require().NoError(err)

    offset := g.s.NodesOffsetByAddress(addr)

    _, newAddr := newPrefundAccount(g.stateDB)
    newNodeKeyAddr := crypto.PubkeyToAddress(privKey.PublicKey)

    input, err = GovernanceABI.ABI.Pack("transferNodeOwnership", newAddr)
    g.Require().NoError(err)

    // Call with non-owner.
    _, noneOwner := newPrefundAccount(g.stateDB)
    _, err = g.call(GovernanceContractAddress, noneOwner, input, big.NewInt(0))
    g.Require().Error(err)

    // Call with owner.
    _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)
    g.Require().Equal(uint64(0), g.s.NodesOffsetByAddress(addr).Uint64())
    g.Require().Equal(uint64(0), g.s.NodesOffsetByNodeKeyAddress(nodeKeyAddr).Uint64())
    g.Require().Equal(offset.Uint64(), g.s.NodesOffsetByAddress(newAddr).Uint64())
    g.Require().Equal(offset.Uint64(), g.s.NodesOffsetByNodeKeyAddress(newNodeKeyAddr).Uint64())

    // Call with owner.
    privKey2, addr2 := newPrefundAccount(g.stateDB)
    pk2 := crypto.FromECDSAPub(&privKey2.PublicKey)
    input, err = GovernanceABI.ABI.Pack("register", pk2, "Test2", "test1@dexon.org", "Taipei", "https://dexon.org")
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr2, input, amount)
    g.Require().NoError(err)

    // Transfer to duplicate owner address.
    input, err = GovernanceABI.ABI.Pack("transferNodeOwnership", addr2)
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, newAddr, input, amount)
    g.Require().Error(err)
}

func (g *OracleContractsTestSuite) TestStakingMechanism() {
    privKey, addr := newPrefundAccount(g.stateDB)
    pk := crypto.FromECDSAPub(&privKey.PublicKey)

    // Register with some stake.
    amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5))
    balanceBeforeStake := g.stateDB.GetBalance(addr)
    input, err := GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org")
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr, input, amount)
    g.Require().NoError(err)

    g.Require().Equal(1, int(g.s.LenNodes().Uint64()))
    g.Require().Equal(0, len(g.s.QualifiedNodes()))
    g.Require().Equal("Test1", g.s.Node(big.NewInt(0)).Name)
    g.Require().Equal(amount.String(), g.s.TotalStaked().String())

    // Check balance.
    g.Require().Equal(new(big.Int).Sub(balanceBeforeStake, amount), g.stateDB.GetBalance(addr))
    g.Require().Equal(new(big.Int).Add(big.NewInt(1), amount), g.stateDB.GetBalance(GovernanceContractAddress))

    // Registering again should fail.
    _, err = g.call(GovernanceContractAddress, addr, input, amount)
    g.Require().Error(err)

    // Duplicate public key should fail
    _, addrDup := newPrefundAccount(g.stateDB)
    input, err = GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org")
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addrDup, input, amount)
    g.Require().Error(err)

    // Stake more to qualify.
    input, err = GovernanceABI.ABI.Pack("stake")
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr, input, amount)
    g.Require().NoError(err)
    g.Require().Equal(1, len(g.s.QualifiedNodes()))
    g.Require().Equal(new(big.Int).Add(amount, amount).String(), g.s.TotalStaked().String())

    // Unstake more then staked should fail.
    unstakeAmount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e6))
    input, err = GovernanceABI.ABI.Pack("unstake", unstakeAmount)
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().Error(err)

    // Unstake.
    input, err = GovernanceABI.ABI.Pack("unstake", amount)
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)
    g.Require().Equal(0, len(g.s.QualifiedNodes()))
    g.Require().Equal(amount.String(), g.s.TotalStaked().String())

    // Withdraw immediately should fail.
    input, err = GovernanceABI.ABI.Pack("withdraw")
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().Error(err)

    // Wait for lockup time than withdraw.
    time.Sleep(time.Second * 2)
    input, err = GovernanceABI.ABI.Pack("withdraw")
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)

    g.Require().Equal(0, len(g.s.QualifiedNodes()))
    g.Require().Equal(1, int(g.s.LenNodes().Uint64()))

    // Unstake all to remove node.
    input, err = GovernanceABI.ABI.Pack("unstake", amount)
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)

    time.Sleep(time.Second * 2)
    input, err = GovernanceABI.ABI.Pack("withdraw")
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)

    g.Require().Equal(0, len(g.s.QualifiedNodes()))
    g.Require().Equal(0, int(g.s.LenNodes().Uint64()))

    node := g.s.Node(big.NewInt(0))
    g.Require().Equal(big.NewInt(0).String(), node.Staked.String())
    g.Require().Equal(big.NewInt(0).String(), g.s.TotalStaked().String())

    // Stake 2 nodes, and unstake the first then the second.
    amount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6))

    // 2nd node Stake.
    privKey2, addr2 := newPrefundAccount(g.stateDB)
    pk2 := crypto.FromECDSAPub(&privKey2.PublicKey)
    input, err = GovernanceABI.ABI.Pack("register", pk2, "Test2", "test2@dexon.org", "Taipei", "https://dexon.org")
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr2, input, amount)
    g.Require().NoError(err)
    g.Require().Equal("Test2", g.s.Node(big.NewInt(0)).Name)
    g.Require().Equal(0, int(g.s.NodesOffsetByAddress(addr2).Int64()))

    // 1st node Stake.
    input, err = GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org")
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr, input, amount)
    g.Require().NoError(err)

    g.Require().Equal(2, int(g.s.LenNodes().Uint64()))
    g.Require().Equal(2, len(g.s.QualifiedNodes()))
    g.Require().Equal(new(big.Int).Mul(amount, big.NewInt(2)).String(), g.s.TotalStaked().String())

    // 2nd node Unstake.
    input, err = GovernanceABI.ABI.Pack("unstake", amount)
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr2, input, big.NewInt(0))
    g.Require().NoError(err)

    node = g.s.Node(big.NewInt(0))
    g.Require().Equal("Test2", node.Name)
    g.Require().Equal(big.NewInt(0).String(), node.Staked.String())
    g.Require().Equal(1, len(g.s.QualifiedNodes()))
    g.Require().Equal(amount.String(), g.s.TotalStaked().String())

    time.Sleep(time.Second * 2)
    input, err = GovernanceABI.ABI.Pack("withdraw")
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr2, input, big.NewInt(0))
    g.Require().NoError(err)

    g.Require().Equal(1, len(g.s.QualifiedNodes()))
    g.Require().Equal(1, int(g.s.LenNodes().Uint64()))
    g.Require().Equal("Test1", g.s.Node(big.NewInt(0)).Name)
    g.Require().Equal(-1, int(g.s.NodesOffsetByAddress(addr2).Int64()))

    // 1st node Unstake.
    input, err = GovernanceABI.ABI.Pack("unstake", amount)
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)
    g.Require().Equal(0, len(g.s.QualifiedNodes()))
    g.Require().Equal(big.NewInt(0).String(), g.s.TotalStaked().String())

    time.Sleep(time.Second * 2)
    input, err = GovernanceABI.ABI.Pack("withdraw")
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)

    g.Require().Equal(0, int(g.s.LenNodes().Uint64()))
    g.Require().Equal(-1, int(g.s.NodesOffsetByAddress(addr).Int64()))

    // Check balance.
    g.Require().Equal(balanceBeforeStake, g.stateDB.GetBalance(addr))
    g.Require().Equal(balanceBeforeStake, g.stateDB.GetBalance(addr2))
    g.Require().Equal(big.NewInt(1), g.stateDB.GetBalance(GovernanceContractAddress))
}

func (g *OracleContractsTestSuite) TestFine() {
    privKey, addr := newPrefundAccount(g.stateDB)
    pk := crypto.FromECDSAPub(&privKey.PublicKey)

    // Stake.
    input, err := GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org")
    g.Require().NoError(err)
    ownerStaked := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6))
    _, err = g.call(GovernanceContractAddress, addr, input, ownerStaked)
    g.Require().NoError(err)
    g.Require().Equal(1, len(g.s.QualifiedNodes()))
    g.Require().Equal(ownerStaked, g.s.Node(big.NewInt(0)).Staked)

    _, finePayer := newPrefundAccount(g.stateDB)
    amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5))

    // Paying to node without fine should fail.
    input, err = GovernanceABI.ABI.Pack("payFine", addr)
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, finePayer, input, amount)
    g.Require().NotNil(err)

    // Fined.
    offset := g.s.NodesOffsetByAddress(addr)
    g.Require().True(offset.Cmp(big.NewInt(0)) >= 0)
    node := g.s.Node(offset)
    node.Fined = new(big.Int).Set(amount)
    g.s.UpdateNode(offset, node)
    node = g.s.Node(offset)
    g.Require().Equal(0, node.Fined.Cmp(amount))

    // Not qualified after fined.
    g.Require().Equal(0, len(g.s.QualifiedNodes()))

    // Cannot unstake before fines are paied.
    input, err = GovernanceABI.ABI.Pack("unstake", big.NewInt(10))
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, finePayer, input, big.NewInt(0))
    g.Require().NotNil(err)

    // Paying more than fine should fail.
    payAmount := new(big.Int).Add(amount, amount)
    input, err = GovernanceABI.ABI.Pack("payFine", addr)
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, finePayer, input, payAmount)
    g.Require().NotNil(err)

    // Pay the fine.
    input, err = GovernanceABI.ABI.Pack("payFine", addr)
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, finePayer, input, amount)
    g.Require().NoError(err)

    // Qualified.
    g.Require().Equal(1, len(g.s.QualifiedNodes()))
}

func (g *OracleContractsTestSuite) TestUpdateConfiguration() {
    _, addr := newPrefundAccount(g.stateDB)

    input, err := GovernanceABI.ABI.Pack("updateConfiguration",
        new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)),
        big.NewInt(1000),
        big.NewInt(2e9),
        big.NewInt(8000000),
        big.NewInt(250),
        big.NewInt(2500),
        big.NewInt(int64(70.5*decimalMultiplier)),
        big.NewInt(264*decimalMultiplier),
        big.NewInt(600),
        big.NewInt(900),
        []*big.Int{big.NewInt(1), big.NewInt(1), big.NewInt(1)})
    g.Require().NoError(err)

    // Call with non-owner.
    _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NotNil(err)

    // Call with owner.
    _, err = g.call(GovernanceContractAddress, g.config.Owner, input, big.NewInt(0))
    g.Require().NoError(err)
}

func (g *OracleContractsTestSuite) TestConfigurationReading() {
    _, addr := newPrefundAccount(g.stateDB)

    // CRS.
    input, err := GovernanceABI.ABI.Pack("crs")
    g.Require().NoError(err)
    res, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)
    var crs0 [32]byte
    err = GovernanceABI.ABI.Unpack(&crs0, "crs", res)
    g.Require().NoError(err)
    g.Require().Equal(crypto.Keccak256Hash([]byte(g.config.GenesisCRSText)),
        common.BytesToHash(crs0[:]))

    // CRSRound.
    input, err = GovernanceABI.ABI.Pack("crsRound")
    g.Require().NoError(err)
    res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)

    // Owner.
    input, err = GovernanceABI.ABI.Pack("owner")
    g.Require().NoError(err)
    res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)
    var owner common.Address
    err = GovernanceABI.ABI.Unpack(&owner, "owner", res)
    g.Require().NoError(err)
    g.Require().Equal(g.config.Owner, owner)

    // MinStake.
    input, err = GovernanceABI.ABI.Pack("minStake")
    g.Require().NoError(err)
    res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)
    var value *big.Int
    err = GovernanceABI.ABI.Unpack(&value, "minStake", res)
    g.Require().NoError(err)
    g.Require().Equal(g.config.MinStake.String(), value.String())

    // BlockReward.
    input, err = GovernanceABI.ABI.Pack("miningVelocity")
    g.Require().NoError(err)
    res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)
    err = GovernanceABI.ABI.Unpack(&value, "miningVelocity", res)
    g.Require().NoError(err)
    g.Require().Equal(g.config.MiningVelocity, float32(value.Uint64())/decimalMultiplier)

    // BlockGasLimit.
    input, err = GovernanceABI.ABI.Pack("blockGasLimit")
    g.Require().NoError(err)
    res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)
    err = GovernanceABI.ABI.Unpack(&value, "blockGasLimit", res)
    g.Require().NoError(err)
    g.Require().Equal(g.config.BlockGasLimit, value.Uint64())

    // LambdaBA.
    input, err = GovernanceABI.ABI.Pack("lambdaBA")
    g.Require().NoError(err)
    res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)
    err = GovernanceABI.ABI.Unpack(&value, "lambdaBA", res)
    g.Require().NoError(err)
    g.Require().Equal(g.config.LambdaBA, value.Uint64())

    // LambdaDKG.
    input, err = GovernanceABI.ABI.Pack("lambdaDKG")
    g.Require().NoError(err)
    res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)
    err = GovernanceABI.ABI.Unpack(&value, "lambdaDKG", res)
    g.Require().NoError(err)
    g.Require().Equal(g.config.LambdaDKG, value.Uint64())

    // NotarySetSize.
    input, err = GovernanceABI.ABI.Pack("notarySetSize")
    g.Require().NoError(err)
    res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)
    err = GovernanceABI.ABI.Unpack(&value, "notarySetSize", res)
    g.Require().NoError(err)
    g.Require().True(uint32(value.Uint64()) > 0)

    // DKGRound.
    input, err = GovernanceABI.ABI.Pack("dkgRound")
    g.Require().NoError(err)
    res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)

    // DKGResetCount.
    input, err = GovernanceABI.ABI.Pack("dkgResetCount", big.NewInt(3))
    g.Require().NoError(err)
    res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)

    // DKGSetSize.
    input, err = GovernanceABI.ABI.Pack("dkgSetSize")
    g.Require().NoError(err)
    res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)
    err = GovernanceABI.ABI.Unpack(&value, "dkgSetSize", res)
    g.Require().NoError(err)
    g.Require().True(uint32(value.Uint64()) > 0)

    // RoundLength.
    input, err = GovernanceABI.ABI.Pack("roundLength")
    g.Require().NoError(err)
    res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)
    err = GovernanceABI.ABI.Unpack(&value, "roundLength", res)
    g.Require().NoError(err)
    g.Require().Equal(g.config.RoundLength, value.Uint64())

    // MinBlockInterval.
    input, err = GovernanceABI.ABI.Pack("minBlockInterval")
    g.Require().NoError(err)
    res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)
    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() {
    key, addr := newPrefundAccount(g.stateDB)
    pkBytes := crypto.FromECDSAPub(&key.PublicKey)

    // Stake.
    amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5))
    input, err := GovernanceABI.ABI.Pack("register", pkBytes, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org")
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr, input, amount)
    g.Require().NoError(err)

    pubKey := coreEcdsa.NewPublicKeyFromECDSA(&key.PublicKey)
    privKey := coreEcdsa.NewPrivateKeyFromECDSA(key)
    vote1 := coreTypes.NewVote(coreTypes.VoteCom, coreCommon.NewRandomHash(), uint64(0))
    vote1.ProposerID = coreTypes.NewNodeID(pubKey)

    vote2 := vote1.Clone()
    for vote2.BlockHash == vote1.BlockHash {
        vote2.BlockHash = coreCommon.NewRandomHash()
    }
    vote1.Signature, err = privKey.Sign(coreUtils.HashVote(vote1))
    g.Require().NoError(err)
    vote2.Signature, err = privKey.Sign(coreUtils.HashVote(vote2))
    g.Require().NoError(err)

    vote1Bytes, err := rlp.EncodeToBytes(vote1)
    g.Require().NoError(err)
    vote2Bytes, err := rlp.EncodeToBytes(vote2)
    g.Require().NoError(err)

    // Report wrong type (fork block)
    input, err = GovernanceABI.ABI.Pack("report", big.NewInt(2), vote1Bytes, vote2Bytes)
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().Error(err)

    input, err = GovernanceABI.ABI.Pack("report", big.NewInt(1), vote1Bytes, vote2Bytes)
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)

    node := g.s.Node(big.NewInt(0))
    g.Require().Equal(node.Fined, g.s.FineValue(big.NewInt(1)))

    // Duplicate report should fail.
    input, err = GovernanceABI.ABI.Pack("report", big.NewInt(1), vote1Bytes, vote2Bytes)
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().Error(err)

    // Check if finedRecords is set.
    payloads := [][]byte{vote1Bytes, vote2Bytes}
    sort.Sort(sortBytes(payloads))

    hash := Bytes32(crypto.Keccak256Hash(payloads...))
    input, err = GovernanceABI.ABI.Pack("finedRecords", hash)
    g.Require().NoError(err)
    res, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)

    var value bool
    err = GovernanceABI.ABI.Unpack(&value, "finedRecords", res)
    g.Require().NoError(err)
    g.Require().True(value)
}

func (g *OracleContractsTestSuite) TestReportForkBlock() {
    key, addr := newPrefundAccount(g.stateDB)
    pkBytes := crypto.FromECDSAPub(&key.PublicKey)

    // Stake.
    amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5))
    input, err := GovernanceABI.ABI.Pack("register", pkBytes, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org")
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr, input, amount)
    g.Require().NoError(err)

    privKey := coreEcdsa.NewPrivateKeyFromECDSA(key)
    block1 := &coreTypes.Block{
        ProposerID: coreTypes.NewNodeID(privKey.PublicKey()),
        ParentHash: coreCommon.NewRandomHash(),
        Timestamp:  time.Now(),
    }

    block2 := block1.Clone()
    for block2.ParentHash == block1.ParentHash {
        block2.ParentHash = coreCommon.NewRandomHash()
    }

    hashBlock := func(block *coreTypes.Block) coreCommon.Hash {
        block.PayloadHash = coreCrypto.Keccak256Hash(block.Payload)
        var err error
        block.Hash, err = coreUtils.HashBlock(block)
        g.Require().NoError(err)
        return block.Hash
    }

    block1.Signature, err = privKey.Sign(hashBlock(block1))
    g.Require().NoError(err)
    block2.Signature, err = privKey.Sign(hashBlock(block2))
    g.Require().NoError(err)

    block1Bytes, err := rlp.EncodeToBytes(block1)
    g.Require().NoError(err)
    block2Bytes, err := rlp.EncodeToBytes(block2)
    g.Require().NoError(err)

    // Report wrong type (fork vote)
    input, err = GovernanceABI.ABI.Pack("report", big.NewInt(1), block1Bytes, block2Bytes)
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().Error(err)

    input, err = GovernanceABI.ABI.Pack("report", big.NewInt(2), block1Bytes, block2Bytes)
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)

    node := g.s.Node(big.NewInt(0))
    g.Require().Equal(node.Fined, g.s.FineValue(big.NewInt(2)))

    // Duplicate report should fail.
    input, err = GovernanceABI.ABI.Pack("report", big.NewInt(2), block1Bytes, block2Bytes)
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().Error(err)

    // Check if finedRecords is set.
    payloads := [][]byte{block1Bytes, block2Bytes}
    sort.Sort(sortBytes(payloads))

    hash := Bytes32(crypto.Keccak256Hash(payloads...))
    input, err = GovernanceABI.ABI.Pack("finedRecords", hash)
    g.Require().NoError(err)
    res, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)

    var value bool
    err = GovernanceABI.ABI.Unpack(&value, "finedRecords", res)
    g.Require().NoError(err)
    g.Require().True(value)
}

func (g *OracleContractsTestSuite) TestMiscVariableReading() {
    privKey, addr := newPrefundAccount(g.stateDB)
    pk := crypto.FromECDSAPub(&privKey.PublicKey)

    input, err := GovernanceABI.ABI.Pack("totalSupply")
    g.Require().NoError(err)
    res, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)

    input, err = GovernanceABI.ABI.Pack("totalStaked")
    g.Require().NoError(err)
    res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)

    // Stake.
    amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5))
    input, err = GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org")
    g.Require().NoError(err)
    _, err = g.call(GovernanceContractAddress, addr, input, amount)
    g.Require().NoError(err)

    input, err = GovernanceABI.ABI.Pack("nodes", big.NewInt(0))
    g.Require().NoError(err)
    res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)

    input, err = GovernanceABI.ABI.Pack("nodesLength")
    g.Require().NoError(err)
    res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)
    var value *big.Int
    err = GovernanceABI.ABI.Unpack(&value, "nodesLength", res)
    g.Require().NoError(err)
    g.Require().Equal(1, int(value.Uint64()))

    input, err = GovernanceABI.ABI.Pack("nodesOffsetByAddress", addr)
    g.Require().NoError(err)
    res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)
    err = GovernanceABI.ABI.Unpack(&value, "nodesOffsetByAddress", res)
    g.Require().NoError(err)
    g.Require().Equal(0, int(value.Uint64()))

    addr, err = publicKeyToNodeKeyAddress(pk)
    g.Require().NoError(err)
    input, err = GovernanceABI.ABI.Pack("nodesOffsetByNodeKeyAddress", addr)
    g.Require().NoError(err)
    res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)
    err = GovernanceABI.ABI.Unpack(&value, "nodesOffsetByNodeKeyAddress", res)
    g.Require().NoError(err)
    g.Require().Equal(0, int(value.Uint64()))

    input, err = GovernanceABI.ABI.Pack("fineValues", big.NewInt(0))
    g.Require().NoError(err)
    res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
    g.Require().NoError(err)
}

func (g *OracleContractsTestSuite) 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())
}

type testCoreMock struct {
    newDKGGPKError error
    tsigReturn     bool
}

func (m *testCoreMock) NewGroupPublicKey(*GovernanceState, *big.Int, int) (tsigVerifierIntf, error) {
    if m.newDKGGPKError != nil {
        return nil, m.newDKGGPKError
    }
    return &testTSigVerifierMock{m.tsigReturn}, nil
}

type testTSigVerifierMock struct {
    ret bool
}

func (v *testTSigVerifierMock) VerifySignature(coreCommon.Hash, coreCrypto.Signature) bool {
    return v.ret
}

func (g *OracleContractsTestSuite) TestResetDKG() {
    for i := uint32(0); i < g.config.DKGSetSize; i++ {
        privKey, addr := newPrefundAccount(g.stateDB)
        pk := crypto.FromECDSAPub(&privKey.PublicKey)

        // Stake.
        amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6))
        input, err := GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org")
        g.Require().NoError(err)
        _, err = g.call(GovernanceContractAddress, addr, input, amount)
        g.Require().NoError(err)
    }
    g.Require().Len(g.s.QualifiedNodes(), int(g.config.DKGSetSize))

    addrs := make(map[int][]common.Address)
    dkgSets := make(map[int]map[coreTypes.NodeID]struct{})
    addDKG := func(round int, final, proposeCRS bool) {
        if proposeCRS && uint64(round) > dexCore.DKGDelayRound {
            // ProposeCRS and clear DKG state.
            input, err := GovernanceABI.ABI.Pack(
                "proposeCRS", big.NewInt(int64(round)), randomBytes(32, 32))
            g.Require().NoError(err)
            _, err = g.call(GovernanceContractAddress, addrs[round-1][0], input, big.NewInt(0))
            g.Require().NoError(err)

            // Clear DKG states for next round.
            dkgSet := dkgSets[round-1]
            g.s.ClearDKGMasterPublicKeyProposed()
            g.s.ClearDKGMasterPublicKeys()
            g.s.ClearDKGComplaintProposed()
            g.s.ClearDKGComplaints()
            g.s.ClearDKGMPKReadys(dkgSet)
            g.s.ResetDKGMPKReadysCount()
            g.s.ClearDKGFinalizeds(dkgSet)
            g.s.ResetDKGFinalizedsCount()
            g.s.SetDKGRound(big.NewInt(int64(round)))
        }

        addrs[round] = []common.Address{}
        target := coreTypes.NewDKGSetTarget(coreCommon.Hash(g.s.CRS()))
        ns := coreTypes.NewNodeSet()

        for _, x := range g.s.QualifiedNodes() {
            mpk, err := coreEcdsa.NewPublicKeyFromByteSlice(x.PublicKey)
            if err != nil {
                panic(err)
            }
            ns.Add(coreTypes.NewNodeID(mpk))
        }
        dkgSet := ns.GetSubSet(int(g.s.DKGSetSize().Uint64()), target)
        g.Require().Len(dkgSet, int(g.config.DKGSetSize))
        dkgSets[round] = dkgSet

        for id := range dkgSet {
            offset := g.s.NodesOffsetByNodeKeyAddress(IdToAddress(id))
            if offset.Cmp(big.NewInt(0)) < 0 {
                panic("DKG node does not exist")
            }
            node := g.s.Node(offset)
            // Prepare MPK.
            x := dkgTypes.MasterPublicKey{}
            b, err := rlp.EncodeToBytes(&x)
            if err != nil {
                panic(err)
            }
            g.s.PushDKGMasterPublicKey(b)
            // Prepare Complaint.
            y := dkgTypes.Complaint{}
            b, err = rlp.EncodeToBytes(&y)
            if err != nil {
                panic(err)
            }
            g.s.PushDKGComplaint(b)
            addr := node.Owner
            addrs[round] = append(addrs[round], addr)
            // Prepare MPK Ready.
            g.s.PutDKGMPKReady(addr, true)
            g.s.IncDKGMPKReadysCount()
            if final {
                // Prepare Finalized.
                g.s.PutDKGFinalized(addr, true)
                g.s.IncDKGFinalizedsCount()
            }
        }
        dkgSetSize := len(dkgSet)
        g.Require().Len(g.s.DKGMasterPublicKeys(), dkgSetSize)
        g.Require().Len(g.s.DKGComplaints(), dkgSetSize)
        g.Require().Equal(int64(dkgSetSize), g.s.DKGMPKReadysCount().Int64())
        for _, addr := range addrs[round] {
            g.Require().True(g.s.DKGMPKReady(addr))
        }

        if final {
            g.Require().Equal(int64(dkgSetSize), g.s.DKGFinalizedsCount().Int64())
            for _, addr := range addrs[round] {
                g.Require().True(g.s.DKGFinalized(addr))
            }
        }

    }

    mock := &testCoreMock{
        tsigReturn: true,
    }
    OracleContracts[GovernanceContractAddress] = func() OracleContract {
        return &GovernanceContract{
            coreDKGUtils: mock,
        }
    }

    // Fill data for previous rounds.
    roundHeight := int64(g.config.RoundLength)
    round := int(dexCore.DKGDelayRound) + 3
    for i := 0; i <= round; i++ {
        g.context.Round = big.NewInt(int64(i))

        // Prepare Round Height
        if i != 0 {
            g.s.PushRoundHeight(big.NewInt(int64(i) * roundHeight))
        }

        addDKG(i+1, true, true)
    }

    round++
    g.s.PushRoundHeight(big.NewInt(int64(round) * roundHeight))
    g.context.Round = big.NewInt(int64(round))
    addDKG(round+1, false, true)
    repeat := 3
    for r := 0; r < repeat; r++ {
        // Add one finalized for test.
        roundPlusOne := big.NewInt(int64(round + 1))
        g.s.PutDKGFinalized(addrs[round+1][0], true)
        g.s.IncDKGFinalizedsCount()

        g.context.BlockNumber = big.NewInt(
            roundHeight*int64(round) + roundHeight*int64(r) + roundHeight*80/100)
        _, addr := newPrefundAccount(g.stateDB)
        newCRS := randomBytes(common.HashLength, common.HashLength)
        input, err := GovernanceABI.ABI.Pack("resetDKG", newCRS)
        g.Require().NoError(err)
        _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
        g.Require().NoError(err)

        // Test if CRS is reset.
        newCRSHash := crypto.Keccak256Hash(newCRS)
        g.Require().Equal(newCRSHash, g.s.CRS())

        // Test if MPK is purged.
        g.Require().Len(g.s.DKGMasterPublicKeys(), 0)
        // Test if MPKReady is purged.
        g.Require().Equal(int64(0), g.s.DKGMPKReadysCount().Int64())
        for _, addr := range addrs[round+1] {
            g.Require().False(g.s.DKGMPKReady(addr))
        }
        // Test if Complaint is purged.
        g.Require().Len(g.s.DKGComplaints(), 0)
        // Test if Finalized is purged.
        g.Require().Equal(int64(0), g.s.DKGFinalizedsCount().Int64())
        for _, addr := range addrs[round+1] {
            g.Require().False(g.s.DKGFinalized(addr))
        }

        g.Require().Equal(int64(r+1), g.s.DKGResetCount(roundPlusOne).Int64())

        addDKG(round+1, false, false)
    }
}

func TestOracleContracts(t *testing.T) {
    suite.Run(t, new(OracleContractsTestSuite))
}