aboutsummaryrefslogblamecommitdiffstats
path: root/core/vm/governance.go
blob: 2e07ba3eb6163f53e476bda0b9d25103fe295939 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
















                                                                               


          
                       




                                                        
                                                      
                                                  
                                                  



                                                                                 
                                                                            
                                                                               

 
                                                                                               





                                         




                         




                         






                            






                              
                            


                   
                         







                              


                         




                         





                              


























                              

                       


                   
                         







                              
               




                         






                         






                              



                       
                         



























                              













                              













                              



                        








                              


















                              





                               












                              
                         







                              









                         
                                  











                              






















                              
                 
                        











                              
                 











                               


















                                 






















                                   


                      













                                    

                            

        

                           

        

                            

        
                    
                         

        
                           




















                                   











                                    

















                                    
                            












                                    
                        


                         

















                                    
                            












                                    
                        


                         
                           


                       
                             








                                    
                            





















                                    
                                                       
                                    
                               








                                                              
                                                                   


                                                  
                                                        
                                                                   
         






                                                




                                                                        



                               






                                                       
                                                 
                              

                            








                                                                              
                                     
                                

                                          
                   
                                                                              

                                                        
                                                                          
                              
                                

                                         
                   
                                                                              

                                                        
                                                                  


































                                                                                   



                                           
 




                                                                               
                                                                   



                                                        





                                                                              
                                                          








                                                           





                                                                              
                                                              









                                                                               
                                                          




                                                        





                                                                              

                                                          

                                                        

                                                    



                                                        
                          
                                                                     




                                                        
                                                            




                                                        
                                                                   




                                                        
                                                                    




                                                        
                                                                           




                                                        
                                                                           




                                                        
                                                                    



                                                        




                                                                               

                                                                                        




                                                        
                                                                        








                                                                              
                                                                     



                                                        
                     
                                                                



                                                        
                        










                                                                               




                                                        
                                                                        



                                                        



                       

                          

                             





                              
                











                           
                                                         
                                   


                       
                                                                       
                                                                 

 
                                                                            
                                                               

 
                                                                       
                                                                                   


                                                 
                                                                            


                                                                
                                                                   


                                                                                     
                                                                              



                                                      
                                                                































                                                                                                      
                                                                       




                                                     



                                                      






























                                                                            
                                                                               













                                                                      
                                                                                       













                                                                           



















                                                                                             





                       
                

                      


                                

 
                                                        
                                                     
 
                                                                

                             
                                                          



                                                                                                
                                                                                                


                                                             
                                         


                                                             
                                           
 
                   
 
                                                       
                               
                                      
                                                                                            
 
                                    
 
                                                                         
                                                          



                                                                                                
                                                         


                                                             
                                      


                                                             







                                                                     
 
 
                                             
                                                                      
                                                               
                                                                     
 
                                                                                 
                                                               
                                                                      
 
                                                                   
                                                               
                                            

 
                        
                                                   
                                                   
 
                                                                 

                                                   
                                                
 


                                                                 
                                                          
                                

                                                                                     
 

                                                   
 
                                              
 


                                                                                    
 
                                        
                                                                              
                                                                           
 

                                                                                    

 
                                  
                                                                        
                                                                     
 
                                                                                    

                                                                             
 
                                                  
                                                                                        



                                                                                      
                                                                                                      







                                                                                      
 
                                       
                                                                             


                                                                                       
                                                                       


                                                                                       

 
                        
                                                        
                                                                 
                                                 
 


                                                                           
 
                            
                                                      
                                                         

 
                           
                                                     
                                                        
 
 
                            
                                                      
                                                         

 
                    
                                              
                                                 
 
 
                                                         
                                                     
                                                        

 
                                
                                                          
                                                             

 
                             
                                                       
                                                          

 
                                
                                                          
                                                             

 
                                   
                                                             
                                                                

 
                                   
                                                             
                                                                

 












                                                                                               













                                                                                                          














                                                                                                  
                                                                 
                                    
                                                   




                                                                            
                                                 
                                                                                  
                                    
                                                   




                                                                                            
                                                                   

                                
                                      


                          
                                                                              

                                   
                                                             



                                   



                                         




                                                                                  



                                                                        







                                                                          
                                                                                           
                                            



                                                


















                                                                                    
                                                                   


                                                


                                                           



                                                

                                                                      










                                                          
                                                                                                
                                            



                                                








                                                    
                                                                 


                                                


                                                                 



                                                

                                                                           



                                                
                                                  






                                                                                              
                                            



                                                


                                             
                                                                      


                                                


                                                          



                                                

                                                                    













                                                            
                                                                                               
                                               
                                                   


                                                
                                           
                                               



                                                                      
                                     
                                        

                                           

                                           


                                                




                                              
          
                                         

                                



                                                        
                                     
                                        
                                          


                                                

                                       



                                                            



                                                         


                                  
                                                                        
                                                                                     

                                


                       
                                                                           
                                
                                     
 

                                                      
                                                        
                                                                
                                                      
                                                              





                                                      
                                                   
                                                           
                                                
                                                               




                                                        
                                                             










                                                                         
                            




                                                      

                                         

                                                      
 


                                                                                  


                       


                                                                                         

                                                
                                  


                       

                                                                                    
 


                                              
                            


                                                
                                       
                                 

                       
// Copyright 2018 The dexon-consensus-core Authors
// This file is part of the dexon-consensus-core library.
//
// The dexon-consensus-core 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-core 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-core library. If not, see
// <http://www.gnu.org/licenses/>.

package vm

import (
    "encoding/json"
    "math/big"
    "strings"

    "github.com/dexon-foundation/dexon/accounts/abi"
    "github.com/dexon-foundation/dexon/common"
    "github.com/dexon-foundation/dexon/core/types"
    "github.com/dexon-foundation/dexon/crypto"
    "github.com/dexon-foundation/dexon/params"

    coreCommon "github.com/dexon-foundation/dexon-consensus-core/common"
    "github.com/dexon-foundation/dexon-consensus-core/core"
    coreCrypto "github.com/dexon-foundation/dexon-consensus-core/core/crypto"
    "github.com/dexon-foundation/dexon-consensus-core/core/crypto/ecdsa"
    coreTypes "github.com/dexon-foundation/dexon-consensus-core/core/types"
)

var GovernanceContractAddress = common.HexToAddress("5765692d4e696e6720536f6e696320426f6a6965")
var minStake = big.NewInt(10000000000000)

const abiJSON = `
[
  {
    "constant": true,
    "inputs": [
      {
        "name": "",
        "type": "uint256"
      },
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "dkgComplaints",
    "outputs": [
      {
        "name": "",
        "type": "bytes"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "notarySetSize",
    "outputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "dkgSetSize",
    "outputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "nodes",
    "outputs": [
      {
        "name": "owner",
        "type": "address"
      },
      {
        "name": "publicKey",
        "type": "bytes"
      },
      {
        "name": "staked",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "lambdaBA",
    "outputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "crs",
    "outputs": [
      {
        "name": "",
        "type": "bytes32"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "phiRatio",
    "outputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "",
        "type": "address"
      }
    ],
    "name": "offset",
    "outputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "roundInterval",
    "outputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "name": "",
        "type": "address"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "lambdaDKG",
    "outputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "roundHeight",
    "outputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "minBlockInterval",
    "outputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "k",
    "outputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "",
        "type": "uint256"
      },
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "dkgMasterPublicKeys",
    "outputs": [
      {
        "name": "",
        "type": "bytes"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "",
        "type": "uint256"
      },
      {
        "name": "",
        "type": "address"
      }
    ],
    "name": "dkgFinalizeds",
    "outputs": [
      {
        "name": "",
        "type": "bool"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "numChains",
    "outputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "maxBlockInterval",
    "outputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "dkgFinalizedsCount",
    "outputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "anonymous": false,
    "inputs": [],
    "name": "ConfigurationChanged",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "name": "round",
        "type": "uint256"
      },
      {
        "indexed": false,
        "name": "crs",
        "type": "bytes32"
      }
    ],
    "name": "CRSProposed",
    "type": "event"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "NumChains",
        "type": "uint256"
      },
      {
        "name": "LambdaBA",
        "type": "uint256"
      },
      {
        "name": "LambdaDKG",
        "type": "uint256"
      },
      {
        "name": "K",
        "type": "uint256"
      },
      {
        "name": "PhiRatio",
        "type": "uint256"
      },
      {
        "name": "NotarySetSize",
        "type": "uint256"
      },
      {
        "name": "DKGSetSize",
        "type": "uint256"
      },
      {
        "name": "RoundInterval",
        "type": "uint256"
      },
      {
        "name": "MinBlockInterval",
        "type": "uint256"
      },
      {
        "name": "MaxBlockInterval",
        "type": "uint256"
      }
    ],
    "name": "updateConfiguration",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "round",
        "type": "uint256"
      },
      {
        "name": "height",
        "type": "uint256"
      }
    ],
    "name": "snapshotRound",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "SignedCRS",
        "type": "bytes"
      }
    ],
    "name": "proposeCRS",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "Round",
        "type": "uint256"
      },
      {
        "name": "Complaint",
        "type": "bytes"
      }
    ],
    "name": "addDKGComplaint",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "Round",
        "type": "uint256"
      },
      {
        "name": "PublicKey",
        "type": "bytes"
      }
    ],
    "name": "addDKGMasterPublicKey",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "Round",
        "type": "uint256"
      },
      {
        "name": "Finalize",
        "type": "bytes"
      }
    ],
    "name": "addDKGFinalize",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "PublicKey",
        "type": "bytes"
      }
    ],
    "name": "stake",
    "outputs": [],
    "payable": true,
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [],
    "name": "unstake",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  }
]
`

var abiObject abi.ABI
var GovernanceContractName2Method map[string]abi.Method
var sig2Method map[string]abi.Method
var events map[string]abi.Event

func init() {
    // Parse governance contract ABI.
    abiObject, err := abi.JSON(strings.NewReader(abiJSON))
    if err != nil {
        panic(err)
    }

    sig2Method = make(map[string]abi.Method)
    GovernanceContractName2Method = make(map[string]abi.Method)

    // Construct dispatch table.
    for _, method := range abiObject.Methods {
        sig2Method[string(method.Id())] = method
        GovernanceContractName2Method[method.Name] = method
    }

    events = make(map[string]abi.Event)

    // Event cache.
    for _, event := range abiObject.Events {
        events[event.Name] = event
    }
}

// RunGovernanceContract executes governance contract.
func RunGovernanceContract(evm *EVM, input []byte, contract *Contract) (
    ret []byte, err error) {
    if len(input) < 4 {
        return nil, nil
    }

    // Parse input.
    method, exists := sig2Method[string(input[:4])]
    if !exists {
        return nil, errExecutionReverted
    }

    // Dispatch method call.
    g := newGovernanceContract(evm, contract)
    arguments := input[4:]

    switch method.Name {
    case "addDKGComplaint":
        args := struct {
            Round     *big.Int
            Complaint []byte
        }{}
        if err := method.Inputs.Unpack(&args, arguments); err != nil {
            return nil, errExecutionReverted
        }
        return g.addDKGComplaint(args.Round, args.Complaint)
    case "addDKGMasterPublicKey":
        args := struct {
            Round     *big.Int
            PublicKey []byte
        }{}
        if err := method.Inputs.Unpack(&args, arguments); err != nil {
            return nil, errExecutionReverted
        }
        return g.addDKGMasterPublicKey(args.Round, args.PublicKey)
    case "addDKGFinalize":
        args := struct {
            Round    *big.Int
            Finalize []byte
        }{}
        if err := method.Inputs.Unpack(&args, arguments); err != nil {
            return nil, errExecutionReverted
        }
        return g.addDKGFinalize(args.Round, args.Finalize)
    case "proposeCRS":
        var signedCRS []byte
        if err := method.Inputs.Unpack(&signedCRS, arguments); err != nil {
            return nil, errExecutionReverted
        }
        return g.proposeCRS(signedCRS)
    case "stake":
        var publicKey []byte
        if err := method.Inputs.Unpack(&publicKey, arguments); err != nil {
            return nil, errExecutionReverted
        }
        return g.stake(publicKey)
    case "snapshotRound":
        args := struct {
            Round  *big.Int
            Height *big.Int
        }{}
        if err := method.Inputs.Unpack(&args, arguments); err != nil {
            return nil, errExecutionReverted
        }
        return g.snapshotRound(args.Round, args.Height)
    case "transferOwnership":
        var newOwner common.Address
        if err := method.Inputs.Unpack(&newOwner, arguments); err != nil {
            return nil, errExecutionReverted
        }
        return g.transferOwnership(newOwner)
    case "unstake":
        return g.unstake()
    case "updateConfiguration":
        var cfg params.DexconConfig
        if err := method.Inputs.Unpack(&cfg, arguments); err != nil {
            return nil, errExecutionReverted
        }
        g.updateConfiguration(&cfg)

    // --------------------------------
    // Solidity auto generated methods.
    // --------------------------------

    case "crs":
        round := new(big.Int)
        if err := method.Inputs.Unpack(&round, arguments); err != nil {
            return nil, errExecutionReverted
        }
        res, err := method.Outputs.Pack(g.state.CRS(round))
        if err != nil {
            return nil, errExecutionReverted
        }
        return res, nil
    case "dkgComplaints":
        round, index := new(big.Int), new(big.Int)
        args := []interface{}{&round, &index}
        if err := method.Inputs.Unpack(&args, arguments); err != nil {
            return nil, errExecutionReverted
        }
        complaints := g.state.DKGComplaints(round)
        if int(index.Uint64()) >= len(complaints) {
            return nil, errExecutionReverted
        }
        complaint := complaints[index.Uint64()]
        res, err := method.Outputs.Pack(complaint)
        if err != nil {
            return nil, errExecutionReverted
        }
        return res, nil
    case "dkgFinalizeds":
        round, addr := new(big.Int), common.Address{}
        args := []interface{}{&round, &addr}
        if err := method.Inputs.Unpack(&args, arguments); err != nil {
            return nil, errExecutionReverted
        }
        finalized := g.state.DKGFinalized(round, addr)
        res, err := method.Outputs.Pack(finalized)
        if err != nil {
            return nil, errExecutionReverted
        }
        return res, nil
    case "dkgFinalizedsCount":
        round := new(big.Int)
        if err := method.Inputs.Unpack(&round, arguments); err != nil {
            return nil, errExecutionReverted
        }
        count := g.state.DKGFinalizedsCount(round)
        res, err := method.Outputs.Pack(count)
        if err != nil {
            return nil, errExecutionReverted
        }
        return res, nil
    case "dkgMasterPublicKeys":
        round, index := new(big.Int), new(big.Int)
        args := []interface{}{&round, &index}
        if err := method.Inputs.Unpack(&args, arguments); err != nil {
            return nil, errExecutionReverted
        }
        mpks := g.state.DKGMasterPublicKeys(round)
        if int(index.Uint64()) >= len(mpks) {
            return nil, errExecutionReverted
        }
        mpk := mpks[index.Uint64()]
        res, err := method.Outputs.Pack(mpk)
        if err != nil {
            return nil, errExecutionReverted
        }
        return res, nil
    case "dkgSetSize":
        res, err := method.Outputs.Pack(g.state.DKGSetSize())
        if err != nil {
            return nil, errExecutionReverted
        }
        return res, nil
    case "k":
        res, err := method.Outputs.Pack(g.state.K())
        if err != nil {
            return nil, errExecutionReverted
        }
        return res, nil
    case "lambdaBA":
        res, err := method.Outputs.Pack(g.state.LambdaBA())
        if err != nil {
            return nil, errExecutionReverted
        }
        return res, nil
    case "lambdaDKG":
        res, err := method.Outputs.Pack(g.state.LambdaDKG())
        if err != nil {
            return nil, errExecutionReverted
        }
        return res, nil
    case "maxBlockInterval":
        res, err := method.Outputs.Pack(g.state.MaxBlockInterval())
        if err != nil {
            return nil, errExecutionReverted
        }
        return res, nil
    case "minBlockInterval":
        res, err := method.Outputs.Pack(g.state.MinBlockInterval())
        if err != nil {
            return nil, errExecutionReverted
        }
        return res, nil
    case "numChains":
        res, err := method.Outputs.Pack(g.state.NumChains())
        if err != nil {
            return nil, errExecutionReverted
        }
        return res, nil
    case "nodes":
        index := new(big.Int)
        if err := method.Inputs.Unpack(&index, arguments); err != nil {
            return nil, errExecutionReverted
        }
        info := g.state.Node(index)
        res, err := method.Outputs.Pack(info.Owner, info.PublicKey, info.Staked)
        if err != nil {
            return nil, errExecutionReverted
        }
        return res, nil
    case "notarySetSize":
        res, err := method.Outputs.Pack(g.state.NotarySetSize())
        if err != nil {
            return nil, errExecutionReverted
        }
        return res, nil
    case "offset":
        addr := common.Address{}
        if err := method.Inputs.Unpack(&addr, arguments); err != nil {
            return nil, errExecutionReverted
        }
        res, err := method.Outputs.Pack(g.state.Offset(addr))
        if err != nil {
            return nil, errExecutionReverted
        }
        return res, nil
    case "owner":
        res, err := method.Outputs.Pack(g.state.Owner())
        if err != nil {
            return nil, errExecutionReverted
        }
        return res, nil
    case "phiRatio":
        res, err := method.Outputs.Pack(g.state.PhiRatio())
        if err != nil {
            return nil, errExecutionReverted
        }
        return res, nil
    case "RoundHeight":
        round := new(big.Int)
        if err := method.Inputs.Unpack(&round, arguments); err != nil {
            return nil, errExecutionReverted
        }
        res, err := method.Outputs.Pack(g.state.RoundHeight(round))
        if err != nil {
            return nil, errExecutionReverted
        }
        return res, nil
    case "roundInterval":
        res, err := method.Outputs.Pack(g.state.RoundInterval())
        if err != nil {
            return nil, errExecutionReverted
        }
        return res, nil
    }
    return nil, nil
}

// Storage position enums.
const (
    RoundHeightLoc = iota
    nodesLoc
    offsetLoc
    crsLoc
    dkgMasterPublicKeysLoc
    dkgComplaintsLoc
    dkgFinailizedLoc
    dkgFinalizedsCountLoc
    ownerLoc
    numChainsLoc
    lambdaBALoc
    lambdaDKGLoc
    kLoc
    phiRatioLoc
    notarySetSizeLoc
    dkgSetSizeLoc
    roundIntervalLoc
    minBlockIntervalLoc
    maxBlockIntervalLoc
)

// State manipulation helper fro the governance contract.
type GovernanceStateHelper struct {
    StateDB StateDB
}

func (s *GovernanceStateHelper) getState(loc common.Hash) common.Hash {
    return s.StateDB.GetState(GovernanceContractAddress, loc)
}

func (s *GovernanceStateHelper) setState(loc common.Hash, val common.Hash) {
    s.StateDB.SetState(GovernanceContractAddress, loc, val)
}

func (s *GovernanceStateHelper) getStateBigInt(loc *big.Int) *big.Int {
    res := s.StateDB.GetState(GovernanceContractAddress, common.BigToHash(loc))
    return new(big.Int).SetBytes(res.Bytes())
}

func (s *GovernanceStateHelper) setStateBigInt(loc *big.Int, val *big.Int) {
    s.setState(common.BigToHash(loc), common.BigToHash(val))
}

func (s *GovernanceStateHelper) getSlotLoc(loc *big.Int) *big.Int {
    return new(big.Int).SetBytes(crypto.Keccak256(common.BigToHash(loc).Bytes()))
}

func (s *GovernanceStateHelper) getMapLoc(pos *big.Int, key []byte) *big.Int {
    return new(big.Int).SetBytes(crypto.Keccak256(
        key, common.BigToHash(pos).Bytes()))
}

func (s *GovernanceStateHelper) readBytes(loc *big.Int) []byte {
    // length of the dynamic array (bytes).
    rawLength := s.getStateBigInt(loc)
    lengthByte := new(big.Int).Mod(rawLength, big.NewInt(256))

    // bytes length <= 31, lengthByte % 2 == 0
    // return the high 31 bytes.
    if new(big.Int).Mod(lengthByte, big.NewInt(2)).Cmp(big.NewInt(0)) == 0 {
        length := new(big.Int).Div(lengthByte, big.NewInt(2)).Uint64()
        return rawLength.Bytes()[:length]
    }

    // actual length = (rawLength - 1) / 2
    length := new(big.Int).Div(new(big.Int).Sub(rawLength, big.NewInt(1)), big.NewInt(2)).Uint64()

    // data address.
    dataLoc := s.getSlotLoc(loc)

    // read continiously for length bytes.
    carry := int64(0)
    if length%32 > 0 {
        carry = 1
    }
    chunks := int64(length/32) + carry
    var data []byte
    for i := int64(0); i < chunks; i++ {
        loc = new(big.Int).Add(dataLoc, big.NewInt(i))
        data = append(data, s.getState(common.BigToHash(loc)).Bytes()...)
    }
    data = data[:length]
    return data
}

func (s *GovernanceStateHelper) writeBytes(loc *big.Int, data []byte) {
    length := int64(len(data))

    // short bytes (length <= 31)
    if length < 32 {
        data2 := append([]byte(nil), data...)
        // Right pad with zeros
        for len(data2) < 31 {
            data2 = append(data2, byte(0))
        }
        data2 = append(data2, byte(length*2))
        s.setState(common.BigToHash(loc), common.BytesToHash(data2))
        return
    }

    // write 2 * length + 1
    storedLength := new(big.Int).Add(new(big.Int).Mul(
        big.NewInt(length), big.NewInt(2)), big.NewInt(1))
    s.setStateBigInt(loc, storedLength)
    // write data chunck.
    dataLoc := s.getSlotLoc(loc)
    carry := int64(0)
    if length%32 > 0 {
        carry = 1
    }
    chunks := length/32 + carry
    for i := int64(0); i < chunks; i++ {
        loc = new(big.Int).Add(dataLoc, big.NewInt(i))
        maxLoc := (i + 1) * 32
        if maxLoc > length {
            maxLoc = length
        }
        data2 := data[i*32 : maxLoc]
        // Right pad with zeros
        for len(data2) < 32 {
            data2 = append(data2, byte(0))
        }
        s.setState(common.BigToHash(loc), common.BytesToHash(data2))
    }
}

func (s *GovernanceStateHelper) read2DByteArray(pos, index *big.Int) [][]byte {
    baseLoc := s.getSlotLoc(pos)
    loc := new(big.Int).Add(baseLoc, index)

    arrayLength := s.getStateBigInt(loc)
    dataLoc := s.getSlotLoc(loc)

    data := [][]byte{}
    for i := int64(0); i < int64(arrayLength.Uint64()); i++ {
        elementLoc := new(big.Int).Add(dataLoc, big.NewInt(i))
        data = append(data, s.readBytes(elementLoc))
    }

    return data
}
func (s *GovernanceStateHelper) appendTo2DByteArray(pos, index *big.Int, data []byte) {
    // Find the loc of the last element.
    baseLoc := s.getSlotLoc(pos)
    loc := new(big.Int).Add(baseLoc, index)

    // increase length by 1.
    arrayLength := s.getStateBigInt(loc)
    s.setStateBigInt(loc, new(big.Int).Add(arrayLength, big.NewInt(1)))

    // write element.
    dataLoc := s.getSlotLoc(loc)
    elementLoc := new(big.Int).Add(dataLoc, arrayLength)
    s.writeBytes(elementLoc, data)
}

// uint256[] public RoundHeight;
func (s *GovernanceStateHelper) LenRoundHeight() *big.Int {
    return s.getStateBigInt(big.NewInt(RoundHeightLoc))
}
func (s *GovernanceStateHelper) RoundHeight(round *big.Int) *big.Int {
    baseLoc := s.getSlotLoc(big.NewInt(RoundHeightLoc))
    loc := new(big.Int).Add(baseLoc, round)
    return s.getStateBigInt(loc)
}
func (s *GovernanceStateHelper) PushRoundHeight(height *big.Int) {
    // increase length by 1.
    length := s.getStateBigInt(big.NewInt(RoundHeightLoc))
    s.setStateBigInt(big.NewInt(RoundHeightLoc), new(big.Int).Add(length, big.NewInt(1)))

    baseLoc := s.getSlotLoc(big.NewInt(RoundHeightLoc))
    loc := new(big.Int).Add(baseLoc, length)

    s.setStateBigInt(loc, height)
}

// struct Node {
//     address owner;
//     bytes publicKey;
//     uint256 staked;
// }
//
// Node[] nodes;

type nodeInfo struct {
    Owner     common.Address
    PublicKey []byte
    Staked    *big.Int
}

func (s *GovernanceStateHelper) NodesLength() *big.Int {
    return s.getStateBigInt(big.NewInt(nodesLoc))
}
func (s *GovernanceStateHelper) Node(index *big.Int) *nodeInfo {
    node := new(nodeInfo)

    arrayBaseLoc := s.getSlotLoc(big.NewInt(nodesLoc))
    elementBaseLoc := new(big.Int).Add(arrayBaseLoc, new(big.Int).Mul(index, big.NewInt(3)))

    // owner.
    loc := elementBaseLoc
    node.Owner = common.BytesToAddress(s.getState(common.BigToHash(elementBaseLoc)).Bytes())

    // publicKey.
    loc = new(big.Int).Add(elementBaseLoc, big.NewInt(1))
    node.PublicKey = s.readBytes(loc)

    // staked.
    loc = new(big.Int).Add(elementBaseLoc, big.NewInt(2))
    node.Staked = s.getStateBigInt(loc)

    return node
}
func (s *GovernanceStateHelper) PushNode(n *nodeInfo) {
    // increase length by 1
    arrayLength := s.NodesLength()
    s.setStateBigInt(big.NewInt(nodesLoc), new(big.Int).Add(arrayLength, big.NewInt(1)))

    s.UpdateNode(arrayLength, n)
}
func (s *GovernanceStateHelper) UpdateNode(index *big.Int, n *nodeInfo) {
    arrayBaseLoc := s.getSlotLoc(big.NewInt(nodesLoc))
    elementBaseLoc := new(big.Int).Add(arrayBaseLoc, new(big.Int).Mul(index, big.NewInt(3)))

    // owner.
    loc := elementBaseLoc
    s.setState(common.BigToHash(loc), n.Owner.Hash())

    // publicKey.
    loc = new(big.Int).Add(elementBaseLoc, big.NewInt(1))
    s.writeBytes(loc, n.PublicKey)

    // staked.
    loc = new(big.Int).Add(elementBaseLoc, big.NewInt(2))
    s.setStateBigInt(loc, n.Staked)
}
func (s *GovernanceStateHelper) Nodes() []*nodeInfo {
    var nodes []*nodeInfo
    for i := int64(0); i < int64(s.NodesLength().Uint64()); i++ {
        nodes = append(nodes, s.Node(big.NewInt(i)))
    }
    return nodes
}

// mapping(address => uint256) public offset;
func (s *GovernanceStateHelper) Offset(addr common.Address) *big.Int {
    loc := s.getMapLoc(big.NewInt(offsetLoc), addr.Bytes())
    return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1))
}
func (s *GovernanceStateHelper) PutOffset(addr common.Address, offset *big.Int) {
    loc := s.getMapLoc(big.NewInt(offsetLoc), addr.Bytes())
    s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1)))
}
func (s *GovernanceStateHelper) DeleteOffset(addr common.Address) {
    loc := s.getMapLoc(big.NewInt(offsetLoc), addr.Bytes())
    s.setStateBigInt(loc, big.NewInt(0))
}

// bytes32[] public crs;
func (s *GovernanceStateHelper) LenCRS() *big.Int {
    return s.getStateBigInt(big.NewInt(crsLoc))
}
func (s *GovernanceStateHelper) CRS(index *big.Int) common.Hash {
    baseLoc := s.getSlotLoc(big.NewInt(crsLoc))
    loc := new(big.Int).Add(baseLoc, index)
    return s.getState(common.BigToHash(loc))
}
func (s *GovernanceStateHelper) CurrentCRS() common.Hash {
    return s.CRS(new(big.Int).Sub(s.LenCRS(), big.NewInt(1)))
}
func (s *GovernanceStateHelper) PushCRS(crs common.Hash) {
    // increase length by 1.
    length := s.getStateBigInt(big.NewInt(crsLoc))
    s.setStateBigInt(big.NewInt(crsLoc), new(big.Int).Add(length, big.NewInt(1)))

    baseLoc := s.getSlotLoc(big.NewInt(crsLoc))
    loc := new(big.Int).Add(baseLoc, length)

    s.setState(common.BigToHash(loc), crs)
}
func (s *GovernanceStateHelper) Round() *big.Int {
    return new(big.Int).Sub(s.getStateBigInt(big.NewInt(crsLoc)), big.NewInt(1))
}

// bytes[][] public dkgMasterPublicKeys;
func (s *GovernanceStateHelper) DKGMasterPublicKeys(round *big.Int) [][]byte {
    return s.read2DByteArray(big.NewInt(dkgMasterPublicKeysLoc), round)
}
func (s *GovernanceStateHelper) PushDKGMasterPublicKey(round *big.Int, mpk []byte) {
    s.appendTo2DByteArray(big.NewInt(dkgMasterPublicKeysLoc), round, mpk)
}

// bytes[][] public dkgComplaints;
func (s *GovernanceStateHelper) DKGComplaints(round *big.Int) [][]byte {
    return s.read2DByteArray(big.NewInt(dkgComplaintsLoc), round)
}
func (s *GovernanceStateHelper) PushDKGComplaint(round *big.Int, complaint []byte) {
    s.appendTo2DByteArray(big.NewInt(dkgComplaintsLoc), round, complaint)
}

// mapping(address => bool)[] public dkgFinalized;
func (s *GovernanceStateHelper) DKGFinalized(round *big.Int, addr common.Address) bool {
    baseLoc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgFinailizedLoc)), round)
    mapLoc := s.getMapLoc(baseLoc, addr.Bytes())
    return s.getStateBigInt(mapLoc).Cmp(big.NewInt(0)) != 0
}
func (s *GovernanceStateHelper) PutDKGFinalized(round *big.Int, addr common.Address, finalized bool) {
    baseLoc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgFinailizedLoc)), round)
    mapLoc := s.getMapLoc(baseLoc, addr.Bytes())
    res := big.NewInt(0)
    if finalized {
        res = big.NewInt(1)
    }
    s.setStateBigInt(mapLoc, res)
}

// uint256[] public dkgFinalizedsCount;
func (s *GovernanceStateHelper) DKGFinalizedsCount(round *big.Int) *big.Int {
    loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgFinalizedsCountLoc)), round)
    return s.getStateBigInt(loc)
}
func (s *GovernanceStateHelper) IncDKGFinalizedsCount(round *big.Int) {
    loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgFinalizedsCountLoc)), round)
    count := s.getStateBigInt(loc)
    s.setStateBigInt(loc, new(big.Int).Add(count, big.NewInt(1)))
}

// address public owner;
func (s *GovernanceStateHelper) Owner() common.Address {
    val := s.getState(common.BigToHash(big.NewInt(ownerLoc)))
    return common.BytesToAddress(val.Bytes())
}
func (s *GovernanceStateHelper) SetOwner(newOwner common.Address) {
    s.setState(common.BigToHash(big.NewInt(ownerLoc)), newOwner.Hash())
}

// uint256 public numChains;
func (s *GovernanceStateHelper) NumChains() *big.Int {
    return s.getStateBigInt(big.NewInt(numChainsLoc))
}

// uint256 public lambdaBA;
func (s *GovernanceStateHelper) LambdaBA() *big.Int {
    return s.getStateBigInt(big.NewInt(lambdaBALoc))
}

// uint256 public lambdaDKG;
func (s *GovernanceStateHelper) LambdaDKG() *big.Int {
    return s.getStateBigInt(big.NewInt(lambdaDKGLoc))
}

// uint256 public k;
func (s *GovernanceStateHelper) K() *big.Int {
    return s.getStateBigInt(big.NewInt(kLoc))
}

// uint256 public phiRatio;  // stored as PhiRatio * 10^6
func (s *GovernanceStateHelper) PhiRatio() *big.Int {
    return s.getStateBigInt(big.NewInt(phiRatioLoc))
}

// uint256 public notarySetSize;
func (s *GovernanceStateHelper) NotarySetSize() *big.Int {
    return s.getStateBigInt(big.NewInt(notarySetSizeLoc))
}

// uint256 public dkgSetSize;
func (s *GovernanceStateHelper) DKGSetSize() *big.Int {
    return s.getStateBigInt(big.NewInt(dkgSetSizeLoc))
}

// uint256 public roundInterval;
func (s *GovernanceStateHelper) RoundInterval() *big.Int {
    return s.getStateBigInt(big.NewInt(roundIntervalLoc))
}

// uint256 public minBlockInterval;
func (s *GovernanceStateHelper) MinBlockInterval() *big.Int {
    return s.getStateBigInt(big.NewInt(minBlockIntervalLoc))
}

// uint256 public maxBlockInterval;
func (s *GovernanceStateHelper) MaxBlockInterval() *big.Int {
    return s.getStateBigInt(big.NewInt(maxBlockIntervalLoc))
}

// Stake is a helper function for creating genesis state.
func (s *GovernanceStateHelper) Stake(addr common.Address, publicKey []byte, staked *big.Int) {
    offset := s.NodesLength()
    s.PushNode(&nodeInfo{
        Owner:     addr,
        PublicKey: publicKey,
        Staked:    staked,
    })
    s.PutOffset(addr, offset)
}

// Configuration returns the current configuration.
func (s *GovernanceStateHelper) Configuration() *params.DexconConfig {
    return &params.DexconConfig{
        NumChains:        uint32(s.getStateBigInt(big.NewInt(numChainsLoc)).Uint64()),
        LambdaBA:         s.getStateBigInt(big.NewInt(lambdaBALoc)).Uint64(),
        LambdaDKG:        s.getStateBigInt(big.NewInt(lambdaDKGLoc)).Uint64(),
        K:                int(s.getStateBigInt(big.NewInt(kLoc)).Uint64()),
        PhiRatio:         float32(s.getStateBigInt(big.NewInt(phiRatioLoc)).Uint64()) / 1000000.0,
        NotarySetSize:    uint32(s.getStateBigInt(big.NewInt(notarySetSizeLoc)).Uint64()),
        DKGSetSize:       uint32(s.getStateBigInt(big.NewInt(dkgSetSizeLoc)).Uint64()),
        RoundInterval:    s.getStateBigInt(big.NewInt(roundIntervalLoc)).Uint64(),
        MinBlockInterval: s.getStateBigInt(big.NewInt(minBlockIntervalLoc)).Uint64(),
        MaxBlockInterval: s.getStateBigInt(big.NewInt(maxBlockIntervalLoc)).Uint64(),
    }
}

// UpdateConfiguration updates system configuration.
func (s *GovernanceStateHelper) UpdateConfiguration(cfg *params.DexconConfig) {
    s.setStateBigInt(big.NewInt(numChainsLoc), big.NewInt(int64(cfg.NumChains)))
    s.setStateBigInt(big.NewInt(lambdaBALoc), big.NewInt(int64(cfg.LambdaBA)))
    s.setStateBigInt(big.NewInt(lambdaDKGLoc), big.NewInt(int64(cfg.LambdaDKG)))
    s.setStateBigInt(big.NewInt(kLoc), big.NewInt(int64(cfg.K)))
    s.setStateBigInt(big.NewInt(phiRatioLoc), big.NewInt(int64(cfg.PhiRatio)))
    s.setStateBigInt(big.NewInt(notarySetSizeLoc), big.NewInt(int64(cfg.NotarySetSize)))
    s.setStateBigInt(big.NewInt(dkgSetSizeLoc), big.NewInt(int64(cfg.DKGSetSize)))
    s.setStateBigInt(big.NewInt(roundIntervalLoc), big.NewInt(int64(cfg.RoundInterval)))
    s.setStateBigInt(big.NewInt(minBlockIntervalLoc), big.NewInt(int64(cfg.MinBlockInterval)))
    s.setStateBigInt(big.NewInt(maxBlockIntervalLoc), big.NewInt(int64(cfg.MaxBlockInterval)))
}

// event ConfigurationChanged();
func (s *GovernanceStateHelper) emitConfigurationChangedEvent() {
    s.StateDB.AddLog(&types.Log{
        Address: GovernanceContractAddress,
        Topics:  []common.Hash{events["ConfigurationChanged"].Id()},
        Data:    []byte{},
    })
}

// event CRSProposed(uint256 round, bytes32 crs);
func (s *GovernanceStateHelper) emitCRSProposed(round *big.Int, crs common.Hash) {
    s.StateDB.AddLog(&types.Log{
        Address: GovernanceContractAddress,
        Topics:  []common.Hash{events["CRSProposed"].Id(), common.BigToHash(round)},
        Data:    crs.Bytes(),
    })
}

// GovernanceContract represents the governance contract of DEXCON.
type GovernanceContract struct {
    evm      *EVM
    state    GovernanceStateHelper
    contract *Contract
}

func newGovernanceContract(evm *EVM, contract *Contract) *GovernanceContract {
    return &GovernanceContract{
        evm:      evm,
        state:    GovernanceStateHelper{evm.StateDB},
        contract: contract,
    }
}

func (g *GovernanceContract) penalize() {
    g.contract.UseGas(g.contract.Gas)
}

func (g *GovernanceContract) inDKGSet(nodeID coreTypes.NodeID) bool {
    target := coreTypes.NewDKGSetTarget(coreCommon.Hash(g.state.CurrentCRS()))
    ns := coreTypes.NewNodeSet()

    for _, x := range g.state.Nodes() {
        mpk, err := ecdsa.NewPublicKeyFromByteSlice(x.PublicKey)
        if err != nil {
            panic(err)
        }
        ns.Add(coreTypes.NewNodeID(mpk))
    }

    dkgSet := ns.GetSubSet(int(g.state.DKGSetSize().Uint64()), target)
    _, ok := dkgSet[nodeID]
    return ok
}

func (g *GovernanceContract) addDKGComplaint(round *big.Int, comp []byte) ([]byte, error) {
    if round.Cmp(g.state.Round()) != 0 {
        g.penalize()
        return nil, errExecutionReverted
    }

    caller := g.contract.Caller()

    // Finalized caller is not allowed to propose complaint.
    if g.state.DKGFinalized(round, caller) {
        g.penalize()
        return nil, errExecutionReverted
    }

    // Calculate 2f
    threshold := new(big.Int).Mul(
        big.NewInt(2),
        new(big.Int).Div(g.state.DKGSetSize(), big.NewInt(3)))

    // If 2f + 1 of DKG set is finalized, one can not propose complaint anymore.
    if g.state.DKGFinalizedsCount(round).Cmp(threshold) > 0 {
        return nil, errExecutionReverted
    }

    var dkgComplaint coreTypes.DKGComplaint
    if err := json.Unmarshal(comp, &dkgComplaint); err != nil {
        g.penalize()
        return nil, errExecutionReverted
    }

    // DKGComplaint must belongs to someone in DKG set.
    if !g.inDKGSet(dkgComplaint.ProposerID) {
        g.penalize()
        return nil, errExecutionReverted
    }

    verified, _ := core.VerifyDKGComplaintSignature(&dkgComplaint)
    if !verified {
        g.penalize()
        return nil, errExecutionReverted
    }

    g.state.PushDKGComplaint(round, comp)

    // Set this to relatively high to prevent spamming
    g.contract.UseGas(10000000)
    return nil, nil
}

func (g *GovernanceContract) addDKGMasterPublicKey(round *big.Int, mpk []byte) ([]byte, error) {
    if round.Cmp(g.state.Round()) != 0 {
        g.penalize()
        return nil, errExecutionReverted
    }

    caller := g.contract.Caller()
    offset := g.state.Offset(caller)

    // Can not add dkg mpk if not staked.
    if offset.Cmp(big.NewInt(0)) < 0 {
        return nil, errExecutionReverted
    }

    var dkgMasterPK coreTypes.DKGMasterPublicKey
    if err := json.Unmarshal(mpk, &dkgMasterPK); err != nil {
        g.penalize()
        return nil, errExecutionReverted
    }

    // DKGMasterPublicKey must belongs to someone in DKG set.
    if !g.inDKGSet(dkgMasterPK.ProposerID) {
        g.penalize()
        return nil, errExecutionReverted
    }

    verified, _ := core.VerifyDKGMasterPublicKeySignature(&dkgMasterPK)
    if !verified {
        g.penalize()
        return nil, errExecutionReverted
    }

    g.state.PushDKGMasterPublicKey(round, mpk)

    // DKG operation is expensive.
    g.contract.UseGas(100000)
    return nil, nil
}

func (g *GovernanceContract) addDKGFinalize(round *big.Int, finalize []byte) ([]byte, error) {
    if round.Cmp(g.state.Round()) != 0 {
        g.penalize()
        return nil, errExecutionReverted
    }

    caller := g.contract.Caller()

    var dkgFinalize coreTypes.DKGFinalize
    if err := json.Unmarshal(finalize, &dkgFinalize); err != nil {
        g.penalize()
        return nil, errExecutionReverted
    }

    // DKGFInalize must belongs to someone in DKG set.
    if !g.inDKGSet(dkgFinalize.ProposerID) {
        g.penalize()
        return nil, errExecutionReverted
    }

    verified, _ := core.VerifyDKGFinalizeSignature(&dkgFinalize)
    if !verified {
        g.penalize()
        return nil, errExecutionReverted
    }

    if !g.state.DKGFinalized(round, caller) {
        g.state.PutDKGFinalized(round, caller, true)
        g.state.IncDKGFinalizedsCount(round)
    }

    // DKG operation is expensive.
    g.contract.UseGas(100000)
    return nil, nil
}

func (g *GovernanceContract) updateConfiguration(config *params.DexconConfig) ([]byte, error) {
    // Only owner can update configuration.
    if g.contract.Caller() != g.state.Owner() {
        return nil, errExecutionReverted
    }

    g.state.UpdateConfiguration(config)
    g.state.emitConfigurationChangedEvent()
    return nil, nil
}

func (g *GovernanceContract) stake(publicKey []byte) ([]byte, error) {
    caller := g.contract.Caller()
    offset := g.state.Offset(caller)

    // Can not stake if already staked.
    if offset.Cmp(big.NewInt(0)) >= 0 {
        g.penalize()
        return nil, errExecutionReverted
    }

    offset = g.state.NodesLength()
    g.state.PushNode(&nodeInfo{
        Owner:     caller,
        PublicKey: publicKey,
        Staked:    g.contract.Value(),
    })
    g.state.PutOffset(caller, offset)

    g.contract.UseGas(21000)
    return nil, nil
}

func (g *GovernanceContract) unstake() ([]byte, error) {
    caller := g.contract.Caller()
    offset := g.state.Offset(caller)
    if offset.Cmp(big.NewInt(0)) < 0 {
        return nil, errExecutionReverted
    }

    node := g.state.Node(offset)
    length := g.state.NodesLength()
    lastIndex := new(big.Int).Sub(length, big.NewInt(1))

    // Delete the node.
    if offset != lastIndex {
        lastNode := g.state.Node(lastIndex)
        g.state.UpdateNode(offset, lastNode)
        g.state.PutOffset(lastNode.Owner, offset)
        g.state.DeleteOffset(caller)
    }

    // Return the staked fund.
    // TODO(w): use OP_CALL so this show up is internal transaction.
    g.evm.Transfer(g.evm.StateDB, GovernanceContractAddress, caller, node.Staked)

    g.contract.UseGas(21000)
    return nil, nil
}

func (g *GovernanceContract) proposeCRS(signedCRS []byte) ([]byte, error) {
    round := g.state.Round()
    prevCRS := g.state.CRS(round)

    // Prepare DKGMasterPublicKeys.
    // TODO(w): make sure DKGMasterPKs are unique.
    var dkgMasterPKs []*coreTypes.DKGMasterPublicKey
    for _, mpk := range g.state.DKGMasterPublicKeys(round) {
        x := new(coreTypes.DKGMasterPublicKey)
        if err := json.Unmarshal(mpk, x); err != nil {
            panic(err)
        }
        dkgMasterPKs = append(dkgMasterPKs, x)
    }

    // Prepare DKGComplaints.
    var dkgComplaints []*coreTypes.DKGComplaint
    for _, comp := range g.state.DKGComplaints(round) {
        x := new(coreTypes.DKGComplaint)
        if err := json.Unmarshal(comp, x); err != nil {
            panic(err)
        }
        dkgComplaints = append(dkgComplaints, x)
    }

    threshold := int(g.state.DKGSetSize().Uint64()/3 + 1)

    dkgGPK, err := core.NewDKGGroupPublicKey(
        round.Uint64(), dkgMasterPKs, dkgComplaints, threshold)
    if err != nil {
        return nil, errExecutionReverted
    }
    signature := coreCrypto.Signature{
        Type:      "bls",
        Signature: signedCRS,
    }
    if !dkgGPK.VerifySignature(coreCommon.Hash(prevCRS), signature) {
        g.penalize()
        return nil, errExecutionReverted
    }

    // Save new CRS into state and increase round.
    newCRS := crypto.Keccak256(signedCRS)
    crs := common.BytesToHash(newCRS)

    g.state.PushCRS(crs)
    g.state.emitCRSProposed(g.state.LenCRS(), crs)

    // To encourage DKG set to propose the correct value, correctly submitting
    // this should cause nothing.
    g.contract.UseGas(0)
    return nil, nil
}

func (g *GovernanceContract) transferOwnership(newOwner common.Address) ([]byte, error) {
    // Only owner can update configuration.
    if g.contract.Caller() != g.state.Owner() {
        return nil, errExecutionReverted
    }
    g.state.SetOwner(newOwner)
    return nil, nil
}

func (g *GovernanceContract) snapshotRound(round, height *big.Int) ([]byte, error) {
    // TODO(w): validate if this mapping is correct.

    // Only allow updating the next round.
    nextRound := g.state.LenRoundHeight()
    if round.Cmp(nextRound) != 0 {
        g.penalize()
        return nil, errExecutionReverted
    }

    g.state.PushRoundHeight(height)
    g.contract.UseGas(100000)
    return nil, nil
}