aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm/evm
diff options
context:
space:
mode:
Diffstat (limited to 'core/vm/evm')
-rw-r--r--core/vm/evm/governance.go2198
-rw-r--r--core/vm/evm/governance_test.go1061
-rw-r--r--core/vm/evm/oracle.go89
-rw-r--r--core/vm/evm/oracle_contract_abi.go (renamed from core/vm/evm/governance_abi.go)492
-rw-r--r--core/vm/evm/oracle_contracts.go2885
-rw-r--r--core/vm/evm/oracle_contracts_test.go1203
6 files changed, 4467 insertions, 3461 deletions
diff --git a/core/vm/evm/governance.go b/core/vm/evm/governance.go
deleted file mode 100644
index 18e733342..000000000
--- a/core/vm/evm/governance.go
+++ /dev/null
@@ -1,2198 +0,0 @@
-// 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 evm
-
-import (
- "bytes"
- "errors"
- "math/big"
- "sort"
- "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"
- "github.com/dexon-foundation/dexon/rlp"
-
- coreCommon "github.com/dexon-foundation/dexon-consensus/common"
- "github.com/dexon-foundation/dexon-consensus/core"
- coreCrypto "github.com/dexon-foundation/dexon-consensus/core/crypto"
- coreUtils "github.com/dexon-foundation/dexon-consensus/core/utils"
- "github.com/dexon-foundation/dexon/core/vm"
-
- "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"
-)
-
-var GovernanceContractAddress = common.HexToAddress("63751838d6485578b23e8b051d40861ecc416794")
-
-var abiObject abi.ABI
-var GovernanceContractName2Method map[string]abi.Method
-var sig2Method map[string]abi.Method
-var events map[string]abi.Event
-
-type Bytes32 [32]byte
-
-type ReportType uint64
-
-const (
- ReportTypeInvalidDKG = iota
- ReportTypeForkVote
- ReportTypeForkBlock
-)
-
-func init() {
- var err error
-
- // Parse governance contract ABI.
- abiObject, err = abi.JSON(strings.NewReader(GovernanceABIJSON))
- 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 *vm.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 "addDKGMPKReady":
- args := struct {
- Round *big.Int
- MPKReady []byte
- }{}
- if err := method.Inputs.Unpack(&args, arguments); err != nil {
- return nil, errExecutionReverted
- }
- return g.addDKGMPKReady(args.Round, args.MPKReady)
- 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 "delegate":
- address := common.Address{}
- if err := method.Inputs.Unpack(&address, arguments); err != nil {
- return nil, errExecutionReverted
- }
- return g.delegate(address)
- case "delegatorsLength":
- address := common.Address{}
- if err := method.Inputs.Unpack(&address, arguments); err != nil {
- return nil, errExecutionReverted
- }
- res, err := method.Outputs.Pack(g.state.LenDelegators(address))
- if err != nil {
- return nil, errExecutionReverted
- }
- return res, nil
- case "nodesLength":
- res, err := method.Outputs.Pack(g.state.LenNodes())
- if err != nil {
- return nil, errExecutionReverted
- }
- return res, nil
- case "payFine":
- address := common.Address{}
- if err := method.Inputs.Unpack(&address, arguments); err != nil {
- return nil, errExecutionReverted
- }
- return g.payFine(address)
- case "proposeCRS":
- args := struct {
- Round *big.Int
- SignedCRS []byte
- }{}
- if err := method.Inputs.Unpack(&args, arguments); err != nil {
- return nil, errExecutionReverted
- }
- return g.proposeCRS(args.Round, args.SignedCRS)
- case "report":
- args := struct {
- Type *big.Int
- Arg1 []byte
- Arg2 []byte
- }{}
- if err := method.Inputs.Unpack(&args, arguments); err != nil {
- return nil, errExecutionReverted
- }
- return g.report(args.Type, args.Arg1, args.Arg2)
- case "stake":
- args := struct {
- PublicKey []byte
- Name string
- Email string
- Location string
- Url string
- }{}
- if err := method.Inputs.Unpack(&args, arguments); err != nil {
- return nil, errExecutionReverted
- }
- return g.stake(args.PublicKey, args.Name, args.Email, args.Location, args.Url)
- 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 "undelegate":
- address := common.Address{}
- if err := method.Inputs.Unpack(&address, arguments); err != nil {
- return nil, errExecutionReverted
- }
- return g.undelegate(address)
- case "unstake":
- return g.unstake()
- case "updateConfiguration":
- var cfg rawConfigStruct
- if err := method.Inputs.Unpack(&cfg, arguments); err != nil {
- return nil, errExecutionReverted
- }
- return g.updateConfiguration(&cfg)
- case "withdraw":
- address := common.Address{}
- if err := method.Inputs.Unpack(&address, arguments); err != nil {
- return nil, errExecutionReverted
- }
- return g.withdraw(address)
-
- // --------------------------------
- // Solidity auto generated methods.
- // --------------------------------
-
- case "blockGasLimit":
- res, err := method.Outputs.Pack(g.state.BlockGasLimit())
- if err != nil {
- return nil, errExecutionReverted
- }
- return res, nil
- 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 "delegators":
- nodeAddr, index := common.Address{}, new(big.Int)
- args := []interface{}{&nodeAddr, &index}
- if err := method.Inputs.Unpack(&args, arguments); err != nil {
- return nil, errExecutionReverted
- }
- delegator := g.state.Delegator(nodeAddr, index)
- res, err := method.Outputs.Pack(delegator.Owner, delegator.Value, delegator.UndelegatedAt)
- if err != nil {
- return nil, errExecutionReverted
- }
- return res, nil
- case "delegatorsOffset":
- nodeAddr, delegatorAddr := common.Address{}, common.Address{}
- args := []interface{}{&nodeAddr, &delegatorAddr}
- if err := method.Inputs.Unpack(&args, arguments); err != nil {
- return nil, errExecutionReverted
- }
- res, err := method.Outputs.Pack(g.state.DelegatorsOffset(nodeAddr, delegatorAddr))
- 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 "dkgReadys":
- round, addr := new(big.Int), common.Address{}
- args := []interface{}{&round, &addr}
- if err := method.Inputs.Unpack(&args, arguments); err != nil {
- return nil, errExecutionReverted
- }
- ready := g.state.DKGMPKReady(round, addr)
- res, err := method.Outputs.Pack(ready)
- if err != nil {
- return nil, errExecutionReverted
- }
- return res, nil
- case "dkgReadysCount":
- round := new(big.Int)
- if err := method.Inputs.Unpack(&round, arguments); err != nil {
- return nil, errExecutionReverted
- }
- count := g.state.DKGMPKReadysCount(round)
- res, err := method.Outputs.Pack(count)
- 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 "finedRecords":
- record := Bytes32{}
- if err := method.Inputs.Unpack(&record, arguments); err != nil {
- return nil, errExecutionReverted
- }
- value := g.state.FineRecords(record)
- res, err := method.Outputs.Pack(value)
- if err != nil {
- return nil, errExecutionReverted
- }
- return res, nil
- case "fineValues":
- index := new(big.Int)
- if err := method.Inputs.Unpack(&index, arguments); err != nil {
- return nil, errExecutionReverted
- }
- value := g.state.FineValue(index)
- res, err := method.Outputs.Pack(value)
- 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 "lastHalvedAmount":
- res, err := method.Outputs.Pack(g.state.LastHalvedAmount())
- if err != nil {
- return nil, errExecutionReverted
- }
- return res, nil
- case "lockupPeriod":
- res, err := method.Outputs.Pack(g.state.LockupPeriod())
- 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 "miningVelocity":
- res, err := method.Outputs.Pack(g.state.MiningVelocity())
- if err != nil {
- return nil, errExecutionReverted
- }
- return res, nil
- case "minStake":
- res, err := method.Outputs.Pack(g.state.MinStake())
- if err != nil {
- return nil, errExecutionReverted
- }
- return res, nil
- case "nextHalvingSupply":
- res, err := method.Outputs.Pack(g.state.NextHalvingSupply())
- 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, info.Fined,
- info.Name, info.Email, info.Location, info.Url)
- if err != nil {
- return nil, errExecutionReverted
- }
- return res, nil
- case "nodesOffsetByAddress":
- address := common.Address{}
- if err := method.Inputs.Unpack(&address, arguments); err != nil {
- return nil, errExecutionReverted
- }
- res, err := method.Outputs.Pack(g.state.NodesOffsetByAddress(address))
- if err != nil {
- return nil, errExecutionReverted
- }
- return res, nil
- case "nodesOffsetByID":
- var id Bytes32
- if err := method.Inputs.Unpack(&id, arguments); err != nil {
- return nil, errExecutionReverted
- }
- res, err := method.Outputs.Pack(g.state.NodesOffsetByID(id))
- 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 "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
- case "totalStaked":
- res, err := method.Outputs.Pack(g.state.TotalStaked())
- if err != nil {
- return nil, errExecutionReverted
- }
- return res, nil
- case "totalSupply":
- res, err := method.Outputs.Pack(g.state.TotalSupply())
- if err != nil {
- return nil, errExecutionReverted
- }
- return res, nil
- }
- return nil, errExecutionReverted
-}
-
-// Storage position enums.
-const (
- roundHeightLoc = iota
- totalSupplyLoc
- totalStakedLoc
- nodesLoc
- nodesOffsetByAddressLoc
- nodesOffsetByIDLoc
- delegatorsLoc
- delegatorsOffsetLoc
- crsLoc
- dkgMasterPublicKeysLoc
- dkgComplaintsLoc
- dkgReadyLoc
- dkgReadysCountLoc
- dkgFinalizedLoc
- dkgFinalizedsCountLoc
- ownerLoc
- minStakeLoc
- lockupPeriodLoc
- miningVelocityLoc
- nextHalvingSupplyLoc
- lastHalvedAmountLoc
- blockGasLimitLoc
- numChainsLoc
- lambdaBALoc
- lambdaDKGLoc
- kLoc
- phiRatioLoc
- notarySetSizeLoc
- dkgSetSizeLoc
- roundIntervalLoc
- minBlockIntervalLoc
- fineValuesLoc
- finedRecordsLoc
-)
-
-func publicKeyToNodeID(pkBytes []byte) (Bytes32, error) {
- pk, err := crypto.UnmarshalPubkey(pkBytes)
- if err != nil {
- return Bytes32{}, err
- }
- id := Bytes32(coreTypes.NewNodeID(ecdsa.NewPublicKeyFromECDSA(pk)).Hash)
- return id, nil
-}
-
-// State manipulation helper fro the governance contract.
-type GovernanceStateHelper struct {
- StateDB vm.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 continuously 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))
-
- if length == 0 {
- s.setState(common.BigToHash(loc), common.Hash{})
- return
- }
-
- // 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)
-}
-
-// uint256 public totalSupply;
-func (s *GovernanceStateHelper) TotalSupply() *big.Int {
- return s.getStateBigInt(big.NewInt(totalSupplyLoc))
-}
-func (s *GovernanceStateHelper) IncTotalSupply(amount *big.Int) {
- s.setStateBigInt(big.NewInt(totalSupplyLoc), new(big.Int).Add(s.TotalSupply(), amount))
-}
-func (s *GovernanceStateHelper) DecTotalSupply(amount *big.Int) {
- s.setStateBigInt(big.NewInt(totalSupplyLoc), new(big.Int).Sub(s.TotalSupply(), amount))
-}
-
-// uint256 public totalStaked;
-func (s *GovernanceStateHelper) TotalStaked() *big.Int {
- return s.getStateBigInt(big.NewInt(totalStakedLoc))
-}
-func (s *GovernanceStateHelper) IncTotalStaked(amount *big.Int) {
- s.setStateBigInt(big.NewInt(totalStakedLoc), new(big.Int).Add(s.TotalStaked(), amount))
-}
-func (s *GovernanceStateHelper) DecTotalStaked(amount *big.Int) {
- s.setStateBigInt(big.NewInt(totalStakedLoc), new(big.Int).Sub(s.TotalStaked(), amount))
-}
-
-// struct Node {
-// address owner;
-// bytes publicKey;
-// uint256 staked;
-// uint256 fined;
-// string name;
-// string email;
-// string location;
-// string url;
-// }
-//
-// Node[] nodes;
-
-type nodeInfo struct {
- Owner common.Address
- PublicKey []byte
- Staked *big.Int
- Fined *big.Int
- Name string
- Email string
- Location string
- Url string
-}
-
-const nodeStructSize = 8
-
-func (s *GovernanceStateHelper) LenNodes() *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(nodeStructSize)))
-
- // 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)
-
- // Fined.
- loc = new(big.Int).Add(elementBaseLoc, big.NewInt(3))
- node.Fined = s.getStateBigInt(loc)
-
- // Name.
- loc = new(big.Int).Add(elementBaseLoc, big.NewInt(4))
- node.Name = string(s.readBytes(loc))
-
- // Email.
- loc = new(big.Int).Add(elementBaseLoc, big.NewInt(5))
- node.Email = string(s.readBytes(loc))
-
- // Location.
- loc = new(big.Int).Add(elementBaseLoc, big.NewInt(6))
- node.Location = string(s.readBytes(loc))
-
- // Url.
- loc = new(big.Int).Add(elementBaseLoc, big.NewInt(7))
- node.Url = string(s.readBytes(loc))
-
- return node
-}
-func (s *GovernanceStateHelper) PushNode(n *nodeInfo) {
- // Increase length by 1.
- arrayLength := s.LenNodes()
- 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(nodeStructSize)))
-
- // 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)
-
- // Fined.
- loc = new(big.Int).Add(elementBaseLoc, big.NewInt(3))
- s.setStateBigInt(loc, n.Fined)
-
- // Name.
- loc = new(big.Int).Add(elementBaseLoc, big.NewInt(4))
- s.writeBytes(loc, []byte(n.Name))
-
- // Email.
- loc = new(big.Int).Add(elementBaseLoc, big.NewInt(5))
- s.writeBytes(loc, []byte(n.Email))
-
- // Location.
- loc = new(big.Int).Add(elementBaseLoc, big.NewInt(6))
- s.writeBytes(loc, []byte(n.Location))
-
- // Url.
- loc = new(big.Int).Add(elementBaseLoc, big.NewInt(7))
- s.writeBytes(loc, []byte(n.Url))
-}
-func (s *GovernanceStateHelper) PopLastNode() {
- // Decrease length by 1.
- arrayLength := s.LenNodes()
- newArrayLength := new(big.Int).Sub(arrayLength, big.NewInt(1))
- s.setStateBigInt(big.NewInt(nodesLoc), newArrayLength)
-
- s.UpdateNode(newArrayLength, &nodeInfo{
- Staked: big.NewInt(0),
- Fined: big.NewInt(0),
- })
-}
-func (s *GovernanceStateHelper) Nodes() []*nodeInfo {
- var nodes []*nodeInfo
- for i := int64(0); i < int64(s.LenNodes().Uint64()); i++ {
- nodes = append(nodes, s.Node(big.NewInt(i)))
- }
- return nodes
-}
-func (s *GovernanceStateHelper) QualifiedNodes() []*nodeInfo {
- var nodes []*nodeInfo
- for i := int64(0); i < int64(s.LenNodes().Uint64()); i++ {
- node := s.Node(big.NewInt(i))
- if new(big.Int).Sub(node.Staked, node.Fined).Cmp(s.MinStake()) >= 0 {
- nodes = append(nodes, node)
- }
- }
- return nodes
-}
-
-// mapping(address => uint256) public nodeOffsetByAddress;
-func (s *GovernanceStateHelper) NodesOffsetByAddress(addr common.Address) *big.Int {
- loc := s.getMapLoc(big.NewInt(nodesOffsetByAddressLoc), addr.Bytes())
- return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1))
-}
-func (s *GovernanceStateHelper) PutNodesOffsetByAddress(addr common.Address, offset *big.Int) {
- loc := s.getMapLoc(big.NewInt(nodesOffsetByAddressLoc), addr.Bytes())
- s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1)))
-}
-func (s *GovernanceStateHelper) DeleteNodesOffsetByAddress(addr common.Address) {
- loc := s.getMapLoc(big.NewInt(nodesOffsetByAddressLoc), addr.Bytes())
- s.setStateBigInt(loc, big.NewInt(0))
-}
-
-// mapping(address => uint256) public nodeOffsetByID;
-func (s *GovernanceStateHelper) NodesOffsetByID(id Bytes32) *big.Int {
- loc := s.getMapLoc(big.NewInt(nodesOffsetByIDLoc), id[:])
- return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1))
-}
-func (s *GovernanceStateHelper) PutNodesOffsetByID(id Bytes32, offset *big.Int) {
- loc := s.getMapLoc(big.NewInt(nodesOffsetByIDLoc), id[:])
- s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1)))
-}
-func (s *GovernanceStateHelper) DeleteNodesOffsetByID(id Bytes32) {
- loc := s.getMapLoc(big.NewInt(nodesOffsetByIDLoc), id[:])
- s.setStateBigInt(loc, big.NewInt(0))
-}
-
-func (s *GovernanceStateHelper) PutNodeOffsets(n *nodeInfo, offset *big.Int) error {
- id, err := publicKeyToNodeID(n.PublicKey)
- if err != nil {
- return err
- }
- s.PutNodesOffsetByID(id, offset)
- s.PutNodesOffsetByAddress(n.Owner, offset)
- return nil
-}
-
-// struct Delegator {
-// address node;
-// address owner;
-// uint256 value;
-// uint256 undelegated_at;
-// }
-
-type delegatorInfo struct {
- Owner common.Address
- Value *big.Int
- UndelegatedAt *big.Int
-}
-
-const delegatorStructSize = 3
-
-// mapping(address => Delegator[]) public delegators;
-func (s *GovernanceStateHelper) LenDelegators(nodeAddr common.Address) *big.Int {
- loc := s.getMapLoc(big.NewInt(delegatorsLoc), nodeAddr.Bytes())
- return s.getStateBigInt(loc)
-}
-func (s *GovernanceStateHelper) Delegator(nodeAddr common.Address, offset *big.Int) *delegatorInfo {
- delegator := new(delegatorInfo)
-
- loc := s.getMapLoc(big.NewInt(delegatorsLoc), nodeAddr.Bytes())
- arrayBaseLoc := s.getSlotLoc(loc)
- elementBaseLoc := new(big.Int).Add(arrayBaseLoc, new(big.Int).Mul(big.NewInt(delegatorStructSize), offset))
-
- // Owner.
- loc = elementBaseLoc
- delegator.Owner = common.BytesToAddress(s.getState(common.BigToHash(elementBaseLoc)).Bytes())
-
- // Value.
- loc = new(big.Int).Add(elementBaseLoc, big.NewInt(1))
- delegator.Value = s.getStateBigInt(loc)
-
- // UndelegatedAt.
- loc = new(big.Int).Add(elementBaseLoc, big.NewInt(2))
- delegator.UndelegatedAt = s.getStateBigInt(loc)
-
- return delegator
-}
-func (s *GovernanceStateHelper) PushDelegator(nodeAddr common.Address, delegator *delegatorInfo) {
- // Increase length by 1.
- arrayLength := s.LenDelegators(nodeAddr)
- loc := s.getMapLoc(big.NewInt(delegatorsLoc), nodeAddr.Bytes())
- s.setStateBigInt(loc, new(big.Int).Add(arrayLength, big.NewInt(1)))
-
- s.UpdateDelegator(nodeAddr, arrayLength, delegator)
-}
-func (s *GovernanceStateHelper) UpdateDelegator(nodeAddr common.Address, offset *big.Int, delegator *delegatorInfo) {
- loc := s.getMapLoc(big.NewInt(delegatorsLoc), nodeAddr.Bytes())
- arrayBaseLoc := s.getSlotLoc(loc)
- elementBaseLoc := new(big.Int).Add(arrayBaseLoc, new(big.Int).Mul(big.NewInt(delegatorStructSize), offset))
-
- // Owner.
- loc = elementBaseLoc
- s.setState(common.BigToHash(loc), delegator.Owner.Hash())
-
- // Value.
- loc = new(big.Int).Add(elementBaseLoc, big.NewInt(1))
- s.setStateBigInt(loc, delegator.Value)
-
- // UndelegatedAt.
- loc = new(big.Int).Add(elementBaseLoc, big.NewInt(2))
- s.setStateBigInt(loc, delegator.UndelegatedAt)
-}
-func (s *GovernanceStateHelper) PopLastDelegator(nodeAddr common.Address) {
- // Decrease length by 1.
- arrayLength := s.LenDelegators(nodeAddr)
- newArrayLength := new(big.Int).Sub(arrayLength, big.NewInt(1))
- loc := s.getMapLoc(big.NewInt(delegatorsLoc), nodeAddr.Bytes())
- s.setStateBigInt(loc, newArrayLength)
-
- s.UpdateDelegator(nodeAddr, newArrayLength, &delegatorInfo{
- Value: big.NewInt(0),
- UndelegatedAt: big.NewInt(0),
- })
-}
-
-// mapping(address => mapping(address => uint256)) delegatorsOffset;
-func (s *GovernanceStateHelper) DelegatorsOffset(nodeAddr, delegatorAddr common.Address) *big.Int {
- loc := s.getMapLoc(s.getMapLoc(big.NewInt(delegatorsOffsetLoc), nodeAddr.Bytes()), delegatorAddr.Bytes())
- return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1))
-}
-func (s *GovernanceStateHelper) PutDelegatorOffset(nodeAddr, delegatorAddr common.Address, offset *big.Int) {
- loc := s.getMapLoc(s.getMapLoc(big.NewInt(delegatorsOffsetLoc), nodeAddr.Bytes()), delegatorAddr.Bytes())
- s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1)))
-}
-func (s *GovernanceStateHelper) DeleteDelegatorsOffset(nodeAddr, delegatorAddr common.Address) {
- loc := s.getMapLoc(s.getMapLoc(big.NewInt(delegatorsOffsetLoc), nodeAddr.Bytes()), delegatorAddr.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)
-}
-func (s *GovernanceStateHelper) UniqueDKGMasterPublicKeys(round *big.Int) []*dkgTypes.MasterPublicKey {
- // Prepare DKGMasterPublicKeys.
- var dkgMasterPKs []*dkgTypes.MasterPublicKey
- existence := make(map[coreTypes.NodeID]struct{})
- for _, mpk := range s.DKGMasterPublicKeys(round) {
- x := new(dkgTypes.MasterPublicKey)
- if err := rlp.DecodeBytes(mpk, x); err != nil {
- panic(err)
- }
-
- // Only the first DKG MPK submission is valid.
- if _, exists := existence[x.ProposerID]; exists {
- continue
- }
- existence[x.ProposerID] = struct{}{}
- dkgMasterPKs = append(dkgMasterPKs, x)
- }
- return dkgMasterPKs
-}
-func (s *GovernanceStateHelper) GetDKGMasterPublicKeyByProposerID(
- round *big.Int, proposerID coreTypes.NodeID) (*dkgTypes.MasterPublicKey, error) {
-
- for _, mpk := range s.DKGMasterPublicKeys(round) {
- x := new(dkgTypes.MasterPublicKey)
- if err := rlp.DecodeBytes(mpk, x); err != nil {
- panic(err)
- }
- if x.ProposerID.Equal(proposerID) {
- return x, nil
- }
- }
- return nil, errors.New("not found")
-}
-
-// 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 dkgReady;
-func (s *GovernanceStateHelper) DKGMPKReady(round *big.Int, addr common.Address) bool {
- baseLoc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgReadyLoc)), round)
- mapLoc := s.getMapLoc(baseLoc, addr.Bytes())
- return s.getStateBigInt(mapLoc).Cmp(big.NewInt(0)) != 0
-}
-func (s *GovernanceStateHelper) PutDKGMPKReady(round *big.Int, addr common.Address, ready bool) {
- baseLoc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgReadyLoc)), round)
- mapLoc := s.getMapLoc(baseLoc, addr.Bytes())
- res := big.NewInt(0)
- if ready {
- res = big.NewInt(1)
- }
- s.setStateBigInt(mapLoc, res)
-}
-
-// uint256[] public dkgReadysCount;
-func (s *GovernanceStateHelper) DKGMPKReadysCount(round *big.Int) *big.Int {
- loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgReadysCountLoc)), round)
- return s.getStateBigInt(loc)
-}
-func (s *GovernanceStateHelper) IncDKGMPKReadysCount(round *big.Int) {
- loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgReadysCountLoc)), round)
- count := s.getStateBigInt(loc)
- s.setStateBigInt(loc, new(big.Int).Add(count, big.NewInt(1)))
-}
-
-// 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(dkgFinalizedLoc)), 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(dkgFinalizedLoc)), 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 minStake;
-func (s *GovernanceStateHelper) MinStake() *big.Int {
- return s.getStateBigInt(big.NewInt(minStakeLoc))
-}
-
-// uint256 public lockupPeriod;
-func (s *GovernanceStateHelper) LockupPeriod() *big.Int {
- return s.getStateBigInt(big.NewInt(lockupPeriodLoc))
-}
-
-// uint256 public miningVelocity;
-func (s *GovernanceStateHelper) MiningVelocity() *big.Int {
- return s.getStateBigInt(big.NewInt(miningVelocityLoc))
-}
-func (s *GovernanceStateHelper) HalfMiningVelocity() {
- s.setStateBigInt(big.NewInt(miningVelocityLoc),
- new(big.Int).Div(s.MiningVelocity(), big.NewInt(2)))
-}
-
-// uint256 public nextHalvingSupply;
-func (s *GovernanceStateHelper) NextHalvingSupply() *big.Int {
- return s.getStateBigInt(big.NewInt(nextHalvingSupplyLoc))
-}
-func (s *GovernanceStateHelper) IncNextHalvingSupply(amount *big.Int) {
- s.setStateBigInt(big.NewInt(nextHalvingSupplyLoc),
- new(big.Int).Add(s.NextHalvingSupply(), amount))
-}
-
-// uint256 public lastHalvedAmount;
-func (s *GovernanceStateHelper) LastHalvedAmount() *big.Int {
- return s.getStateBigInt(big.NewInt(lastHalvedAmountLoc))
-}
-func (s *GovernanceStateHelper) HalfLastHalvedAmount() {
- s.setStateBigInt(big.NewInt(lastHalvedAmountLoc),
- new(big.Int).Div(s.LastHalvedAmount(), big.NewInt(2)))
-}
-
-func (s *GovernanceStateHelper) MiningHalved() {
- s.HalfMiningVelocity()
- s.HalfLastHalvedAmount()
- s.IncNextHalvingSupply(s.LastHalvedAmount())
-}
-
-// uint256 public blockGasLimit;
-func (s *GovernanceStateHelper) BlockGasLimit() *big.Int {
- return s.getStateBigInt(big.NewInt(blockGasLimitLoc))
-}
-func (s *GovernanceStateHelper) SetBlockGasLimit(reward *big.Int) {
- s.setStateBigInt(big.NewInt(blockGasLimitLoc), reward)
-}
-
-// 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 fineValues;
-func (s *GovernanceStateHelper) FineValue(index *big.Int) *big.Int {
- arrayBaseLoc := s.getSlotLoc(big.NewInt(fineValuesLoc))
- return s.getStateBigInt(new(big.Int).Add(arrayBaseLoc, index))
-}
-func (s *GovernanceStateHelper) FineValues() []*big.Int {
- len := s.getStateBigInt(big.NewInt(fineValuesLoc))
- result := make([]*big.Int, len.Uint64())
- for i := 0; i < int(len.Uint64()); i++ {
- result[i] = s.FineValue(big.NewInt(int64(i)))
- }
- return result
-}
-func (s *GovernanceStateHelper) SetFineValues(values []*big.Int) {
- s.setStateBigInt(big.NewInt(fineValuesLoc), big.NewInt(int64(len(values))))
-
- arrayBaseLoc := s.getSlotLoc(big.NewInt(fineValuesLoc))
- for i, v := range values {
- s.setStateBigInt(new(big.Int).Add(arrayBaseLoc, big.NewInt(int64(i))), v)
- }
-}
-
-// uint256[] public fineRdecords;
-func (s *GovernanceStateHelper) FineRecords(recordHash Bytes32) bool {
- loc := s.getMapLoc(big.NewInt(finedRecordsLoc), recordHash[:])
- return s.getStateBigInt(loc).Cmp(big.NewInt(0)) > 0
-}
-func (s *GovernanceStateHelper) SetFineRecords(recordHash Bytes32, status bool) {
- loc := s.getMapLoc(big.NewInt(finedRecordsLoc), recordHash[:])
- value := int64(0)
- if status {
- value = int64(1)
- }
- s.setStateBigInt(loc, big.NewInt(value))
-}
-
-// Stake is a helper function for creating genesis state.
-func (s *GovernanceStateHelper) Stake(
- addr common.Address, publicKey []byte, staked *big.Int,
- name, email, location, url string) {
- offset := s.LenNodes()
- node := &nodeInfo{
- Owner: addr,
- PublicKey: publicKey,
- Staked: staked,
- Fined: big.NewInt(0),
- Name: name,
- Email: email,
- Location: location,
- Url: url,
- }
- s.PushNode(node)
- if err := s.PutNodeOffsets(node, offset); err != nil {
- panic(err)
- }
-
- if staked.Cmp(big.NewInt(0)) == 0 {
- return
- }
-
- offset = s.LenDelegators(addr)
- s.PushDelegator(addr, &delegatorInfo{
- Owner: addr,
- Value: staked,
- UndelegatedAt: big.NewInt(0),
- })
- s.PutDelegatorOffset(addr, addr, offset)
-
- // Add to network total staked.
- s.IncTotalStaked(staked)
-}
-
-const decimalMultiplier = 100000000.0
-
-// Configuration returns the current configuration.
-func (s *GovernanceStateHelper) Configuration() *params.DexconConfig {
- return &params.DexconConfig{
- MinStake: s.getStateBigInt(big.NewInt(minStakeLoc)),
- LockupPeriod: s.getStateBigInt(big.NewInt(lockupPeriodLoc)).Uint64(),
- MiningVelocity: float32(s.getStateBigInt(big.NewInt(miningVelocityLoc)).Uint64()) / decimalMultiplier,
- NextHalvingSupply: s.getStateBigInt(big.NewInt(nextHalvingSupplyLoc)),
- LastHalvedAmount: s.getStateBigInt(big.NewInt(lastHalvedAmountLoc)),
- BlockGasLimit: s.getStateBigInt(big.NewInt(blockGasLimitLoc)).Uint64(),
- NumChains: uint32(s.getStateBigInt(big.NewInt(numChainsLoc)).Uint64()),
- LambdaBA: s.getStateBigInt(big.NewInt(lambdaBALoc)).Uint64(),
- LambdaDKG: s.getStateBigInt(big.NewInt(lambdaDKGLoc)).Uint64(),
- K: uint32(s.getStateBigInt(big.NewInt(kLoc)).Uint64()),
- PhiRatio: float32(s.getStateBigInt(big.NewInt(phiRatioLoc)).Uint64()) / decimalMultiplier,
- 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(),
- FineValues: s.FineValues(),
- }
-}
-
-// UpdateConfiguration updates system configuration.
-func (s *GovernanceStateHelper) UpdateConfiguration(cfg *params.DexconConfig) {
- s.setStateBigInt(big.NewInt(minStakeLoc), cfg.MinStake)
- s.setStateBigInt(big.NewInt(lockupPeriodLoc), big.NewInt(int64(cfg.LockupPeriod)))
- s.setStateBigInt(big.NewInt(miningVelocityLoc), big.NewInt(int64(cfg.MiningVelocity*decimalMultiplier)))
- s.setStateBigInt(big.NewInt(nextHalvingSupplyLoc), cfg.NextHalvingSupply)
- s.setStateBigInt(big.NewInt(lastHalvedAmountLoc), cfg.LastHalvedAmount)
- s.setStateBigInt(big.NewInt(blockGasLimitLoc), big.NewInt(int64(cfg.BlockGasLimit)))
- 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*decimalMultiplier)))
- 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.SetFineValues(cfg.FineValues)
-}
-
-type rawConfigStruct struct {
- MinStake *big.Int
- LockupPeriod *big.Int
- MiningVelocity *big.Int
- BlockGasLimit *big.Int
- NumChains *big.Int
- LambdaBA *big.Int
- LambdaDKG *big.Int
- K *big.Int
- PhiRatio *big.Int
- NotarySetSize *big.Int
- DKGSetSize *big.Int
- RoundInterval *big.Int
- MinBlockInterval *big.Int
- FineValues []*big.Int
-}
-
-// UpdateConfigurationRaw updates system configuration.
-func (s *GovernanceStateHelper) UpdateConfigurationRaw(cfg *rawConfigStruct) {
- s.setStateBigInt(big.NewInt(minStakeLoc), cfg.MinStake)
- s.setStateBigInt(big.NewInt(lockupPeriodLoc), cfg.LockupPeriod)
- s.setStateBigInt(big.NewInt(miningVelocityLoc), cfg.MiningVelocity)
- s.setStateBigInt(big.NewInt(blockGasLimitLoc), cfg.BlockGasLimit)
- s.setStateBigInt(big.NewInt(numChainsLoc), cfg.NumChains)
- s.setStateBigInt(big.NewInt(lambdaBALoc), cfg.LambdaBA)
- s.setStateBigInt(big.NewInt(lambdaDKGLoc), cfg.LambdaDKG)
- s.setStateBigInt(big.NewInt(kLoc), cfg.K)
- s.setStateBigInt(big.NewInt(phiRatioLoc), cfg.PhiRatio)
- s.setStateBigInt(big.NewInt(notarySetSizeLoc), cfg.NotarySetSize)
- s.setStateBigInt(big.NewInt(dkgSetSizeLoc), cfg.DKGSetSize)
- s.setStateBigInt(big.NewInt(roundIntervalLoc), cfg.RoundInterval)
- s.setStateBigInt(big.NewInt(minBlockIntervalLoc), cfg.MinBlockInterval)
- s.SetFineValues(cfg.FineValues)
-}
-
-// 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(),
- })
-}
-
-// event Staked(address indexed NodeAddress, uint256 Amount);
-func (s *GovernanceStateHelper) emitStaked(nodeAddr common.Address) {
- s.StateDB.AddLog(&types.Log{
- Address: GovernanceContractAddress,
- Topics: []common.Hash{events["Staked"].Id(), nodeAddr.Hash()},
- Data: []byte{},
- })
-}
-
-// event Unstaked(address indexed NodeAddress);
-func (s *GovernanceStateHelper) emitUnstaked(nodeAddr common.Address) {
- s.StateDB.AddLog(&types.Log{
- Address: GovernanceContractAddress,
- Topics: []common.Hash{events["Unstaked"].Id(), nodeAddr.Hash()},
- Data: []byte{},
- })
-}
-
-// event Delegated(address indexed NodeAddress, address indexed DelegatorAddress, uint256 Amount);
-func (s *GovernanceStateHelper) emitDelegated(nodeAddr, delegatorAddr common.Address, amount *big.Int) {
- s.StateDB.AddLog(&types.Log{
- Address: GovernanceContractAddress,
- Topics: []common.Hash{events["Delegated"].Id(), nodeAddr.Hash(), delegatorAddr.Hash()},
- Data: common.BigToHash(amount).Bytes(),
- })
-}
-
-// event Undelegated(address indexed NodeAddress, address indexed DelegatorAddress);
-func (s *GovernanceStateHelper) emitUndelegated(nodeAddr, delegatorAddr common.Address) {
- s.StateDB.AddLog(&types.Log{
- Address: GovernanceContractAddress,
- Topics: []common.Hash{events["Undelegated"].Id(), nodeAddr.Hash(), delegatorAddr.Hash()},
- Data: []byte{},
- })
-}
-
-// event Withdrawn(address indexed NodeAddress, uint256 Amount);
-func (s *GovernanceStateHelper) emitWithdrawn(nodeAddr common.Address, amount *big.Int) {
- s.StateDB.AddLog(&types.Log{
- Address: GovernanceContractAddress,
- Topics: []common.Hash{events["Withdrawn"].Id(), nodeAddr.Hash()},
- Data: common.BigToHash(amount).Bytes(),
- })
-}
-
-// event ForkReported(address indexed NodeAddress, address indexed Type, bytes Arg1, bytes Arg2);
-func (s *GovernanceStateHelper) emitForkReported(nodeAddr common.Address, reportType *big.Int, arg1, arg2 []byte) {
-
- t, err := abi.NewType("bytes")
- if err != nil {
- panic(err)
- }
-
- arg := abi.Arguments{
- abi.Argument{
- Name: "Arg1",
- Type: t,
- Indexed: false,
- },
- abi.Argument{
- Name: "Arg2",
- Type: t,
- Indexed: false,
- },
- }
-
- data, err := arg.Pack(arg1, arg2)
- if err != nil {
- panic(err)
- }
- s.StateDB.AddLog(&types.Log{
- Address: GovernanceContractAddress,
- Topics: []common.Hash{events["ForkReported"].Id(), nodeAddr.Hash()},
- Data: data,
- })
-}
-
-// event Fined(address indexed NodeAddress, uint256 Amount);
-func (s *GovernanceStateHelper) emitFined(nodeAddr common.Address, amount *big.Int) {
- s.StateDB.AddLog(&types.Log{
- Address: GovernanceContractAddress,
- Topics: []common.Hash{events["Fined"].Id(), nodeAddr.Hash()},
- Data: common.BigToHash(amount).Bytes(),
- })
-}
-
-// event FinePaid(address indexed NodeAddress, uint256 Amount);
-func (s *GovernanceStateHelper) emitFinePaid(nodeAddr common.Address, amount *big.Int) {
- s.StateDB.AddLog(&types.Log{
- Address: GovernanceContractAddress,
- Topics: []common.Hash{events["FinePaid"].Id(), nodeAddr.Hash()},
- Data: common.BigToHash(amount).Bytes(),
- })
-}
-
-// GovernanceContract represents the governance contract of DEXCON.
-type GovernanceContract struct {
- evm *EVM
- state GovernanceStateHelper
- contract *vm.Contract
-}
-
-func newGovernanceContract(evm *EVM, contract *vm.Contract) *GovernanceContract {
- return &GovernanceContract{
- evm: evm,
- state: GovernanceStateHelper{evm.StateDB},
- contract: contract,
- }
-}
-
-func (g *GovernanceContract) Address() common.Address {
- return GovernanceContractAddress
-}
-
-func (g *GovernanceContract) transfer(from, to common.Address, amount *big.Int) bool {
- // TODO(w): add this to debug trace so it shows up as internal transaction.
- if g.evm.CanTransfer(g.evm.StateDB, from, amount) {
- g.evm.Transfer(g.evm.StateDB, from, to, amount)
- return true
- }
- return false
-}
-
-func (g *GovernanceContract) useGas(gas uint64) ([]byte, error) {
- if !g.contract.UseGas(gas) {
- return nil, vm.ErrOutOfGas
- }
- return nil, nil
-}
-
-func (g *GovernanceContract) penalize() ([]byte, error) {
- g.useGas(g.contract.Gas)
- return nil, errExecutionReverted
-}
-
-func (g *GovernanceContract) inDKGSet(round *big.Int, nodeID coreTypes.NodeID) bool {
- target := coreTypes.NewDKGSetTarget(coreCommon.Hash(g.state.CurrentCRS()))
- ns := coreTypes.NewNodeSet()
-
- configRound := big.NewInt(0) // If round < core.ConfigRoundShift, use 0.
- if round.Uint64() >= core.ConfigRoundShift {
- configRound = new(big.Int).Sub(round, big.NewInt(int64(core.ConfigRoundShift)))
- }
-
- statedb, err := g.evm.StateAtNumber(g.state.RoundHeight(configRound).Uint64())
- if err != nil {
- panic(err)
- }
-
- state := GovernanceStateHelper{statedb}
- for _, x := range state.QualifiedNodes() {
- 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 {
- return g.penalize()
- }
-
- caller := g.contract.Caller()
-
- // Finalized caller is not allowed to propose complaint.
- if g.state.DKGFinalized(round, caller) {
- return g.penalize()
- }
-
- // 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 dkgTypes.Complaint
- if err := rlp.DecodeBytes(comp, &dkgComplaint); err != nil {
- return g.penalize()
- }
-
- // DKGComplaint must belongs to someone in DKG set.
- if !g.inDKGSet(round, dkgComplaint.ProposerID) {
- return g.penalize()
- }
-
- verified, _ := coreUtils.VerifyDKGComplaintSignature(&dkgComplaint)
- if !verified {
- return g.penalize()
- }
-
- mpk, err := g.state.GetDKGMasterPublicKeyByProposerID(
- round, dkgComplaint.PrivateShare.ProposerID)
- if err != nil {
- return g.penalize()
- }
-
- // Verify DKG complaint is correct.
- ok, err := coreUtils.VerifyDKGComplaint(&dkgComplaint, mpk)
- if !ok || err != nil {
- return g.penalize()
- }
-
- // Fine the attacker.
- need, err := coreUtils.NeedPenaltyDKGPrivateShare(&dkgComplaint, mpk)
- if err != nil {
- return g.penalize()
- }
- if need {
- fineValue := g.state.FineValue(big.NewInt(ReportTypeInvalidDKG))
- offset := g.state.NodesOffsetByID(Bytes32(dkgComplaint.PrivateShare.ProposerID.Hash))
- node := g.state.Node(offset)
- if err := g.fine(node.Owner, fineValue, comp, nil); err != nil {
- return g.penalize()
- }
- }
-
- g.state.PushDKGComplaint(round, comp)
-
- // Set this to relatively high to prevent spamming
- return g.useGas(5000000)
-}
-
-func (g *GovernanceContract) addDKGMasterPublicKey(round *big.Int, mpk []byte) ([]byte, error) {
- // Can only add DKG master public key of current and next round.
- if round.Cmp(new(big.Int).Add(g.state.Round(), big.NewInt(1))) > 0 {
- return g.penalize()
- }
-
- caller := g.contract.Caller()
- offset := g.state.NodesOffsetByAddress(caller)
-
- // Can not add dkg mpk if not staked.
- if offset.Cmp(big.NewInt(0)) < 0 {
- return nil, errExecutionReverted
- }
-
- // MPKReady caller is not allowed to propose mpk.
- if g.state.DKGMPKReady(round, caller) {
- return g.penalize()
- }
-
- // 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 mpk ready, one can not propose mpk anymore.
- if g.state.DKGMPKReadysCount(round).Cmp(threshold) > 0 {
- return nil, errExecutionReverted
- }
-
- var dkgMasterPK dkgTypes.MasterPublicKey
- if err := rlp.DecodeBytes(mpk, &dkgMasterPK); err != nil {
- return g.penalize()
- }
-
- // DKGMasterPublicKey must belongs to someone in DKG set.
- if !g.inDKGSet(round, dkgMasterPK.ProposerID) {
- return g.penalize()
- }
-
- verified, _ := coreUtils.VerifyDKGMasterPublicKeySignature(&dkgMasterPK)
- if !verified {
- return g.penalize()
- }
-
- g.state.PushDKGMasterPublicKey(round, mpk)
-
- return g.useGas(100000)
-}
-
-func (g *GovernanceContract) addDKGMPKReady(round *big.Int, ready []byte) ([]byte, error) {
- if round.Cmp(g.state.Round()) != 0 {
- return g.penalize()
- }
-
- caller := g.contract.Caller()
-
- var dkgReady dkgTypes.MPKReady
- if err := rlp.DecodeBytes(ready, &dkgReady); err != nil {
- return g.penalize()
- }
-
- // DKGFInalize must belongs to someone in DKG set.
- if !g.inDKGSet(round, dkgReady.ProposerID) {
- return g.penalize()
- }
-
- verified, _ := coreUtils.VerifyDKGMPKReadySignature(&dkgReady)
- if !verified {
- return g.penalize()
- }
-
- if !g.state.DKGMPKReady(round, caller) {
- g.state.PutDKGMPKReady(round, caller, true)
- g.state.IncDKGMPKReadysCount(round)
- }
-
- return g.useGas(100000)
-}
-func (g *GovernanceContract) addDKGFinalize(round *big.Int, finalize []byte) ([]byte, error) {
- if round.Cmp(g.state.Round()) != 0 {
- return g.penalize()
- }
-
- caller := g.contract.Caller()
-
- var dkgFinalize dkgTypes.Finalize
- if err := rlp.DecodeBytes(finalize, &dkgFinalize); err != nil {
- return g.penalize()
- }
-
- // DKGFInalize must belongs to someone in DKG set.
- if !g.inDKGSet(round, dkgFinalize.ProposerID) {
- return g.penalize()
- }
-
- verified, _ := coreUtils.VerifyDKGFinalizeSignature(&dkgFinalize)
- if !verified {
- return g.penalize()
- }
-
- if !g.state.DKGFinalized(round, caller) {
- g.state.PutDKGFinalized(round, caller, true)
- g.state.IncDKGFinalizedsCount(round)
- }
-
- return g.useGas(100000)
-}
-
-func (g *GovernanceContract) delegate(nodeAddr common.Address) ([]byte, error) {
- offset := g.state.NodesOffsetByAddress(nodeAddr)
- if offset.Cmp(big.NewInt(0)) < 0 {
- return nil, errExecutionReverted
- }
-
- caller := g.contract.Caller()
- value := g.contract.Value
-
- // Can not delegate if no fund was sent.
- if value.Cmp(big.NewInt(0)) == 0 {
- return nil, errExecutionReverted
- }
-
- // Can not delegate if already delegated.
- delegatorOffset := g.state.DelegatorsOffset(nodeAddr, caller)
- if delegatorOffset.Cmp(big.NewInt(0)) >= 0 {
- return nil, errExecutionReverted
- }
-
- // Add to the total staked of node.
- node := g.state.Node(offset)
- node.Staked = new(big.Int).Add(node.Staked, g.contract.Value)
- g.state.UpdateNode(offset, node)
-
- // Add to network total staked.
- g.state.IncTotalStaked(g.contract.Value)
-
- // Push delegator record.
- offset = g.state.LenDelegators(nodeAddr)
- g.state.PushDelegator(nodeAddr, &delegatorInfo{
- Owner: caller,
- Value: value,
- UndelegatedAt: big.NewInt(0),
- })
- g.state.PutDelegatorOffset(nodeAddr, caller, offset)
- g.state.emitDelegated(nodeAddr, caller, value)
-
- return g.useGas(200000)
-}
-
-func (g *GovernanceContract) updateConfiguration(cfg *rawConfigStruct) ([]byte, error) {
- // Only owner can update configuration.
- if g.contract.Caller() != g.state.Owner() {
- return nil, errExecutionReverted
- }
-
- g.state.UpdateConfigurationRaw(cfg)
- g.state.emitConfigurationChangedEvent()
- return nil, nil
-}
-
-func (g *GovernanceContract) stake(
- publicKey []byte, name, email, location, url string) ([]byte, error) {
-
- // Reject invalid inputs.
- if len(name) >= 32 || len(email) >= 32 || len(location) >= 32 || len(url) >= 128 {
- return g.penalize()
- }
-
- caller := g.contract.Caller()
- offset := g.state.NodesOffsetByAddress(caller)
-
- // Can not stake if already staked.
- if offset.Cmp(big.NewInt(0)) >= 0 {
- return nil, errExecutionReverted
- }
-
- offset = g.state.LenNodes()
- node := &nodeInfo{
- Owner: caller,
- PublicKey: publicKey,
- Staked: big.NewInt(0),
- Fined: big.NewInt(0),
- Name: name,
- Email: email,
- Location: location,
- Url: url,
- }
- g.state.PushNode(node)
- if err := g.state.PutNodeOffsets(node, offset); err != nil {
- return g.penalize()
- }
-
- // Delegate fund to itself.
- if g.contract.Value.Cmp(big.NewInt(0)) > 0 {
- if ret, err := g.delegate(caller); err != nil {
- return ret, err
- }
- }
-
- g.state.emitStaked(caller)
- return g.useGas(100000)
-}
-
-func (g *GovernanceContract) undelegateHelper(nodeAddr, caller common.Address) ([]byte, error) {
- nodeOffset := g.state.NodesOffsetByAddress(nodeAddr)
- if nodeOffset.Cmp(big.NewInt(0)) < 0 {
- return nil, errExecutionReverted
- }
-
- offset := g.state.DelegatorsOffset(nodeAddr, caller)
- if offset.Cmp(big.NewInt(0)) < 0 {
- return nil, errExecutionReverted
- }
-
- node := g.state.Node(nodeOffset)
- if node.Fined.Cmp(big.NewInt(0)) > 0 {
- return nil, errExecutionReverted
- }
-
- delegator := g.state.Delegator(nodeAddr, offset)
-
- if delegator.UndelegatedAt.Cmp(big.NewInt(0)) != 0 {
- return nil, errExecutionReverted
- }
-
- // Set undelegate time.
- delegator.UndelegatedAt = g.evm.Time
- g.state.UpdateDelegator(nodeAddr, offset, delegator)
-
- // Subtract from the total staked of node.
- node.Staked = new(big.Int).Sub(node.Staked, delegator.Value)
- g.state.UpdateNode(nodeOffset, node)
-
- // Subtract to network total staked.
- g.state.DecTotalStaked(delegator.Value)
-
- g.state.emitUndelegated(nodeAddr, caller)
-
- return g.useGas(100000)
-}
-
-func (g *GovernanceContract) undelegate(nodeAddr common.Address) ([]byte, error) {
- return g.undelegateHelper(nodeAddr, g.contract.Caller())
-}
-
-func (g *GovernanceContract) withdraw(nodeAddr common.Address) ([]byte, error) {
- caller := g.contract.Caller()
-
- nodeOffset := g.state.NodesOffsetByAddress(nodeAddr)
- if nodeOffset.Cmp(big.NewInt(0)) < 0 {
- return nil, errExecutionReverted
- }
-
- offset := g.state.DelegatorsOffset(nodeAddr, caller)
- if offset.Cmp(big.NewInt(0)) < 0 {
- return nil, errExecutionReverted
- }
-
- delegator := g.state.Delegator(nodeAddr, offset)
-
- // Not yet undelegated.
- if delegator.UndelegatedAt.Cmp(big.NewInt(0)) == 0 {
- return g.penalize()
- }
-
- unlockTime := new(big.Int).Add(delegator.UndelegatedAt, g.state.LockupPeriod())
- if g.evm.Time.Cmp(unlockTime) <= 0 {
- return g.penalize()
- }
-
- length := g.state.LenDelegators(nodeAddr)
- lastIndex := new(big.Int).Sub(length, big.NewInt(1))
-
- // Delete the delegator.
- if offset.Cmp(lastIndex) != 0 {
- lastNode := g.state.Delegator(nodeAddr, lastIndex)
- g.state.UpdateDelegator(nodeAddr, offset, lastNode)
- g.state.PutDelegatorOffset(nodeAddr, lastNode.Owner, offset)
- }
- g.state.DeleteDelegatorsOffset(nodeAddr, caller)
- g.state.PopLastDelegator(nodeAddr)
-
- // Return the staked fund.
- if !g.transfer(GovernanceContractAddress, delegator.Owner, delegator.Value) {
- return nil, errExecutionReverted
- }
-
- g.state.emitWithdrawn(nodeAddr, delegator.Value)
-
- // We are the last delegator to withdraw the fund, remove the node info.
- if g.state.LenDelegators(nodeAddr).Cmp(big.NewInt(0)) == 0 {
- length := g.state.LenNodes()
- lastIndex := new(big.Int).Sub(length, big.NewInt(1))
-
- // Delete the node.
- if offset.Cmp(lastIndex) != 0 {
- lastNode := g.state.Node(lastIndex)
- g.state.UpdateNode(offset, lastNode)
- if err := g.state.PutNodeOffsets(lastNode, offset); err != nil {
- panic(err)
- }
- }
- g.state.DeleteNodesOffsetByAddress(nodeAddr)
- g.state.PopLastNode()
- }
-
- return g.useGas(100000)
-}
-
-func (g *GovernanceContract) unstake() ([]byte, error) {
- caller := g.contract.Caller()
- offset := g.state.NodesOffsetByAddress(caller)
- if offset.Cmp(big.NewInt(0)) < 0 {
- return nil, errExecutionReverted
- }
-
- node := g.state.Node(offset)
- if node.Fined.Cmp(big.NewInt(0)) > 0 {
- return nil, errExecutionReverted
- }
-
- // Undelegate all delegators.
- lenDelegators := g.state.LenDelegators(caller)
- i := new(big.Int).Sub(lenDelegators, big.NewInt(1))
- for i.Cmp(big.NewInt(0)) >= 0 {
- delegator := g.state.Delegator(caller, i)
- if ret, err := g.undelegateHelper(caller, delegator.Owner); err != nil {
- return ret, err
- }
- i = i.Sub(i, big.NewInt(1))
- }
-
- g.state.emitUnstaked(caller)
-
- return g.useGas(100000)
-}
-
-func (g *GovernanceContract) payFine(nodeAddr common.Address) ([]byte, error) {
- caller := g.contract.Caller()
-
- nodeOffset := g.state.NodesOffsetByAddress(nodeAddr)
- if nodeOffset.Cmp(big.NewInt(0)) < 0 {
- return nil, errExecutionReverted
- }
-
- offset := g.state.DelegatorsOffset(nodeAddr, caller)
- if offset.Cmp(big.NewInt(0)) < 0 {
- return nil, errExecutionReverted
- }
-
- node := g.state.Node(nodeOffset)
- if node.Fined.Cmp(big.NewInt(0)) <= 0 || node.Fined.Cmp(g.contract.Value) < 0 {
- return nil, errExecutionReverted
- }
-
- node.Fined = new(big.Int).Sub(node.Fined, g.contract.Value)
- g.state.UpdateNode(nodeOffset, node)
-
- // TODO: paid fine should be added to award pool.
-
- g.state.emitFinePaid(nodeAddr, g.contract.Value)
-
- return g.useGas(100000)
-}
-
-func (g *GovernanceContract) proposeCRS(nextRound *big.Int, signedCRS []byte) ([]byte, error) {
- round := g.state.Round()
-
- if nextRound.Cmp(round) <= 0 {
- return nil, errExecutionReverted
- }
-
- prevCRS := g.state.CRS(round)
-
- // Prepare DKGMasterPublicKeys.
- dkgMasterPKs := g.state.UniqueDKGMasterPublicKeys(round)
-
- // Prepare DKGComplaints.
- var dkgComplaints []*dkgTypes.Complaint
- for _, comp := range g.state.DKGComplaints(round) {
- x := new(dkgTypes.Complaint)
- if err := rlp.DecodeBytes(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) {
- return g.penalize()
- }
-
- // Save new CRS into state and increase round.
- newCRS := crypto.Keccak256(signedCRS)
- crs := common.BytesToHash(newCRS)
-
- g.state.PushCRS(crs)
- g.state.emitCRSProposed(nextRound, crs)
-
- // To encourage DKG set to propose the correct value, correctly submitting
- // this should cause nothing.
- return g.useGas(0)
-}
-
-type sortBytes [][]byte
-
-func (s sortBytes) Less(i, j int) bool {
- return bytes.Compare(s[i], s[j]) < 0
-}
-
-func (s sortBytes) Swap(i, j int) {
- s[i], s[j] = s[j], s[i]
-}
-
-func (s sortBytes) Len() int {
- return len(s)
-}
-
-func (g *GovernanceContract) fine(nodeAddr common.Address, amount *big.Int, payloads ...[]byte) error {
- sort.Sort(sortBytes(payloads))
-
- hash := Bytes32(crypto.Keccak256Hash(payloads...))
- if g.state.FineRecords(hash) {
- return errors.New("already fined")
- }
- g.state.SetFineRecords(hash, true)
-
- nodeOffset := g.state.NodesOffsetByAddress(nodeAddr)
- if nodeOffset.Cmp(big.NewInt(0)) < 0 {
- return errExecutionReverted
- }
-
- // Set fined value.
- node := g.state.Node(nodeOffset)
- node.Fined = new(big.Int).Add(node.Fined, amount)
- g.state.UpdateNode(nodeOffset, node)
-
- g.state.emitFined(nodeAddr, amount)
-
- return nil
-}
-
-func (g *GovernanceContract) report(reportType *big.Int, arg1, arg2 []byte) ([]byte, error) {
- typeEnum := ReportType(reportType.Uint64())
- var reportedNodeID coreTypes.NodeID
-
- switch typeEnum {
- case ReportTypeForkVote:
- vote1 := new(coreTypes.Vote)
- if err := rlp.DecodeBytes(arg1, vote1); err != nil {
- return g.penalize()
- }
- vote2 := new(coreTypes.Vote)
- if err := rlp.DecodeBytes(arg2, vote2); err != nil {
- return g.penalize()
- }
- need, err := coreUtils.NeedPenaltyForkVote(vote1, vote2)
- if !need || err != nil {
- return g.penalize()
- }
- reportedNodeID = vote1.ProposerID
- case ReportTypeForkBlock:
- block1 := new(coreTypes.Block)
- if err := rlp.DecodeBytes(arg1, block1); err != nil {
- return g.penalize()
- }
- block2 := new(coreTypes.Block)
- if err := rlp.DecodeBytes(arg2, block2); err != nil {
- return g.penalize()
- }
- need, err := coreUtils.NeedPenaltyForkBlock(block1, block2)
- if !need || err != nil {
- return g.penalize()
- }
- reportedNodeID = block1.ProposerID
- default:
- return g.penalize()
- }
-
- offset := g.state.NodesOffsetByID(Bytes32(reportedNodeID.Hash))
- node := g.state.Node(offset)
-
- g.state.emitForkReported(node.Owner, reportType, arg1, arg2)
-
- fineValue := g.state.FineValue(reportType)
- if err := g.fine(node.Owner, fineValue, arg1, arg2); err != nil {
- return nil, errExecutionReverted
- }
- 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) {
- // Validate if this mapping is correct. Only block proposer need to verify this.
- if g.evm.IsBlockProposer() {
- realHeight, ok := g.evm.GetRoundHeight(round.Uint64())
- if !ok {
- return g.penalize()
- }
-
- if height.Cmp(new(big.Int).SetUint64(realHeight)) != 0 {
- return g.penalize()
- }
- }
-
- // Only allow updating the next round.
- nextRound := g.state.LenRoundHeight()
- if round.Cmp(nextRound) != 0 {
- // No need to penalize, since the only possibility at this point is the
- // round height is already snapshoted.
- return nil, errExecutionReverted
- }
-
- g.state.PushRoundHeight(height)
- return nil, nil
-}
diff --git a/core/vm/evm/governance_test.go b/core/vm/evm/governance_test.go
deleted file mode 100644
index 5a82c7f1a..000000000
--- a/core/vm/evm/governance_test.go
+++ /dev/null
@@ -1,1061 +0,0 @@
-// 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 evm
-
-import (
- "bytes"
- "crypto/ecdsa"
- "math/big"
- "math/rand"
- "sort"
- "testing"
- "time"
-
- coreCommon "github.com/dexon-foundation/dexon-consensus/common"
- 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"
- 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/core/vm"
- "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 := rand.Int31()%(maxLength-minLength) + minLength
- b := make([]byte, length)
- for i := range b {
- b[i] = byte(65 + rand.Int31()%60)
- }
- return b
-}
-
-type GovernanceStateHelperTestSuite struct {
- suite.Suite
-
- s *GovernanceStateHelper
-}
-
-func (g *GovernanceStateHelperTestSuite) SetupTest() {
- db := state.NewDatabase(ethdb.NewMemDatabase())
- statedb, err := state.New(common.Hash{}, db)
- if err != nil {
- panic(err)
- }
- g.s = &GovernanceStateHelper{statedb}
-}
-
-func (g *GovernanceStateHelperTestSuite) TestReadWriteBytes() {
- 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))
-
- // 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))
- }
-}
-
-func TestGovernanceStateHelper(t *testing.T) {
- suite.Run(t, new(GovernanceStateHelperTestSuite))
-}
-
-type GovernanceContractTestSuite struct {
- suite.Suite
-
- config *params.DexconConfig
- memDB *ethdb.MemDatabase
- stateDB *state.StateDB
- s *GovernanceStateHelper
-}
-
-func (g *GovernanceContractTestSuite) 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 = &GovernanceStateHelper{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
-
- 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.PushCRS(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)
-}
-
-func (g *GovernanceContractTestSuite) newPrefundAccount() (*ecdsa.PrivateKey, common.Address) {
- privKey, err := crypto.GenerateKey()
- if err != nil {
- panic(err)
- }
- address := crypto.PubkeyToAddress(privKey.PublicKey)
-
- g.stateDB.AddBalance(address, new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2e6)))
- return privKey, address
-}
-
-func (g *GovernanceContractTestSuite) call(caller common.Address, input []byte, value *big.Int) ([]byte, error) {
- context := vm.Context{
- CanTransfer: func(db vm.StateDB, addr common.Address, amount *big.Int) bool {
- return db.GetBalance(addr).Cmp(amount) >= 0
- },
- Transfer: func(db vm.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
- },
- Time: big.NewInt(time.Now().UnixNano() / 1000000),
- BlockNumber: big.NewInt(0),
- }
-
- evm := NewEVM(context, g.stateDB, params.TestChainConfig, Config{IsBlockProposer: true})
- ret, _, err := evm.Call(vm.AccountRef(caller), GovernanceContractAddress, input, 10000000, value)
- return ret, err
-}
-
-func (g *GovernanceContractTestSuite) TestTransferOwnership() {
- _, addr := g.newPrefundAccount()
-
- input, err := abiObject.Pack("transferOwnership", addr)
- g.Require().NoError(err)
-
- // Call with non-owner.
- _, err = g.call(addr, input, big.NewInt(0))
- g.Require().NotNil(err)
-
- // Call with owner.
- _, err = g.call(g.config.Owner, input, big.NewInt(0))
- g.Require().NoError(err)
- g.Require().Equal(addr, g.s.Owner())
-}
-
-func (g *GovernanceContractTestSuite) TestStakeUnstakeWithoutExtraDelegators() {
- privKey, addr := g.newPrefundAccount()
- pk := crypto.FromECDSAPub(&privKey.PublicKey)
-
- // Stake.
- amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6))
- balanceBeforeStake := g.stateDB.GetBalance(addr)
- input, err := abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org")
- g.Require().NoError(err)
- _, err = g.call(addr, input, amount)
- g.Require().NoError(err)
-
- g.Require().Equal(1, int(g.s.LenNodes().Uint64()))
- g.Require().Equal(1, 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))
-
- // Staking again should fail.
- _, err = g.call(addr, input, amount)
- g.Require().NotNil(err)
-
- // Unstake.
- input, err = abiObject.Pack("unstake")
- g.Require().NoError(err)
- _, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
- g.Require().Equal(0, len(g.s.QualifiedNodes()))
- g.Require().Equal(1, int(g.s.LenDelegators(addr).Uint64()))
- g.Require().Equal(1, 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())
-
- // Wait for lockup time than withdraw.
- time.Sleep(time.Second * 2)
- input, err = abiObject.Pack("withdraw", addr)
- g.Require().NoError(err)
- _, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
-
- g.Require().Equal(0, len(g.s.QualifiedNodes()))
- g.Require().Equal(0, int(g.s.LenDelegators(addr).Uint64()))
- g.Require().Equal(0, int(g.s.LenNodes().Uint64()))
-
- // Stake 2 nodes, and unstake the first then the second.
-
- // 2nd node Stake.
- privKey2, addr2 := g.newPrefundAccount()
- pk2 := crypto.FromECDSAPub(&privKey2.PublicKey)
- input, err = abiObject.Pack("stake", pk2, "Test2", "test2@dexon.org", "Taipei, Taiwan", "https://dexon.org")
- g.Require().NoError(err)
- _, err = g.call(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 = abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org")
- g.Require().NoError(err)
- _, err = g.call(addr, input, amount)
- g.Require().NoError(err)
-
- 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 = abiObject.Pack("unstake")
- g.Require().NoError(err)
- _, err = g.call(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 = abiObject.Pack("withdraw", addr2)
- g.Require().NoError(err)
- _, err = g.call(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 = abiObject.Pack("unstake")
- g.Require().NoError(err)
- _, err = g.call(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 = abiObject.Pack("withdraw", addr)
- g.Require().NoError(err)
- _, err = g.call(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()))
- g.Require().Equal(-1, int(g.s.DelegatorsOffset(addr, 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 *GovernanceContractTestSuite) TestDelegateUndelegate() {
- privKey, addr := g.newPrefundAccount()
- pk := crypto.FromECDSAPub(&privKey.PublicKey)
-
- // Stake.
- input, err := abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org")
- g.Require().NoError(err)
- ownerStaked := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5))
- _, err = g.call(addr, input, ownerStaked)
- g.Require().NoError(err)
- g.Require().Equal(0, len(g.s.QualifiedNodes()))
- g.Require().Equal(addr, g.s.Delegator(addr, big.NewInt(0)).Owner)
- g.Require().Equal(ownerStaked, g.s.Node(big.NewInt(0)).Staked)
-
- // 1st delegator delegate to 1st node.
- _, addrDelegator := g.newPrefundAccount()
-
- balanceBeforeDelegate := g.stateDB.GetBalance(addrDelegator)
- amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3e5))
- input, err = abiObject.Pack("delegate", addr)
- g.Require().NoError(err)
-
- _, err = g.call(addrDelegator, input, amount)
- g.Require().NoError(err)
- g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator))
- g.Require().Equal(addrDelegator, g.s.Delegator(addr, big.NewInt(1)).Owner)
- g.Require().Equal(new(big.Int).Add(amount, ownerStaked), g.s.Node(big.NewInt(0)).Staked)
- g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String())
- g.Require().Equal(1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64()))
-
- // Same person delegate the 2nd time should fail.
- _, err = g.call(addrDelegator, input, big.NewInt(1e18))
- g.Require().NotNil(err)
-
- // Not yet qualified.
- g.Require().Equal(0, len(g.s.QualifiedNodes()))
-
- // 2nd delegator delegate to 1st node.
- _, addrDelegator2 := g.newPrefundAccount()
- _, err = g.call(addrDelegator2, input, amount)
- g.Require().NoError(err)
- g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator2))
- g.Require().Equal(addrDelegator2, g.s.Delegator(addr, big.NewInt(2)).Owner)
- g.Require().Equal(new(big.Int).Add(ownerStaked, new(big.Int).Mul(amount, big.NewInt(2))),
- g.s.Node(big.NewInt(0)).Staked)
- g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String())
- g.Require().Equal(2, int(g.s.DelegatorsOffset(addr, addrDelegator2).Int64()))
-
- // Qualified.
- g.Require().Equal(1, len(g.s.QualifiedNodes()))
-
- // Undelegate addrDelegator.
- balanceBeforeUnDelegate := g.stateDB.GetBalance(addrDelegator)
- input, err = abiObject.Pack("undelegate", addr)
- g.Require().NoError(err)
- _, err = g.call(addrDelegator, input, big.NewInt(0))
- g.Require().Equal(new(big.Int).Add(amount, ownerStaked), g.s.Node(big.NewInt(0)).Staked)
- g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String())
- g.Require().NoError(err)
-
- // Undelegate the second time should fail.
- _, err = g.call(addrDelegator, input, big.NewInt(0))
- g.Require().Error(err)
-
- // Withdraw within lockup time should fail.
- input, err = abiObject.Pack("withdraw", addr)
- g.Require().NoError(err)
- _, err = g.call(addrDelegator, input, big.NewInt(0))
- g.Require().NotNil(err)
-
- g.Require().Equal(3, int(g.s.LenDelegators(addr).Uint64()))
- g.Require().Equal(balanceBeforeUnDelegate, g.stateDB.GetBalance(addrDelegator))
- g.Require().NotEqual(-1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64()))
-
- // Wait for lockup time than withdraw.
- time.Sleep(time.Second * 2)
- input, err = abiObject.Pack("withdraw", addr)
- g.Require().NoError(err)
- _, err = g.call(addrDelegator, input, big.NewInt(0))
- g.Require().NoError(err)
-
- g.Require().Equal(2, int(g.s.LenDelegators(addr).Uint64()))
- g.Require().Equal(new(big.Int).Add(balanceBeforeUnDelegate, amount), g.stateDB.GetBalance(addrDelegator))
- g.Require().Equal(-1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64()))
-
- // Withdraw when their is no delegation should fail.
- time.Sleep(time.Second)
- input, err = abiObject.Pack("withdraw", addr)
- g.Require().NoError(err)
- _, err = g.call(addrDelegator, input, big.NewInt(0))
- g.Require().Error(err)
-
- // Undelegate addrDelegator2.
- balanceBeforeUnDelegate = g.stateDB.GetBalance(addrDelegator2)
- input, err = abiObject.Pack("undelegate", addr)
- g.Require().NoError(err)
- _, err = g.call(addrDelegator2, input, big.NewInt(0))
- g.Require().NoError(err)
-
- g.Require().Equal(ownerStaked, g.s.Node(big.NewInt(0)).Staked)
- g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String())
-
- // Wait for lockup time than withdraw.
- time.Sleep(time.Second * 2)
- input, err = abiObject.Pack("withdraw", addr)
- g.Require().NoError(err)
- _, err = g.call(addrDelegator2, input, big.NewInt(0))
- g.Require().NoError(err)
-
- g.Require().Equal(1, int(g.s.LenDelegators(addr).Uint64()))
- g.Require().Equal(new(big.Int).Add(balanceBeforeUnDelegate, amount), g.stateDB.GetBalance(addrDelegator2))
- g.Require().Equal(-1, int(g.s.DelegatorsOffset(addr, addrDelegator2).Int64()))
-
- // Unqualified
- g.Require().Equal(0, len(g.s.QualifiedNodes()))
-
- // Owner undelegate itself.
- g.Require().Equal(1, int(g.s.LenNodes().Uint64()))
- g.Require().Equal(1, int(g.s.LenDelegators(addr).Uint64()))
-
- input, err = abiObject.Pack("undelegate", addr)
- g.Require().NoError(err)
- _, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
- g.Require().Equal(big.NewInt(0).String(), g.s.Node(big.NewInt(0)).Staked.String())
- g.Require().Equal(big.NewInt(0).String(), g.s.TotalStaked().String())
-
- time.Sleep(time.Second * 2)
- input, err = abiObject.Pack("withdraw", addr)
- g.Require().NoError(err)
- _, err = g.call(addr, input, big.NewInt(0))
-
- g.Require().Equal(0, int(g.s.LenNodes().Uint64()))
- g.Require().Equal(0, int(g.s.LenDelegators(addr).Uint64()))
-}
-
-func (g *GovernanceContractTestSuite) TestFine() {
- privKey, addr := g.newPrefundAccount()
- pk := crypto.FromECDSAPub(&privKey.PublicKey)
-
- // Stake.
- input, err := abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org")
- g.Require().NoError(err)
- ownerStaked := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5))
- _, err = g.call(addr, input, ownerStaked)
- g.Require().NoError(err)
- g.Require().Equal(0, len(g.s.QualifiedNodes()))
- g.Require().Equal(addr, g.s.Delegator(addr, big.NewInt(0)).Owner)
- g.Require().Equal(ownerStaked, g.s.Node(big.NewInt(0)).Staked)
-
- // 1st delegator delegate to 1st node.
- _, addrDelegator := g.newPrefundAccount()
-
- balanceBeforeDelegate := g.stateDB.GetBalance(addrDelegator)
- amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5))
- input, err = abiObject.Pack("delegate", addr)
- g.Require().NoError(err)
-
- _, err = g.call(addrDelegator, input, amount)
- g.Require().NoError(err)
- g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator))
- g.Require().Equal(addrDelegator, g.s.Delegator(addr, big.NewInt(1)).Owner)
- g.Require().Equal(new(big.Int).Add(amount, ownerStaked), g.s.Node(big.NewInt(0)).Staked)
- g.Require().Equal(1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64()))
-
- // Qualified.
- g.Require().Equal(1, len(g.s.QualifiedNodes()))
-
- // Paying to node without fine should fail.
- input, err = abiObject.Pack("payFine", addr)
- g.Require().NoError(err)
- _, err = g.call(addrDelegator, 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 undelegate before fines are paied.
- input, err = abiObject.Pack("undelegate", addr)
- g.Require().NoError(err)
- _, err = g.call(addrDelegator, input, big.NewInt(0))
- g.Require().NotNil(err)
-
- // Only delegators can pay fine.
- _, addrDelegator2 := g.newPrefundAccount()
- input, err = abiObject.Pack("payFine", addr)
- g.Require().NoError(err)
- _, err = g.call(addrDelegator2, input, big.NewInt(5e5))
- g.Require().NotNil(err)
-
- // Paying more than fine should fail.
- payAmount := new(big.Int).Add(amount, amount)
- input, err = abiObject.Pack("payFine", addr)
- g.Require().NoError(err)
- _, err = g.call(addrDelegator, input, payAmount)
- g.Require().NotNil(err)
-
- // Pay the fine.
- input, err = abiObject.Pack("payFine", addr)
- g.Require().NoError(err)
- _, err = g.call(addrDelegator, input, amount)
- g.Require().NoError(err)
-
- // Qualified.
- g.Require().Equal(1, len(g.s.QualifiedNodes()))
-
- // Can undelegate after all fines are paied.
- input, err = abiObject.Pack("undelegate", addr)
- g.Require().NoError(err)
- _, err = g.call(addrDelegator, input, big.NewInt(0))
- g.Require().NoError(err)
-}
-
-func (g *GovernanceContractTestSuite) TestUnstakeWithExtraDelegators() {
- privKey, addr := g.newPrefundAccount()
- pk := crypto.FromECDSAPub(&privKey.PublicKey)
-
- // Stake.
- amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5))
- input, err := abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org")
- g.Require().NoError(err)
- _, err = g.call(addr, input, amount)
- g.Require().NoError(err)
-
- // 1st delegator delegate to 1st node.
- _, addrDelegator := g.newPrefundAccount()
-
- balanceBeforeDelegate := g.stateDB.GetBalance(addrDelegator)
- amount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3e5))
- input, err = abiObject.Pack("delegate", addr)
- g.Require().NoError(err)
-
- _, err = g.call(addrDelegator, input, amount)
- g.Require().NoError(err)
- g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator))
- g.Require().Equal(addrDelegator, g.s.Delegator(addr, big.NewInt(1)).Owner)
- g.Require().Equal(0, len(g.s.QualifiedNodes()))
-
- // 2st delegator delegate to 1st node.
- _, addrDelegator2 := g.newPrefundAccount()
-
- balanceBeforeDelegate = g.stateDB.GetBalance(addrDelegator2)
- input, err = abiObject.Pack("delegate", addr)
- g.Require().NoError(err)
-
- _, err = g.call(addrDelegator2, input, amount)
- g.Require().NoError(err)
- g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator2))
- g.Require().Equal(addrDelegator2, g.s.Delegator(addr, big.NewInt(2)).Owner)
-
- // Node is now qualified.
- g.Require().Equal(1, len(g.s.QualifiedNodes()))
-
- // Unstake.
- input, err = abiObject.Pack("unstake")
- g.Require().NoError(err)
- _, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
-
- time.Sleep(time.Second * 2)
- input, err = abiObject.Pack("withdraw", addr)
- g.Require().NoError(err)
- _, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
- _, err = g.call(addrDelegator, input, big.NewInt(0))
- g.Require().NoError(err)
- _, err = g.call(addrDelegator2, input, big.NewInt(0))
- g.Require().NoError(err)
-
- g.Require().Equal(0, int(g.s.LenDelegators(addr).Uint64()))
- g.Require().Equal(0, int(g.s.LenNodes().Uint64()))
-
- // Check balance.
- g.Require().Equal(balanceBeforeDelegate, g.stateDB.GetBalance(addr))
- g.Require().Equal(balanceBeforeDelegate, g.stateDB.GetBalance(addrDelegator))
- g.Require().Equal(balanceBeforeDelegate, g.stateDB.GetBalance(addrDelegator2))
- g.Require().Equal(big.NewInt(1), g.stateDB.GetBalance(GovernanceContractAddress))
-}
-
-func (g *GovernanceContractTestSuite) TestUpdateConfiguration() {
- _, addr := g.newPrefundAccount()
-
- input, err := abiObject.Pack("updateConfiguration",
- new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)),
- big.NewInt(1000),
- big.NewInt(0.1875*decimalMultiplier),
- big.NewInt(1e18),
- big.NewInt(1e18),
- big.NewInt(8000000),
- big.NewInt(6),
- big.NewInt(250),
- big.NewInt(2500),
- big.NewInt(0),
- big.NewInt(667000),
- big.NewInt(4),
- big.NewInt(4),
- big.NewInt(600000),
- 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(addr, input, big.NewInt(0))
- g.Require().NotNil(err)
-
- // Call with owner.
- _, err = g.call(g.config.Owner, input, big.NewInt(0))
- g.Require().NoError(err)
-}
-
-func (g *GovernanceContractTestSuite) TestSnapshotRound() {
- _, addr := g.newPrefundAccount()
-
- // Wrong height.
- input, err := abiObject.Pack("snapshotRound", big.NewInt(1), big.NewInt(666))
- g.Require().NoError(err)
- _, err = g.call(addr, input, big.NewInt(0))
- g.Require().NotNil(err)
-
- // Invalid round.
- input, err = abiObject.Pack("snapshotRound", big.NewInt(2), big.NewInt(2000))
- g.Require().NoError(err)
- _, err = g.call(addr, input, big.NewInt(0))
- g.Require().NotNil(err)
-
- // Correct.
- input, err = abiObject.Pack("snapshotRound", big.NewInt(1), big.NewInt(1000))
- g.Require().NoError(err)
- _, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
-
- // Duplicate round.
- input, err = abiObject.Pack("snapshotRound", big.NewInt(1), big.NewInt(1000))
- g.Require().NoError(err)
- _, err = g.call(addr, input, big.NewInt(0))
- g.Require().NotNil(err)
-
- // Invalid round.
- input, err = abiObject.Pack("snapshotRound", big.NewInt(3), big.NewInt(3000))
- g.Require().NoError(err)
- _, err = g.call(addr, input, big.NewInt(0))
- g.Require().NotNil(err)
-
- // Correct.
- input, err = abiObject.Pack("snapshotRound", big.NewInt(2), big.NewInt(2000))
- g.Require().NoError(err)
- _, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
-}
-
-func (g *GovernanceContractTestSuite) TestConfigurationReading() {
- _, addr := g.newPrefundAccount()
-
- // CRS.
- input, err := abiObject.Pack("crs", big.NewInt(0))
- g.Require().NoError(err)
- res, err := g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
- var crs0 [32]byte
- err = abiObject.Unpack(&crs0, "crs", res)
- g.Require().NoError(err)
- g.Require().Equal(crypto.Keccak256Hash([]byte(g.config.GenesisCRSText)), common.BytesToHash(crs0[:]))
-
- // Owner.
- input, err = abiObject.Pack("owner")
- g.Require().NoError(err)
- res, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
- var owner common.Address
- err = abiObject.Unpack(&owner, "owner", res)
- g.Require().NoError(err)
- g.Require().Equal(g.config.Owner, owner)
-
- // MinStake.
- input, err = abiObject.Pack("minStake")
- g.Require().NoError(err)
- res, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
- var value *big.Int
- err = abiObject.Unpack(&value, "minStake", res)
- g.Require().NoError(err)
- g.Require().Equal(g.config.MinStake.String(), value.String())
-
- // BlockReward.
- input, err = abiObject.Pack("miningVelocity")
- g.Require().NoError(err)
- res, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
- err = abiObject.Unpack(&value, "miningVelocity", res)
- g.Require().NoError(err)
- g.Require().Equal(g.config.MiningVelocity, float32(value.Uint64())/decimalMultiplier)
-
- // BlockGasLimit.
- input, err = abiObject.Pack("blockGasLimit")
- g.Require().NoError(err)
- res, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
- err = abiObject.Unpack(&value, "blockGasLimit", res)
- g.Require().NoError(err)
- g.Require().Equal(g.config.BlockGasLimit, value.Uint64())
-
- // NumChains.
- input, err = abiObject.Pack("numChains")
- g.Require().NoError(err)
- res, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
- err = abiObject.Unpack(&value, "numChains", res)
- g.Require().NoError(err)
- g.Require().Equal(g.config.NumChains, uint32(value.Uint64()))
-
- // LambdaBA.
- input, err = abiObject.Pack("lambdaBA")
- g.Require().NoError(err)
- res, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
- err = abiObject.Unpack(&value, "lambdaBA", res)
- g.Require().NoError(err)
- g.Require().Equal(g.config.LambdaBA, value.Uint64())
-
- // LambdaDKG.
- input, err = abiObject.Pack("lambdaDKG")
- g.Require().NoError(err)
- res, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
- err = abiObject.Unpack(&value, "lambdaDKG", res)
- g.Require().NoError(err)
- g.Require().Equal(g.config.LambdaDKG, value.Uint64())
-
- // K.
- input, err = abiObject.Pack("k")
- g.Require().NoError(err)
- res, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
- err = abiObject.Unpack(&value, "k", res)
- g.Require().NoError(err)
- g.Require().Equal(g.config.K, uint32(value.Uint64()))
-
- // PhiRatio.
- input, err = abiObject.Pack("phiRatio")
- g.Require().NoError(err)
- res, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
- err = abiObject.Unpack(&value, "phiRatio", res)
- g.Require().NoError(err)
- g.Require().Equal(g.config.PhiRatio, float32(value.Uint64())/decimalMultiplier)
-
- // NotarySetSize.
- input, err = abiObject.Pack("notarySetSize")
- g.Require().NoError(err)
- res, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
- err = abiObject.Unpack(&value, "notarySetSize", res)
- g.Require().NoError(err)
- g.Require().Equal(g.config.NotarySetSize, uint32(value.Uint64()))
-
- // DKGSetSize.
- input, err = abiObject.Pack("dkgSetSize")
- g.Require().NoError(err)
- res, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
- err = abiObject.Unpack(&value, "dkgSetSize", res)
- g.Require().NoError(err)
- g.Require().Equal(g.config.DKGSetSize, uint32(value.Uint64()))
-
- // RoundInterval.
- input, err = abiObject.Pack("roundInterval")
- g.Require().NoError(err)
- res, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
- err = abiObject.Unpack(&value, "roundInterval", res)
- g.Require().NoError(err)
- g.Require().Equal(g.config.RoundInterval, value.Uint64())
-
- // MinBlockInterval.
- input, err = abiObject.Pack("minBlockInterval")
- g.Require().NoError(err)
- res, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
- err = abiObject.Unpack(&value, "minBlockInterval", res)
- g.Require().NoError(err)
- g.Require().Equal(g.config.MinBlockInterval, value.Uint64())
-}
-
-func (g *GovernanceContractTestSuite) TestReportForkVote() {
- key, addr := g.newPrefundAccount()
- pkBytes := crypto.FromECDSAPub(&key.PublicKey)
-
- // Stake.
- amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5))
- input, err := abiObject.Pack("stake", pkBytes, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org")
- g.Require().NoError(err)
- _, err = g.call(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 = abiObject.Pack("report", big.NewInt(2), vote1Bytes, vote2Bytes)
- g.Require().NoError(err)
- _, err = g.call(addr, input, big.NewInt(0))
- g.Require().Error(err)
-
- input, err = abiObject.Pack("report", big.NewInt(1), vote1Bytes, vote2Bytes)
- g.Require().NoError(err)
- _, err = g.call(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 = abiObject.Pack("report", big.NewInt(1), vote1Bytes, vote2Bytes)
- g.Require().NoError(err)
- _, err = g.call(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 = abiObject.Pack("finedRecords", hash)
- g.Require().NoError(err)
- res, err := g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
-
- var value bool
- err = abiObject.Unpack(&value, "finedRecords", res)
- g.Require().NoError(err)
- g.Require().True(value)
-}
-
-func (g *GovernanceContractTestSuite) TestReportForkBlock() {
- key, addr := g.newPrefundAccount()
- pkBytes := crypto.FromECDSAPub(&key.PublicKey)
-
- // Stake.
- amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5))
- input, err := abiObject.Pack("stake", pkBytes, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org")
- g.Require().NoError(err)
- _, err = g.call(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 = abiObject.Pack("report", big.NewInt(1), block1Bytes, block2Bytes)
- g.Require().NoError(err)
- _, err = g.call(addr, input, big.NewInt(0))
- g.Require().Error(err)
-
- input, err = abiObject.Pack("report", big.NewInt(2), block1Bytes, block2Bytes)
- g.Require().NoError(err)
- _, err = g.call(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 = abiObject.Pack("report", big.NewInt(2), block1Bytes, block2Bytes)
- g.Require().NoError(err)
- _, err = g.call(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 = abiObject.Pack("finedRecords", hash)
- g.Require().NoError(err)
- res, err := g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
-
- var value bool
- err = abiObject.Unpack(&value, "finedRecords", res)
- g.Require().NoError(err)
- g.Require().True(value)
-}
-
-func (g *GovernanceContractTestSuite) TestMiscVariableReading() {
- privKey, addr := g.newPrefundAccount()
- pk := crypto.FromECDSAPub(&privKey.PublicKey)
-
- input, err := abiObject.Pack("totalSupply")
- g.Require().NoError(err)
- res, err := g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
-
- input, err = abiObject.Pack("totalStaked")
- g.Require().NoError(err)
- res, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
-
- // Stake.
- amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5))
- input, err = abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org")
- g.Require().NoError(err)
- _, err = g.call(addr, input, amount)
- g.Require().NoError(err)
-
- // 1st delegator delegate to 1st node.
- _, addrDelegator := g.newPrefundAccount()
- amount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3e5))
- input, err = abiObject.Pack("delegate", addr)
- g.Require().NoError(err)
- _, err = g.call(addrDelegator, input, amount)
- g.Require().NoError(err)
-
- // 2st delegator delegate to 1st node.
- _, addrDelegator2 := g.newPrefundAccount()
- input, err = abiObject.Pack("delegate", addr)
- g.Require().NoError(err)
- _, err = g.call(addrDelegator2, input, amount)
- g.Require().NoError(err)
-
- input, err = abiObject.Pack("nodes", big.NewInt(0))
- g.Require().NoError(err)
- res, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
-
- input, err = abiObject.Pack("nodesLength")
- g.Require().NoError(err)
- res, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
- var value *big.Int
- err = abiObject.Unpack(&value, "nodesLength", res)
- g.Require().NoError(err)
- g.Require().Equal(1, int(value.Uint64()))
-
- input, err = abiObject.Pack("nodesOffsetByAddress", addr)
- g.Require().NoError(err)
- res, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
- err = abiObject.Unpack(&value, "nodesOffsetByAddress", res)
- g.Require().NoError(err)
- g.Require().Equal(0, int(value.Uint64()))
-
- id, err := publicKeyToNodeID(pk)
- g.Require().NoError(err)
- input, err = abiObject.Pack("nodesOffsetByID", id)
- g.Require().NoError(err)
- res, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
- err = abiObject.Unpack(&value, "nodesOffsetByID", res)
- g.Require().NoError(err)
- g.Require().Equal(0, int(value.Uint64()))
-
- input, err = abiObject.Pack("delegators", addr, big.NewInt(0))
- g.Require().NoError(err)
- res, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
-
- input, err = abiObject.Pack("delegatorsLength", addr)
- g.Require().NoError(err)
- res, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
- err = abiObject.Unpack(&value, "delegatorsLength", res)
- g.Require().NoError(err)
- g.Require().Equal(3, int(value.Uint64()))
-
- input, err = abiObject.Pack("delegatorsOffset", addr, addrDelegator2)
- g.Require().NoError(err)
- res, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
- err = abiObject.Unpack(&value, "delegatorsOffset", res)
- g.Require().NoError(err)
- g.Require().Equal(2, int(value.Uint64()))
-
- input, err = abiObject.Pack("fineValues", big.NewInt(0))
- g.Require().NoError(err)
- res, err = g.call(addr, input, big.NewInt(0))
- g.Require().NoError(err)
-}
-
-func (g *GovernanceContractTestSuite) 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())
-}
-
-func TestGovernanceContract(t *testing.T) {
- suite.Run(t, new(GovernanceContractTestSuite))
-}
diff --git a/core/vm/evm/oracle.go b/core/vm/evm/oracle.go
new file mode 100644
index 000000000..1daba822e
--- /dev/null
+++ b/core/vm/evm/oracle.go
@@ -0,0 +1,89 @@
+// Copyright 2019 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 evm
+
+import (
+ "strings"
+
+ "github.com/dexon-foundation/dexon/accounts/abi"
+ "github.com/dexon-foundation/dexon/common"
+ "github.com/dexon-foundation/dexon/core/vm"
+)
+
+var GovernanceContractAddress = common.HexToAddress("63751838d6485578b23e8b051d40861ecc416794")
+
+var GovernanceABI *OracleContractABI
+
+func init() {
+ GovernanceABI = NewOracleContractABI(GovernanceABIJSON)
+}
+
+// OracleContract represent special system contracts written in Go.
+type OracleContract interface {
+ Run(evm *EVM, input []byte, contract *vm.Contract) (ret []byte, err error)
+}
+
+// A map representing available system oracle contracts.
+var OracleContracts = map[common.Address]func() OracleContract{
+ GovernanceContractAddress: func() OracleContract {
+ return &GovernanceContract{
+ coreDKGUtils: &defaultCoreDKGUtils{},
+ }
+ },
+}
+
+// Run oracle contract.
+func RunOracleContract(oracle OracleContract, evm *EVM, input []byte, contract *vm.Contract) (ret []byte, err error) {
+ return oracle.Run(evm, input, contract)
+}
+
+// OracleContractABI represents ABI information for a given contract.
+type OracleContractABI struct {
+ ABI abi.ABI
+ Name2Method map[string]abi.Method
+ Sig2Method map[string]abi.Method
+ Events map[string]abi.Event
+}
+
+// NewOracleContractABI parse the ABI.
+func NewOracleContractABI(abiDefinition string) *OracleContractABI {
+ abiObject, err := abi.JSON(strings.NewReader(abiDefinition))
+ if err != nil {
+ panic(err)
+ }
+
+ sig2Method := make(map[string]abi.Method)
+ name2Method := make(map[string]abi.Method)
+
+ for _, method := range abiObject.Methods {
+ sig2Method[string(method.Id())] = method
+ name2Method[method.Name] = method
+ }
+
+ events := make(map[string]abi.Event)
+ for _, event := range abiObject.Events {
+ events[event.Name] = event
+ }
+
+ return &OracleContractABI{
+ ABI: abiObject,
+ Name2Method: name2Method,
+ Sig2Method: sig2Method,
+ Events: events,
+ }
+}
diff --git a/core/vm/evm/governance_abi.go b/core/vm/evm/oracle_contract_abi.go
index 966c4c4f3..3e7fc8784 100644
--- a/core/vm/evm/governance_abi.go
+++ b/core/vm/evm/oracle_contract_abi.go
@@ -28,40 +28,13 @@ const GovernanceABIJSON = `
{
"name": "",
"type": "address"
- },
- {
- "name": "",
- "type": "address"
- }
- ],
- "name": "delegatorsOffset",
- "outputs": [
- {
- "name": "",
- "type": "int256"
}
],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [
- {
- "name": "",
- "type": "uint256"
- },
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "name": "dkgComplaints",
+ "name": "dkgSuccesses",
"outputs": [
{
"name": "",
- "type": "bytes"
+ "type": "bool"
}
],
"payable": false,
@@ -85,20 +58,6 @@ const GovernanceABIJSON = `
{
"constant": true,
"inputs": [],
- "name": "dkgSetSize",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [],
"name": "totalSupply",
"outputs": [
{
@@ -151,6 +110,14 @@ const GovernanceABIJSON = `
{
"name": "url",
"type": "string"
+ },
+ {
+ "name": "unstaked",
+ "type": "uint256"
+ },
+ {
+ "name": "unstakedAt",
+ "type": "uint256"
}
],
"payable": false,
@@ -160,7 +127,7 @@ const GovernanceABIJSON = `
{
"constant": true,
"inputs": [],
- "name": "miningVelocity",
+ "name": "notaryParamBeta",
"outputs": [
{
"name": "",
@@ -174,7 +141,7 @@ const GovernanceABIJSON = `
{
"constant": true,
"inputs": [],
- "name": "lambdaBA",
+ "name": "miningVelocity",
"outputs": [
{
"name": "",
@@ -188,7 +155,7 @@ const GovernanceABIJSON = `
{
"constant": true,
"inputs": [],
- "name": "minStake",
+ "name": "lambdaBA",
"outputs": [
{
"name": "",
@@ -201,17 +168,12 @@ const GovernanceABIJSON = `
},
{
"constant": true,
- "inputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "name": "crs",
+ "inputs": [],
+ "name": "minStake",
"outputs": [
{
"name": "",
- "type": "bytes32"
+ "type": "uint256"
}
],
"payable": false,
@@ -221,7 +183,7 @@ const GovernanceABIJSON = `
{
"constant": true,
"inputs": [],
- "name": "phiRatio",
+ "name": "crsRound",
"outputs": [
{
"name": "",
@@ -234,13 +196,22 @@ const GovernanceABIJSON = `
},
{
"constant": true,
- "inputs": [
+ "inputs": [],
+ "name": "notaryParamAlpha",
+ "outputs": [
{
"name": "",
"type": "uint256"
}
],
- "name": "dkgMPKReadysCount",
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "dkgSuccessesCount",
"outputs": [
{
"name": "",
@@ -256,14 +227,10 @@ const GovernanceABIJSON = `
"inputs": [
{
"name": "",
- "type": "uint256"
- },
- {
- "name": "",
"type": "address"
}
],
- "name": "dkgMPKReadys",
+ "name": "dkgFinalizeds",
"outputs": [
{
"name": "",
@@ -276,28 +243,25 @@ const GovernanceABIJSON = `
},
{
"constant": true,
- "inputs": [
- {
- "name": "",
- "type": "address"
- },
+ "inputs": [],
+ "name": "blockGasLimit",
+ "outputs": [
{
"name": "",
"type": "uint256"
}
],
- "name": "delegators",
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "dkgRound",
"outputs": [
{
- "name": "owner",
- "type": "address"
- },
- {
- "name": "value",
- "type": "uint256"
- },
- {
- "name": "undelegated_at",
+ "name": "",
"type": "uint256"
}
],
@@ -308,7 +272,7 @@ const GovernanceABIJSON = `
{
"constant": true,
"inputs": [],
- "name": "blockGasLimit",
+ "name": "totalStaked",
"outputs": [
{
"name": "",
@@ -324,10 +288,10 @@ const GovernanceABIJSON = `
"inputs": [
{
"name": "",
- "type": "bytes32"
+ "type": "address"
}
],
- "name": "nodesOffsetByID",
+ "name": "nodesOffsetByAddress",
"outputs": [
{
"name": "",
@@ -341,7 +305,21 @@ const GovernanceABIJSON = `
{
"constant": true,
"inputs": [],
- "name": "totalStaked",
+ "name": "crs",
+ "outputs": [
+ {
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "roundLength",
"outputs": [
{
"name": "",
@@ -355,7 +333,7 @@ const GovernanceABIJSON = `
{
"constant": true,
"inputs": [],
- "name": "roundInterval",
+ "name": "nextHalvingSupply",
"outputs": [
{
"name": "",
@@ -371,14 +349,14 @@ const GovernanceABIJSON = `
"inputs": [
{
"name": "",
- "type": "address"
+ "type": "uint256"
}
],
- "name": "nodesOffsetByAddress",
+ "name": "dkgComplaints",
"outputs": [
{
"name": "",
- "type": "int256"
+ "type": "bytes"
}
],
"payable": false,
@@ -388,11 +366,11 @@ const GovernanceABIJSON = `
{
"constant": true,
"inputs": [],
- "name": "nextHalvingSupply",
+ "name": "owner",
"outputs": [
{
"name": "",
- "type": "uint256"
+ "type": "address"
}
],
"payable": false,
@@ -401,14 +379,38 @@ const GovernanceABIJSON = `
},
{
"constant": true,
- "inputs": [],
- "name": "owner",
+ "inputs": [
+ {
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "name": "dkgMasterPublicKeyOffset",
"outputs": [
{
"name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "",
"type": "address"
}
],
+ "name": "dkgMPKReadys",
+ "outputs": [
+ {
+ "name": "",
+ "type": "bool"
+ }
+ ],
"payable": false,
"stateMutability": "view",
"type": "function"
@@ -501,7 +503,7 @@ const GovernanceABIJSON = `
{
"constant": true,
"inputs": [],
- "name": "minBlockInterval",
+ "name": "dkgMPKReadysCount",
"outputs": [
{
"name": "",
@@ -515,7 +517,7 @@ const GovernanceABIJSON = `
{
"constant": true,
"inputs": [],
- "name": "k",
+ "name": "minBlockInterval",
"outputs": [
{
"name": "",
@@ -532,10 +534,6 @@ const GovernanceABIJSON = `
{
"name": "",
"type": "uint256"
- },
- {
- "name": "",
- "type": "uint256"
}
],
"name": "dkgMasterPublicKeys",
@@ -554,18 +552,28 @@ const GovernanceABIJSON = `
"inputs": [
{
"name": "",
- "type": "uint256"
- },
+ "type": "address"
+ }
+ ],
+ "name": "lastProposedHeight",
+ "outputs": [
{
"name": "",
- "type": "address"
+ "type": "uint256"
}
],
- "name": "dkgFinalizeds",
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "minGasPrice",
"outputs": [
{
"name": "",
- "type": "bool"
+ "type": "uint256"
}
],
"payable": false,
@@ -575,7 +583,7 @@ const GovernanceABIJSON = `
{
"constant": true,
"inputs": [],
- "name": "numChains",
+ "name": "dkgFinalizedsCount",
"outputs": [
{
"name": "",
@@ -588,6 +596,44 @@ const GovernanceABIJSON = `
},
{
"constant": true,
+ "inputs": [
+ {
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "name": "dkgComplaintsProposed",
+ "outputs": [
+ {
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "nodesOffsetByNodeKeyAddress",
+ "outputs": [
+ {
+ "name": "",
+ "type": "int256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
"inputs": [],
"name": "lockupPeriod",
"outputs": [
@@ -608,7 +654,7 @@ const GovernanceABIJSON = `
"type": "uint256"
}
],
- "name": "dkgFinalizedsCount",
+ "name": "dkgResetCount",
"outputs": [
{
"name": "",
@@ -649,9 +695,14 @@ const GovernanceABIJSON = `
"indexed": true,
"name": "NodeAddress",
"type": "address"
+ },
+ {
+ "indexed": true,
+ "name": "NewOwnerAddress",
+ "type": "address"
}
],
- "name": "Staked",
+ "name": "NodeOwnershipTransfered",
"type": "event"
},
{
@@ -661,9 +712,14 @@ const GovernanceABIJSON = `
"indexed": true,
"name": "NodeAddress",
"type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "PublicKey",
+ "type": "bytes"
}
],
- "name": "Unstaked",
+ "name": "NodePublicKeyReplaced",
"type": "event"
},
{
@@ -675,17 +731,12 @@ const GovernanceABIJSON = `
"type": "address"
},
{
- "indexed": true,
- "name": "DelegatorAddress",
- "type": "address"
- },
- {
"indexed": false,
"name": "Amount",
"type": "uint256"
}
],
- "name": "Delegated",
+ "name": "Staked",
"type": "event"
},
{
@@ -697,12 +748,12 @@ const GovernanceABIJSON = `
"type": "address"
},
{
- "indexed": true,
- "name": "DelegatorAddress",
- "type": "address"
+ "indexed": false,
+ "name": "Amount",
+ "type": "uint256"
}
],
- "name": "Undelegated",
+ "name": "Unstaked",
"type": "event"
},
{
@@ -729,6 +780,30 @@ const GovernanceABIJSON = `
"indexed": true,
"name": "NodeAddress",
"type": "address"
+ }
+ ],
+ "name": "NodeAdded",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "NodeAddress",
+ "type": "address"
+ }
+ ],
+ "name": "NodeRemoved",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "NodeAddress",
+ "type": "address"
},
{
"indexed": false,
@@ -746,7 +821,7 @@ const GovernanceABIJSON = `
"type": "bytes"
}
],
- "name": "ForkReported",
+ "name": "Reported",
"type": "event"
},
{
@@ -784,10 +859,27 @@ const GovernanceABIJSON = `
"type": "event"
},
{
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "Round",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "name": "BlockHeight",
+ "type": "uint256"
+ }
+ ],
+ "name": "DKGReset",
+ "type": "event"
+ },
+ {
"constant": false,
"inputs": [
{
- "name": "newOwner",
+ "name": "NewOwner",
"type": "address"
}
],
@@ -809,15 +901,7 @@ const GovernanceABIJSON = `
"type": "uint256"
},
{
- "name": "MiningVelocity",
- "type": "uint256"
- },
- {
- "name": "NextHalvingSupply",
- "type": "uint256"
- },
- {
- "name": "LastHalvingAmount",
+ "name": "MinGasPrice",
"type": "uint256"
},
{
@@ -825,10 +909,6 @@ const GovernanceABIJSON = `
"type": "uint256"
},
{
- "name": "NumChains",
- "type": "uint256"
- },
- {
"name": "LambdaBA",
"type": "uint256"
},
@@ -837,23 +917,15 @@ const GovernanceABIJSON = `
"type": "uint256"
},
{
- "name": "K",
+ "name": "NotaryParamAlpha",
"type": "uint256"
},
{
- "name": "PhiRatio",
+ "name": "NotaryParamBeta",
"type": "uint256"
},
{
- "name": "NotarySetSize",
- "type": "uint256"
- },
- {
- "name": "DKGSetSize",
- "type": "uint256"
- },
- {
- "name": "RoundInterval",
+ "name": "RoundLength",
"type": "uint256"
},
{
@@ -872,57 +944,66 @@ const GovernanceABIJSON = `
"type": "function"
},
{
- "constant": true,
- "inputs": [],
- "name": "nodesLength",
- "outputs": [
+ "constant": false,
+ "inputs": [
{
- "name": "",
- "type": "uint256"
+ "name": "NewOwner",
+ "type": "address"
}
],
+ "name": "transferNodeOwnership",
+ "outputs": [],
"payable": false,
- "stateMutability": "view",
+ "stateMutability": "nonpayable",
"type": "function"
},
{
- "constant": true,
+ "constant": false,
"inputs": [
{
- "name": "NodeAddress",
+ "name": "OldOwner",
"type": "address"
- }
- ],
- "name": "delegatorsLength",
- "outputs": [
+ },
{
- "name": "",
- "type": "uint256"
+ "name": "NewOwner",
+ "type": "address"
}
],
+ "name": "transferNodeOwnershipByFoundation",
+ "outputs": [],
"payable": false,
- "stateMutability": "view",
+ "stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
- "name": "Round",
- "type": "uint256"
- },
- {
- "name": "Height",
- "type": "uint256"
+ "name": "NewPublicKey",
+ "type": "bytes"
}
],
- "name": "snapshotRound",
+ "name": "replaceNodePublicKey",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
+ "constant": true,
+ "inputs": [],
+ "name": "nodesLength",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
"constant": false,
"inputs": [
{
@@ -944,10 +1025,6 @@ const GovernanceABIJSON = `
"constant": false,
"inputs": [
{
- "name": "Round",
- "type": "uint256"
- },
- {
"name": "Complaint",
"type": "bytes"
}
@@ -962,10 +1039,6 @@ const GovernanceABIJSON = `
"constant": false,
"inputs": [
{
- "name": "Round",
- "type": "uint256"
- },
- {
"name": "PublicKey",
"type": "bytes"
}
@@ -980,10 +1053,6 @@ const GovernanceABIJSON = `
"constant": false,
"inputs": [
{
- "name": "Round",
- "type": "uint256"
- },
- {
"name": "MPKReady",
"type": "bytes"
}
@@ -998,10 +1067,6 @@ const GovernanceABIJSON = `
"constant": false,
"inputs": [
{
- "name": "Round",
- "type": "uint256"
- },
- {
"name": "Finalize",
"type": "bytes"
}
@@ -1016,6 +1081,20 @@ const GovernanceABIJSON = `
"constant": false,
"inputs": [
{
+ "name": "Success",
+ "type": "bytes"
+ }
+ ],
+ "name": "addDKGSuccess",
+ "outputs": [],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
"name": "PublicKey",
"type": "bytes"
},
@@ -1036,7 +1115,7 @@ const GovernanceABIJSON = `
"type": "string"
}
],
- "name": "stake",
+ "name": "register",
"outputs": [],
"payable": true,
"stateMutability": "payable",
@@ -1045,52 +1124,47 @@ const GovernanceABIJSON = `
{
"constant": false,
"inputs": [],
- "name": "unstake",
+ "name": "stake",
"outputs": [],
- "payable": false,
- "stateMutability": "nonpayable",
+ "payable": true,
+ "stateMutability": "payable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
- "name": "NodeAddress",
- "type": "address"
+ "name": "Amount",
+ "type": "uint256"
}
],
- "name": "delegate",
+ "name": "unstake",
"outputs": [],
- "payable": true,
- "stateMutability": "payable",
+ "payable": false,
+ "stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
- "inputs": [
- {
- "name": "NodeAddress",
- "type": "address"
- }
- ],
- "name": "undelegate",
+ "inputs": [],
+ "name": "withdraw",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
- "constant": false,
- "inputs": [
+ "constant": true,
+ "inputs": [],
+ "name": "withdrawable",
+ "outputs": [
{
- "name": "NodeAddress",
- "type": "address"
+ "name": "",
+ "type": "bool"
}
],
- "name": "withdraw",
- "outputs": [],
"payable": false,
- "stateMutability": "nonpayable",
+ "stateMutability": "view",
"type": "function"
},
{
@@ -1128,6 +1202,20 @@ const GovernanceABIJSON = `
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "NewSignedCRS",
+ "type": "bytes"
+ }
+ ],
+ "name": "resetDKG",
+ "outputs": [],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "function"
}
]
`
diff --git a/core/vm/evm/oracle_contracts.go b/core/vm/evm/oracle_contracts.go
new file mode 100644
index 000000000..4a13198e2
--- /dev/null
+++ b/core/vm/evm/oracle_contracts.go
@@ -0,0 +1,2885 @@
+// 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 evm
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "math"
+ "math/big"
+ "sort"
+ "sync/atomic"
+
+ "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/core/vm"
+ "github.com/dexon-foundation/dexon/crypto"
+ "github.com/dexon-foundation/dexon/params"
+ "github.com/dexon-foundation/dexon/rlp"
+
+ 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"
+ coreUtils "github.com/dexon-foundation/dexon-consensus/core/utils"
+
+ "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"
+)
+
+type Bytes32 [32]byte
+
+type FineType uint64
+
+const (
+ FineTypeFailStop = iota
+ FineTypeFailStopDKG
+ FineTypeInvalidDKG
+ FineTypeForkVote
+ FineTypeForkBlock
+)
+
+const GovernanceActionGasCost = 200000
+
+// Storage position enums.
+const (
+ roundHeightLoc = iota
+ totalSupplyLoc
+ totalStakedLoc
+ nodesLoc
+ nodesOffsetByAddressLoc
+ nodesOffsetByNodeKeyAddressLoc
+ lastProposedHeightLoc
+ crsRoundLoc
+ crsLoc
+ dkgRoundLoc
+ dkgResetCountLoc
+ dkgMasterPublicKeysLoc
+ dkgMasterPublicKeyOffsetLoc
+ dkgComplaintsLoc
+ dkgComplaintsProposedLoc
+ dkgReadyLoc
+ dkgReadysCountLoc
+ dkgFinalizedLoc
+ dkgFinalizedsCountLoc
+ dkgSuccessLoc
+ dkgSuccessesCountLoc
+ ownerLoc
+ minStakeLoc
+ lockupPeriodLoc
+ miningVelocityLoc
+ nextHalvingSupplyLoc
+ lastHalvedAmountLoc
+ minGasPriceLoc
+ blockGasLimitLoc
+ lambdaBALoc
+ lambdaDKGLoc
+ notarySetSizeLoc
+ notaryParamAlphaLoc
+ notaryParamBetaLoc
+ roundLengthLoc
+ minBlockIntervalLoc
+ fineValuesLoc
+ finedRecordsLoc
+)
+
+func publicKeyToNodeKeyAddress(pkBytes []byte) (common.Address, error) {
+ pk, err := crypto.UnmarshalPubkey(pkBytes)
+ if err != nil {
+ return common.Address{}, err
+ }
+ return crypto.PubkeyToAddress(*pk), nil
+}
+
+func getDKGMasterPublicKeyID(mpk *dkgTypes.MasterPublicKey) Bytes32 {
+ return Bytes32(mpk.ProposerID.Hash)
+}
+
+func getDKGComplaintID(comp *dkgTypes.Complaint) Bytes32 {
+ return Bytes32(crypto.Keccak256Hash(
+ comp.ProposerID.Hash[:],
+ comp.PrivateShare.ProposerID.Hash[:],
+ []byte(fmt.Sprintf("%v", comp.IsNack()))))
+}
+
+func IdToAddress(id coreTypes.NodeID) common.Address {
+ return common.BytesToAddress(id.Hash[12:])
+}
+
+// State manipulation helper fro the governance contract.
+type GovernanceState struct {
+ StateDB vm.StateDB
+}
+
+func (s *GovernanceState) getState(loc common.Hash) common.Hash {
+ return s.StateDB.GetState(GovernanceContractAddress, loc)
+}
+
+func (s *GovernanceState) setState(loc common.Hash, val common.Hash) {
+ s.StateDB.SetState(GovernanceContractAddress, loc, val)
+}
+
+func (s *GovernanceState) getStateBigInt(loc *big.Int) *big.Int {
+ res := s.StateDB.GetState(GovernanceContractAddress, common.BigToHash(loc))
+ return new(big.Int).SetBytes(res.Bytes())
+}
+
+func (s *GovernanceState) setStateBigInt(loc *big.Int, val *big.Int) {
+ s.setState(common.BigToHash(loc), common.BigToHash(val))
+}
+
+func (s *GovernanceState) getSlotLoc(loc *big.Int) *big.Int {
+ return new(big.Int).SetBytes(crypto.Keccak256(common.BigToHash(loc).Bytes()))
+}
+
+func (s *GovernanceState) getMapLoc(pos *big.Int, key []byte) *big.Int {
+ return new(big.Int).SetBytes(crypto.Keccak256(key, common.BigToHash(pos).Bytes()))
+}
+
+func (s *GovernanceState) 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 continuously 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 *GovernanceState) writeBytes(loc *big.Int, data []byte) {
+ length := int64(len(data))
+
+ if length == 0 {
+ s.setState(common.BigToHash(loc), common.Hash{})
+ return
+ }
+
+ // 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 *GovernanceState) eraseBytes(loc *big.Int) {
+ // 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 {
+ s.setStateBigInt(loc, big.NewInt(0))
+ return
+ }
+
+ // Actual length = (rawLength - 1) / 2
+ length := new(big.Int).Div(new(big.Int).Sub(
+ rawLength, big.NewInt(1)), big.NewInt(2)).Uint64()
+
+ // Fill 0.
+ s.writeBytes(loc, make([]byte, length))
+
+ // Clear slot.
+ s.setStateBigInt(loc, big.NewInt(0))
+}
+
+func (s *GovernanceState) read1DByteArray(loc *big.Int) [][]byte {
+ 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 *GovernanceState) appendTo1DByteArray(loc *big.Int, data []byte) {
+ // 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)
+}
+
+func (s *GovernanceState) erase1DByteArray(loc *big.Int) {
+ arrayLength := s.getStateBigInt(loc)
+ dataLoc := s.getSlotLoc(loc)
+
+ for i := int64(0); i < int64(arrayLength.Uint64()); i++ {
+ elementLoc := new(big.Int).Add(dataLoc, big.NewInt(i))
+ s.eraseBytes(elementLoc)
+ }
+ s.setStateBigInt(loc, big.NewInt(0))
+}
+
+// uint256[] public roundHeight;
+func (s *GovernanceState) 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 *GovernanceState) 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)
+}
+
+// uint256 public totalSupply;
+func (s *GovernanceState) TotalSupply() *big.Int {
+ return s.getStateBigInt(big.NewInt(totalSupplyLoc))
+}
+func (s *GovernanceState) IncTotalSupply(amount *big.Int) {
+ s.setStateBigInt(big.NewInt(totalSupplyLoc), new(big.Int).Add(s.TotalSupply(), amount))
+}
+func (s *GovernanceState) DecTotalSupply(amount *big.Int) {
+ s.setStateBigInt(big.NewInt(totalSupplyLoc), new(big.Int).Sub(s.TotalSupply(), amount))
+}
+
+// uint256 public totalStaked;
+func (s *GovernanceState) TotalStaked() *big.Int {
+ return s.getStateBigInt(big.NewInt(totalStakedLoc))
+}
+func (s *GovernanceState) IncTotalStaked(amount *big.Int) {
+ s.setStateBigInt(big.NewInt(totalStakedLoc), new(big.Int).Add(s.TotalStaked(), amount))
+}
+func (s *GovernanceState) DecTotalStaked(amount *big.Int) {
+ s.setStateBigInt(big.NewInt(totalStakedLoc), new(big.Int).Sub(s.TotalStaked(), amount))
+}
+
+// struct Node {
+// address owner;
+// bytes publicKey;
+// uint256 staked;
+// uint256 fined;
+// string name;
+// string email;
+// string location;
+// string url;
+// uint256 unstaked;
+// uint256 unstakedAt;
+// uint256 lastProposedHeight;
+// }
+//
+// Node[] nodes;
+
+type nodeInfo struct {
+ Owner common.Address
+ PublicKey []byte
+ Staked *big.Int
+ Fined *big.Int
+ Name string
+ Email string
+ Location string
+ Url string
+ Unstaked *big.Int
+ UnstakedAt *big.Int
+}
+
+const nodeStructSize = 10
+
+func (s *GovernanceState) LenNodes() *big.Int {
+ return s.getStateBigInt(big.NewInt(nodesLoc))
+}
+func (s *GovernanceState) 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(nodeStructSize)))
+
+ // 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)
+
+ // Fined.
+ loc = new(big.Int).Add(elementBaseLoc, big.NewInt(3))
+ node.Fined = s.getStateBigInt(loc)
+
+ // Name.
+ loc = new(big.Int).Add(elementBaseLoc, big.NewInt(4))
+ node.Name = string(s.readBytes(loc))
+
+ // Email.
+ loc = new(big.Int).Add(elementBaseLoc, big.NewInt(5))
+ node.Email = string(s.readBytes(loc))
+
+ // Location.
+ loc = new(big.Int).Add(elementBaseLoc, big.NewInt(6))
+ node.Location = string(s.readBytes(loc))
+
+ // Url.
+ loc = new(big.Int).Add(elementBaseLoc, big.NewInt(7))
+ node.Url = string(s.readBytes(loc))
+
+ // Unstaked.
+ loc = new(big.Int).Add(elementBaseLoc, big.NewInt(8))
+ node.Unstaked = s.getStateBigInt(loc)
+
+ // UnstakedAt.
+ loc = new(big.Int).Add(elementBaseLoc, big.NewInt(9))
+ node.UnstakedAt = s.getStateBigInt(loc)
+
+ return node
+}
+func (s *GovernanceState) PushNode(n *nodeInfo) {
+ // Increase length by 1.
+ arrayLength := s.LenNodes()
+ s.setStateBigInt(big.NewInt(nodesLoc), new(big.Int).Add(arrayLength, big.NewInt(1)))
+
+ s.UpdateNode(arrayLength, n)
+}
+func (s *GovernanceState) 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(nodeStructSize)))
+
+ // 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)
+
+ // Fined.
+ loc = new(big.Int).Add(elementBaseLoc, big.NewInt(3))
+ s.setStateBigInt(loc, n.Fined)
+
+ // Name.
+ loc = new(big.Int).Add(elementBaseLoc, big.NewInt(4))
+ s.writeBytes(loc, []byte(n.Name))
+
+ // Email.
+ loc = new(big.Int).Add(elementBaseLoc, big.NewInt(5))
+ s.writeBytes(loc, []byte(n.Email))
+
+ // Location.
+ loc = new(big.Int).Add(elementBaseLoc, big.NewInt(6))
+ s.writeBytes(loc, []byte(n.Location))
+
+ // Url.
+ loc = new(big.Int).Add(elementBaseLoc, big.NewInt(7))
+ s.writeBytes(loc, []byte(n.Url))
+
+ // Unstaked.
+ loc = new(big.Int).Add(elementBaseLoc, big.NewInt(8))
+ s.setStateBigInt(loc, n.Unstaked)
+
+ // UnstakedAt.
+ loc = new(big.Int).Add(elementBaseLoc, big.NewInt(9))
+ s.setStateBigInt(loc, n.UnstakedAt)
+
+ // Update set size.
+ s.CalNotarySetSize()
+}
+func (s *GovernanceState) PopLastNode() {
+ // Decrease length by 1.
+ arrayLength := s.LenNodes()
+ newArrayLength := new(big.Int).Sub(arrayLength, big.NewInt(1))
+ s.setStateBigInt(big.NewInt(nodesLoc), newArrayLength)
+
+ s.UpdateNode(newArrayLength, &nodeInfo{
+ Staked: big.NewInt(0),
+ Fined: big.NewInt(0),
+ Unstaked: big.NewInt(0),
+ UnstakedAt: big.NewInt(0),
+ })
+}
+func (s *GovernanceState) Nodes() []*nodeInfo {
+ var nodes []*nodeInfo
+ for i := int64(0); i < int64(s.LenNodes().Uint64()); i++ {
+ nodes = append(nodes, s.Node(big.NewInt(i)))
+ }
+ return nodes
+}
+func (s *GovernanceState) QualifiedNodes() []*nodeInfo {
+ var nodes []*nodeInfo
+ for i := int64(0); i < int64(s.LenNodes().Uint64()); i++ {
+ node := s.Node(big.NewInt(i))
+ // Node with unpaid fine is consider unqualified.
+ if node.Fined.Cmp(big.NewInt(0)) > 0 {
+ continue
+ }
+ if node.Staked.Cmp(s.MinStake()) >= 0 {
+ nodes = append(nodes, node)
+ }
+ }
+ return nodes
+}
+
+// mapping(address => uint256) public nodesOffsetByAddress;
+func (s *GovernanceState) NodesOffsetByAddress(addr common.Address) *big.Int {
+ loc := s.getMapLoc(big.NewInt(nodesOffsetByAddressLoc), addr.Bytes())
+ return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1))
+}
+func (s *GovernanceState) PutNodesOffsetByAddress(addr common.Address, offset *big.Int) {
+ loc := s.getMapLoc(big.NewInt(nodesOffsetByAddressLoc), addr.Bytes())
+ s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1)))
+}
+func (s *GovernanceState) DeleteNodesOffsetByAddress(addr common.Address) {
+ loc := s.getMapLoc(big.NewInt(nodesOffsetByAddressLoc), addr.Bytes())
+ s.setStateBigInt(loc, big.NewInt(0))
+}
+
+// mapping(address => uint256) public nodesOffsetByNodeKeyAddress;
+func (s *GovernanceState) NodesOffsetByNodeKeyAddress(addr common.Address) *big.Int {
+ loc := s.getMapLoc(big.NewInt(nodesOffsetByNodeKeyAddressLoc), addr.Bytes())
+ return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1))
+}
+func (s *GovernanceState) PutNodesOffsetByNodeKeyAddress(addr common.Address, offset *big.Int) {
+ loc := s.getMapLoc(big.NewInt(nodesOffsetByNodeKeyAddressLoc), addr.Bytes())
+ s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1)))
+}
+func (s *GovernanceState) DeleteNodesOffsetByNodeKeyAddress(addr common.Address) {
+ loc := s.getMapLoc(big.NewInt(nodesOffsetByNodeKeyAddressLoc), addr.Bytes())
+ s.setStateBigInt(loc, big.NewInt(0))
+}
+
+func (s *GovernanceState) PutNodeOffsets(n *nodeInfo, offset *big.Int) {
+ address, err := publicKeyToNodeKeyAddress(n.PublicKey)
+ if err != nil {
+ panic(err)
+ }
+ s.PutNodesOffsetByNodeKeyAddress(address, offset)
+ s.PutNodesOffsetByAddress(n.Owner, offset)
+}
+func (s *GovernanceState) DeleteNodeOffsets(n *nodeInfo) {
+ address, err := publicKeyToNodeKeyAddress(n.PublicKey)
+ if err != nil {
+ panic(err)
+ }
+ s.DeleteNodesOffsetByNodeKeyAddress(address)
+ s.DeleteNodesOffsetByAddress(n.Owner)
+}
+
+func (s *GovernanceState) GetNodeByID(id coreTypes.NodeID) (*nodeInfo, error) {
+ offset := s.NodesOffsetByNodeKeyAddress(IdToAddress(id))
+ if offset.Cmp(big.NewInt(0)) < 0 {
+ return nil, errors.New("node not found")
+ }
+ node := s.Node(offset)
+ return node, nil
+}
+
+// mapping(address => uint256) public lastProposedHeight;
+func (s *GovernanceState) LastProposedHeight(addr common.Address) *big.Int {
+ loc := s.getMapLoc(big.NewInt(lastProposedHeightLoc), addr.Bytes())
+ return s.getStateBigInt(loc)
+}
+func (s *GovernanceState) PutLastProposedHeight(addr common.Address, height *big.Int) {
+ loc := s.getMapLoc(big.NewInt(lastProposedHeightLoc), addr.Bytes())
+ s.setStateBigInt(loc, height)
+}
+
+// uint256 public crsRound;
+func (s *GovernanceState) CRSRound() *big.Int {
+ return s.getStateBigInt(big.NewInt(crsRoundLoc))
+}
+func (s *GovernanceState) SetCRSRound(round *big.Int) {
+ s.setStateBigInt(big.NewInt(crsRoundLoc), round)
+}
+
+// bytes32 public crs;
+func (s *GovernanceState) CRS() common.Hash {
+ return s.getState(common.BigToHash(big.NewInt(crsLoc)))
+}
+func (s *GovernanceState) SetCRS(crs common.Hash) {
+ s.setState(common.BigToHash(big.NewInt(crsLoc)), crs)
+}
+
+// uint256 public dkgRound;
+func (s *GovernanceState) DKGRound() *big.Int {
+ return s.getStateBigInt(big.NewInt(dkgRoundLoc))
+}
+func (s *GovernanceState) SetDKGRound(round *big.Int) {
+ s.setStateBigInt(big.NewInt(dkgRoundLoc), round)
+}
+
+// uint256[] public dkgResetCount;
+func (s *GovernanceState) DKGResetCount(round *big.Int) *big.Int {
+ arrayBaseLoc := s.getSlotLoc(big.NewInt(dkgResetCountLoc))
+ return s.getStateBigInt(new(big.Int).Add(arrayBaseLoc, round))
+}
+func (s *GovernanceState) IncDKGResetCount(round *big.Int) {
+ loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgResetCountLoc)), round)
+ count := s.getStateBigInt(loc)
+ s.setStateBigInt(loc, new(big.Int).Add(count, big.NewInt(1)))
+}
+
+// bytes[] public dkgMasterPublicKeys;
+func (s *GovernanceState) LenDKGMasterPublicKeys() *big.Int {
+ return s.getStateBigInt(big.NewInt(dkgMasterPublicKeysLoc))
+}
+func (s *GovernanceState) DKGMasterPublicKey(offset *big.Int) []byte {
+ loc := big.NewInt(dkgMasterPublicKeysLoc)
+ dataLoc := s.getSlotLoc(loc)
+ elementLoc := new(big.Int).Add(dataLoc, offset)
+ return s.readBytes(elementLoc)
+}
+func (s *GovernanceState) DKGMasterPublicKeyItem(offset *big.Int) *dkgTypes.MasterPublicKey {
+ element := s.DKGMasterPublicKey(offset)
+ x := new(dkgTypes.MasterPublicKey)
+ if err := rlp.DecodeBytes(element, x); err != nil {
+ panic(err)
+ }
+ return x
+}
+func (s *GovernanceState) DKGMasterPublicKeys() [][]byte {
+ return s.read1DByteArray(big.NewInt(dkgMasterPublicKeysLoc))
+}
+func (s *GovernanceState) PushDKGMasterPublicKey(mpk []byte) {
+ s.appendTo1DByteArray(big.NewInt(dkgMasterPublicKeysLoc), mpk)
+}
+func (s *GovernanceState) DKGMasterPublicKeyItems() []*dkgTypes.MasterPublicKey {
+ // Prepare DKGMasterPublicKeys.
+ var dkgMasterPKs []*dkgTypes.MasterPublicKey
+ for _, mpk := range s.DKGMasterPublicKeys() {
+ x := new(dkgTypes.MasterPublicKey)
+ if err := rlp.DecodeBytes(mpk, x); err != nil {
+ panic(err)
+ }
+ dkgMasterPKs = append(dkgMasterPKs, x)
+ }
+ return dkgMasterPKs
+}
+func (s *GovernanceState) ClearDKGMasterPublicKeys() {
+ s.erase1DByteArray(big.NewInt(dkgMasterPublicKeysLoc))
+}
+
+// mapping(bytes32 => uint256) public dkgMasterPublicKeyOffset;
+func (s *GovernanceState) DKGMasterPublicKeyOffset(id Bytes32) *big.Int {
+ loc := s.getMapLoc(big.NewInt(dkgMasterPublicKeyOffsetLoc), id[:])
+ return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1))
+}
+func (s *GovernanceState) PutDKGMasterPublicKeyOffset(id Bytes32, offset *big.Int) {
+ loc := s.getMapLoc(big.NewInt(dkgMasterPublicKeyOffsetLoc), id[:])
+ s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1)))
+}
+func (s *GovernanceState) ClearDKGMasterPublicKeyOffset() {
+ for _, mpk := range s.DKGMasterPublicKeyItems() {
+ s.PutDKGMasterPublicKeyOffset(getDKGMasterPublicKeyID(mpk), big.NewInt(-1))
+ }
+}
+
+// bytes[] public dkgComplaints;
+func (s *GovernanceState) LenDKGComplaints() *big.Int {
+ return s.getStateBigInt(big.NewInt(dkgComplaintsLoc))
+}
+func (s *GovernanceState) DKGComplaint(offset *big.Int) []byte {
+ loc := big.NewInt(dkgComplaintsLoc)
+ dataLoc := s.getSlotLoc(loc)
+ elementLoc := new(big.Int).Add(dataLoc, offset)
+ return s.readBytes(elementLoc)
+}
+func (s *GovernanceState) DKGComplaints() [][]byte {
+ return s.read1DByteArray(big.NewInt(dkgComplaintsLoc))
+}
+func (s *GovernanceState) PushDKGComplaint(complaint []byte) {
+ s.appendTo1DByteArray(big.NewInt(dkgComplaintsLoc), complaint)
+}
+func (s *GovernanceState) ClearDKGComplaints() {
+ s.erase1DByteArray(big.NewInt(dkgComplaintsLoc))
+}
+func (s *GovernanceState) DKGComplaintItems() []*dkgTypes.Complaint {
+ var dkgComplaints []*dkgTypes.Complaint
+ for _, pk := range s.DKGComplaints() {
+ x := new(dkgTypes.Complaint)
+ if err := rlp.DecodeBytes(pk, x); err != nil {
+ panic(err)
+ }
+ dkgComplaints = append(dkgComplaints, x)
+ }
+ return dkgComplaints
+}
+
+// mapping(bytes32 => bool) public dkgComplaintsProposed;
+func (s *GovernanceState) DKGComplaintProposed(id Bytes32) bool {
+ loc := s.getMapLoc(big.NewInt(dkgComplaintsProposedLoc), id[:])
+ return s.getStateBigInt(loc).Cmp(big.NewInt(0)) > 0
+}
+func (s *GovernanceState) PutDKGComplaintProposed(id Bytes32, status bool) {
+ loc := s.getMapLoc(big.NewInt(dkgComplaintsProposedLoc), id[:])
+ val := big.NewInt(0)
+ if status {
+ val = big.NewInt(1)
+ }
+ s.setStateBigInt(loc, val)
+}
+func (s *GovernanceState) ClearDKGComplaintProposed() {
+ for _, comp := range s.DKGComplaintItems() {
+ s.PutDKGComplaintProposed(getDKGComplaintID(comp), false)
+ }
+}
+
+// mapping(address => bool) public dkgMPKReadys;
+func (s *GovernanceState) DKGMPKReady(addr common.Address) bool {
+ mapLoc := s.getMapLoc(big.NewInt(dkgReadyLoc), addr.Bytes())
+ return s.getStateBigInt(mapLoc).Cmp(big.NewInt(0)) != 0
+}
+func (s *GovernanceState) PutDKGMPKReady(addr common.Address, ready bool) {
+ mapLoc := s.getMapLoc(big.NewInt(dkgReadyLoc), addr.Bytes())
+ res := big.NewInt(0)
+ if ready {
+ res = big.NewInt(1)
+ }
+ s.setStateBigInt(mapLoc, res)
+}
+func (s *GovernanceState) ClearDKGMPKReadys(notarySet map[coreTypes.NodeID]struct{}) {
+ for id := range notarySet {
+ s.PutDKGMPKReady(IdToAddress(id), false)
+ }
+}
+
+// uint256 public dkgMPKReadysCount;
+func (s *GovernanceState) DKGMPKReadysCount() *big.Int {
+ return s.getStateBigInt(big.NewInt(dkgReadysCountLoc))
+}
+func (s *GovernanceState) IncDKGMPKReadysCount() {
+ s.setStateBigInt(big.NewInt(dkgReadysCountLoc),
+ new(big.Int).Add(s.getStateBigInt(big.NewInt(dkgReadysCountLoc)), big.NewInt(1)))
+}
+func (s *GovernanceState) ResetDKGMPKReadysCount() {
+ s.setStateBigInt(big.NewInt(dkgReadysCountLoc), big.NewInt(0))
+}
+
+// mapping(address => bool) public dkgFinalizeds;
+func (s *GovernanceState) DKGFinalized(addr common.Address) bool {
+ mapLoc := s.getMapLoc(big.NewInt(dkgFinalizedLoc), addr.Bytes())
+ return s.getStateBigInt(mapLoc).Cmp(big.NewInt(0)) != 0
+}
+func (s *GovernanceState) PutDKGFinalized(addr common.Address, finalized bool) {
+ mapLoc := s.getMapLoc(big.NewInt(dkgFinalizedLoc), addr.Bytes())
+ res := big.NewInt(0)
+ if finalized {
+ res = big.NewInt(1)
+ }
+ s.setStateBigInt(mapLoc, res)
+}
+func (s *GovernanceState) ClearDKGFinalizeds(dkgSet map[coreTypes.NodeID]struct{}) {
+ for id := range dkgSet {
+ s.PutDKGFinalized(IdToAddress(id), false)
+ }
+}
+
+// uint256 public dkgFinalizedsCount;
+func (s *GovernanceState) DKGFinalizedsCount() *big.Int {
+ return s.getStateBigInt(big.NewInt(dkgFinalizedsCountLoc))
+}
+func (s *GovernanceState) IncDKGFinalizedsCount() {
+ s.setStateBigInt(big.NewInt(dkgFinalizedsCountLoc),
+ new(big.Int).Add(s.getStateBigInt(big.NewInt(dkgFinalizedsCountLoc)), big.NewInt(1)))
+}
+func (s *GovernanceState) ResetDKGFinalizedsCount() {
+ s.setStateBigInt(big.NewInt(dkgFinalizedsCountLoc), big.NewInt(0))
+}
+
+// mapping(address => bool) public dkgSuccesses;
+func (s *GovernanceState) DKGSuccess(addr common.Address) bool {
+ mapLoc := s.getMapLoc(big.NewInt(dkgSuccessLoc), addr.Bytes())
+ return s.getStateBigInt(mapLoc).Cmp(big.NewInt(0)) != 0
+}
+func (s *GovernanceState) PutDKGSuccess(addr common.Address, success bool) {
+ mapLoc := s.getMapLoc(big.NewInt(dkgSuccessLoc), addr.Bytes())
+ res := big.NewInt(0)
+ if success {
+ res = big.NewInt(1)
+ }
+ s.setStateBigInt(mapLoc, res)
+}
+func (s *GovernanceState) ClearDKGSuccesses(dkgSet map[coreTypes.NodeID]struct{}) {
+ for id := range dkgSet {
+ s.PutDKGSuccess(IdToAddress(id), false)
+ }
+}
+
+// uint256 public dkgSuccessesCount;
+func (s *GovernanceState) DKGSuccessesCount() *big.Int {
+ return s.getStateBigInt(big.NewInt(dkgSuccessesCountLoc))
+}
+func (s *GovernanceState) IncDKGSuccessesCount() {
+ s.setStateBigInt(big.NewInt(dkgSuccessesCountLoc),
+ new(big.Int).Add(s.getStateBigInt(big.NewInt(dkgSuccessesCountLoc)), big.NewInt(1)))
+}
+func (s *GovernanceState) ResetDKGSuccessesCount() {
+ s.setStateBigInt(big.NewInt(dkgSuccessesCountLoc), big.NewInt(0))
+}
+
+// address public owner;
+func (s *GovernanceState) Owner() common.Address {
+ val := s.getState(common.BigToHash(big.NewInt(ownerLoc)))
+ return common.BytesToAddress(val.Bytes())
+}
+func (s *GovernanceState) SetOwner(newOwner common.Address) {
+ s.setState(common.BigToHash(big.NewInt(ownerLoc)), newOwner.Hash())
+}
+
+// uint256 public minStake;
+func (s *GovernanceState) MinStake() *big.Int {
+ return s.getStateBigInt(big.NewInt(minStakeLoc))
+}
+
+// uint256 public lockupPeriod;
+func (s *GovernanceState) LockupPeriod() *big.Int {
+ return s.getStateBigInt(big.NewInt(lockupPeriodLoc))
+}
+
+// uint256 public miningVelocity;
+func (s *GovernanceState) MiningVelocity() *big.Int {
+ return s.getStateBigInt(big.NewInt(miningVelocityLoc))
+}
+func (s *GovernanceState) HalfMiningVelocity() {
+ s.setStateBigInt(big.NewInt(miningVelocityLoc),
+ new(big.Int).Div(s.MiningVelocity(), big.NewInt(2)))
+}
+
+// uint256 public nextHalvingSupply;
+func (s *GovernanceState) NextHalvingSupply() *big.Int {
+ return s.getStateBigInt(big.NewInt(nextHalvingSupplyLoc))
+}
+func (s *GovernanceState) IncNextHalvingSupply(amount *big.Int) {
+ s.setStateBigInt(big.NewInt(nextHalvingSupplyLoc),
+ new(big.Int).Add(s.NextHalvingSupply(), amount))
+}
+
+// uint256 public lastHalvedAmount;
+func (s *GovernanceState) LastHalvedAmount() *big.Int {
+ return s.getStateBigInt(big.NewInt(lastHalvedAmountLoc))
+}
+func (s *GovernanceState) HalfLastHalvedAmount() {
+ s.setStateBigInt(big.NewInt(lastHalvedAmountLoc),
+ new(big.Int).Div(s.LastHalvedAmount(), big.NewInt(2)))
+}
+func (s *GovernanceState) MiningHalved() {
+ s.HalfMiningVelocity()
+ s.HalfLastHalvedAmount()
+ s.IncNextHalvingSupply(s.LastHalvedAmount())
+}
+
+// uint256 public minGasPrice;
+func (s *GovernanceState) MinGasPrice() *big.Int {
+ return s.getStateBigInt(big.NewInt(minGasPriceLoc))
+}
+
+// uint256 public blockGasLimit;
+func (s *GovernanceState) BlockGasLimit() *big.Int {
+ return s.getStateBigInt(big.NewInt(blockGasLimitLoc))
+}
+func (s *GovernanceState) SetBlockGasLimit(reward *big.Int) {
+ s.setStateBigInt(big.NewInt(blockGasLimitLoc), reward)
+}
+
+// uint256 public lambdaBA;
+func (s *GovernanceState) LambdaBA() *big.Int {
+ return s.getStateBigInt(big.NewInt(lambdaBALoc))
+}
+
+// uint256 public lambdaDKG;
+func (s *GovernanceState) LambdaDKG() *big.Int {
+ return s.getStateBigInt(big.NewInt(lambdaDKGLoc))
+}
+
+// uint256 public notarySetSize;
+func (s *GovernanceState) NotarySetSize() *big.Int {
+ return s.getStateBigInt(big.NewInt(notarySetSizeLoc))
+}
+func (s *GovernanceState) CalNotarySetSize() {
+ nodeSetSize := float64(len(s.QualifiedNodes()))
+ setSize := math.Ceil((nodeSetSize*0.6-1)/3)*3 + 1
+
+ if nodeSetSize >= 80 {
+ alpha := float64(s.NotaryParamAlpha().Uint64()) / decimalMultiplier
+ beta := float64(s.NotaryParamBeta().Uint64()) / decimalMultiplier
+ setSize = math.Ceil(alpha*math.Log(nodeSetSize) - beta)
+ }
+ s.setStateBigInt(big.NewInt(notarySetSizeLoc), big.NewInt(int64(setSize)))
+}
+
+// uint256 public notaryParamAlpha;
+func (s *GovernanceState) NotaryParamAlpha() *big.Int {
+ return s.getStateBigInt(big.NewInt(notaryParamAlphaLoc))
+}
+
+// uint256 public notaryParamBeta;
+func (s *GovernanceState) NotaryParamBeta() *big.Int {
+ return s.getStateBigInt(big.NewInt(notaryParamBetaLoc))
+}
+
+// uint256 public roundLength;
+func (s *GovernanceState) RoundLength() *big.Int {
+ return s.getStateBigInt(big.NewInt(roundLengthLoc))
+}
+
+// uint256 public minBlockInterval;
+func (s *GovernanceState) MinBlockInterval() *big.Int {
+ return s.getStateBigInt(big.NewInt(minBlockIntervalLoc))
+}
+
+// uint256[] public fineValues;
+func (s *GovernanceState) FineValue(index *big.Int) *big.Int {
+ arrayBaseLoc := s.getSlotLoc(big.NewInt(fineValuesLoc))
+ return s.getStateBigInt(new(big.Int).Add(arrayBaseLoc, index))
+}
+func (s *GovernanceState) FineValues() []*big.Int {
+ len := s.getStateBigInt(big.NewInt(fineValuesLoc))
+ result := make([]*big.Int, len.Uint64())
+ for i := 0; i < int(len.Uint64()); i++ {
+ result[i] = s.FineValue(big.NewInt(int64(i)))
+ }
+ return result
+}
+func (s *GovernanceState) SetFineValues(values []*big.Int) {
+ s.setStateBigInt(big.NewInt(fineValuesLoc), big.NewInt(int64(len(values))))
+
+ arrayBaseLoc := s.getSlotLoc(big.NewInt(fineValuesLoc))
+ for i, v := range values {
+ s.setStateBigInt(new(big.Int).Add(arrayBaseLoc, big.NewInt(int64(i))), v)
+ }
+}
+
+// mapping(bytes32 => bool) public fineRdecords;
+func (s *GovernanceState) FineRecords(recordHash Bytes32) bool {
+ loc := s.getMapLoc(big.NewInt(finedRecordsLoc), recordHash[:])
+ return s.getStateBigInt(loc).Cmp(big.NewInt(0)) > 0
+}
+func (s *GovernanceState) SetFineRecords(recordHash Bytes32, status bool) {
+ loc := s.getMapLoc(big.NewInt(finedRecordsLoc), recordHash[:])
+ value := int64(0)
+ if status {
+ value = int64(1)
+ }
+ s.setStateBigInt(loc, big.NewInt(value))
+}
+
+// Initialize initializes governance contract state.
+func (s *GovernanceState) Initialize(config *params.DexconConfig, totalSupply *big.Int) {
+ if config.NextHalvingSupply.Cmp(totalSupply) <= 0 {
+ panic(fmt.Sprintf("invalid genesis found, totalSupply: %s, nextHavlingSupply: %s",
+ totalSupply, config.NextHalvingSupply))
+ }
+
+ // Genesis CRS.
+ crs := crypto.Keccak256Hash([]byte(config.GenesisCRSText))
+ s.SetCRS(crs)
+
+ // Round 0 height.
+ s.PushRoundHeight(big.NewInt(0))
+
+ // Owner.
+ s.SetOwner(config.Owner)
+
+ // Governance configuration.
+ s.UpdateConfiguration(config)
+
+ // Set totalSupply.
+ s.IncTotalSupply(totalSupply)
+
+ // Set DKGRound.
+ s.SetDKGRound(big.NewInt(int64(dexCore.DKGDelayRound)))
+}
+
+// Register is a helper function for creating genesis state.
+func (s *GovernanceState) Register(
+ addr common.Address, publicKey []byte,
+ name, email, location, url string, staked *big.Int) {
+ offset := s.LenNodes()
+ node := &nodeInfo{
+ Owner: addr,
+ PublicKey: publicKey,
+ Staked: staked,
+ Fined: big.NewInt(0),
+ Name: name,
+ Email: email,
+ Location: location,
+ Url: url,
+ Unstaked: big.NewInt(0),
+ UnstakedAt: big.NewInt(0),
+ }
+ s.PushNode(node)
+ s.PutNodeOffsets(node, offset)
+
+ if staked.Cmp(big.NewInt(0)) == 0 {
+ return
+ }
+
+ // Add to network total staked.
+ s.IncTotalStaked(staked)
+}
+
+func (s *GovernanceState) Disqualify(n *nodeInfo) error {
+ nodeAddr, err := publicKeyToNodeKeyAddress(n.PublicKey)
+ if err != nil {
+ return err
+ }
+
+ // Node might already been unstaked in the latest state.
+ offset := s.NodesOffsetByNodeKeyAddress(nodeAddr)
+ if offset.Cmp(big.NewInt(0)) < 0 {
+ return errors.New("node does not exist")
+ }
+
+ // Set fined value.
+ node := s.Node(offset)
+ amount := s.FineValue(big.NewInt(FineTypeFailStop))
+ node.Fined = new(big.Int).Add(node.Fined, amount)
+ s.UpdateNode(offset, node)
+
+ return nil
+}
+
+const decimalMultiplier = 100000000.0
+
+// Configuration returns the current configuration.
+func (s *GovernanceState) Configuration() *params.DexconConfig {
+ return &params.DexconConfig{
+ MinStake: s.getStateBigInt(big.NewInt(minStakeLoc)),
+ LockupPeriod: s.getStateBigInt(big.NewInt(lockupPeriodLoc)).Uint64(),
+ MiningVelocity: float32(s.getStateBigInt(big.NewInt(miningVelocityLoc)).Uint64()) / decimalMultiplier,
+ NextHalvingSupply: s.getStateBigInt(big.NewInt(nextHalvingSupplyLoc)),
+ LastHalvedAmount: s.getStateBigInt(big.NewInt(lastHalvedAmountLoc)),
+ MinGasPrice: s.getStateBigInt(big.NewInt(minGasPriceLoc)),
+ BlockGasLimit: s.getStateBigInt(big.NewInt(blockGasLimitLoc)).Uint64(),
+ LambdaBA: s.getStateBigInt(big.NewInt(lambdaBALoc)).Uint64(),
+ LambdaDKG: s.getStateBigInt(big.NewInt(lambdaDKGLoc)).Uint64(),
+ NotarySetSize: uint32(s.getStateBigInt(big.NewInt(notarySetSizeLoc)).Uint64()),
+ NotaryParamAlpha: float32(s.getStateBigInt(big.NewInt(notaryParamAlphaLoc)).Uint64()) / decimalMultiplier,
+ NotaryParamBeta: float32(s.getStateBigInt(big.NewInt(notaryParamBetaLoc)).Uint64()) / decimalMultiplier,
+ RoundLength: s.getStateBigInt(big.NewInt(roundLengthLoc)).Uint64(),
+ MinBlockInterval: s.getStateBigInt(big.NewInt(minBlockIntervalLoc)).Uint64(),
+ FineValues: s.FineValues(),
+ }
+}
+
+// UpdateConfiguration updates system configuration.
+func (s *GovernanceState) UpdateConfiguration(cfg *params.DexconConfig) {
+ s.setStateBigInt(big.NewInt(minStakeLoc), cfg.MinStake)
+ s.setStateBigInt(big.NewInt(lockupPeriodLoc), big.NewInt(int64(cfg.LockupPeriod)))
+ s.setStateBigInt(big.NewInt(miningVelocityLoc), big.NewInt(int64(cfg.MiningVelocity*decimalMultiplier)))
+ s.setStateBigInt(big.NewInt(nextHalvingSupplyLoc), cfg.NextHalvingSupply)
+ s.setStateBigInt(big.NewInt(lastHalvedAmountLoc), cfg.LastHalvedAmount)
+ s.setStateBigInt(big.NewInt(minGasPriceLoc), cfg.MinGasPrice)
+ s.setStateBigInt(big.NewInt(blockGasLimitLoc), big.NewInt(int64(cfg.BlockGasLimit)))
+ s.setStateBigInt(big.NewInt(lambdaBALoc), big.NewInt(int64(cfg.LambdaBA)))
+ s.setStateBigInt(big.NewInt(lambdaDKGLoc), big.NewInt(int64(cfg.LambdaDKG)))
+ s.setStateBigInt(big.NewInt(notarySetSizeLoc), big.NewInt(int64(cfg.NotarySetSize)))
+ s.setStateBigInt(big.NewInt(notaryParamAlphaLoc), big.NewInt(int64(cfg.NotaryParamAlpha*decimalMultiplier)))
+ s.setStateBigInt(big.NewInt(notaryParamBetaLoc), big.NewInt(int64(cfg.NotaryParamBeta*decimalMultiplier)))
+ s.setStateBigInt(big.NewInt(roundLengthLoc), big.NewInt(int64(cfg.RoundLength)))
+ s.setStateBigInt(big.NewInt(minBlockIntervalLoc), big.NewInt(int64(cfg.MinBlockInterval)))
+ s.SetFineValues(cfg.FineValues)
+
+ // Calculate set size.
+ s.CalNotarySetSize()
+}
+
+type rawConfigStruct struct {
+ MinStake *big.Int
+ LockupPeriod *big.Int
+ BlockGasLimit *big.Int
+ MinGasPrice *big.Int
+ LambdaBA *big.Int
+ LambdaDKG *big.Int
+ NotaryParamAlpha *big.Int
+ NotaryParamBeta *big.Int
+ RoundLength *big.Int
+ MinBlockInterval *big.Int
+ FineValues []*big.Int
+}
+
+// UpdateConfigurationRaw updates system configuration.
+func (s *GovernanceState) UpdateConfigurationRaw(cfg *rawConfigStruct) {
+ s.setStateBigInt(big.NewInt(minStakeLoc), cfg.MinStake)
+ s.setStateBigInt(big.NewInt(lockupPeriodLoc), cfg.LockupPeriod)
+ s.setStateBigInt(big.NewInt(minGasPriceLoc), cfg.MinGasPrice)
+ s.setStateBigInt(big.NewInt(blockGasLimitLoc), cfg.BlockGasLimit)
+ s.setStateBigInt(big.NewInt(lambdaBALoc), cfg.LambdaBA)
+ s.setStateBigInt(big.NewInt(lambdaDKGLoc), cfg.LambdaDKG)
+ s.setStateBigInt(big.NewInt(notaryParamAlphaLoc), cfg.NotaryParamAlpha)
+ s.setStateBigInt(big.NewInt(notaryParamBetaLoc), cfg.NotaryParamBeta)
+ s.setStateBigInt(big.NewInt(roundLengthLoc), cfg.RoundLength)
+ s.setStateBigInt(big.NewInt(minBlockIntervalLoc), cfg.MinBlockInterval)
+ s.SetFineValues(cfg.FineValues)
+
+ // Calculate set size.
+ s.CalNotarySetSize()
+}
+
+// event ConfigurationChanged();
+func (s *GovernanceState) emitConfigurationChangedEvent() {
+ s.StateDB.AddLog(&types.Log{
+ Address: GovernanceContractAddress,
+ Topics: []common.Hash{GovernanceABI.Events["ConfigurationChanged"].Id()},
+ Data: []byte{},
+ })
+}
+
+// event CRSProposed(uint256 indexed Round, bytes32 CRS);
+func (s *GovernanceState) emitCRSProposed(round *big.Int, crs common.Hash) {
+ s.StateDB.AddLog(&types.Log{
+ Address: GovernanceContractAddress,
+ Topics: []common.Hash{GovernanceABI.Events["CRSProposed"].Id(), common.BigToHash(round)},
+ Data: crs.Bytes(),
+ })
+}
+
+// event NodeOwnershipTransfered(address indexed NodeAddress, address indexed NewOwnerAddress);
+func (s *GovernanceState) emitNodeOwnershipTransfered(nodeAddr, newNodeAddr common.Address) {
+ s.StateDB.AddLog(&types.Log{
+ Address: GovernanceContractAddress,
+ Topics: []common.Hash{GovernanceABI.Events["NodeOwnershipTransfered"].Id(),
+ nodeAddr.Hash(), newNodeAddr.Hash()},
+ Data: []byte{},
+ })
+}
+
+// event NodePublicKeyReplaced(address indexed NodeAddress, bytes PublicKey);
+func (s *GovernanceState) emitNodePublicKeyReplaced(nodeAddr common.Address, pk []byte) {
+ s.StateDB.AddLog(&types.Log{
+ Address: GovernanceContractAddress,
+ Topics: []common.Hash{GovernanceABI.Events["NodePublicKeyReplaced"].Id(), nodeAddr.Hash()},
+ Data: pk,
+ })
+}
+
+// event Staked(address indexed NodeAddress, uint256 Amount);
+func (s *GovernanceState) emitStaked(nodeAddr common.Address, amount *big.Int) {
+ s.StateDB.AddLog(&types.Log{
+ Address: GovernanceContractAddress,
+ Topics: []common.Hash{GovernanceABI.Events["Staked"].Id(), nodeAddr.Hash()},
+ Data: common.BigToHash(amount).Bytes(),
+ })
+}
+
+// event Unstaked(address indexed NodeAddress, uint256 Amount);
+func (s *GovernanceState) emitUnstaked(nodeAddr common.Address, amount *big.Int) {
+ s.StateDB.AddLog(&types.Log{
+ Address: GovernanceContractAddress,
+ Topics: []common.Hash{GovernanceABI.Events["Unstaked"].Id(), nodeAddr.Hash()},
+ Data: common.BigToHash(amount).Bytes(),
+ })
+}
+
+// event Withdrawn(address indexed NodeAddress, uint256 Amount);
+func (s *GovernanceState) emitWithdrawn(nodeAddr common.Address, amount *big.Int) {
+ s.StateDB.AddLog(&types.Log{
+ Address: GovernanceContractAddress,
+ Topics: []common.Hash{GovernanceABI.Events["Withdrawn"].Id(), nodeAddr.Hash()},
+ Data: common.BigToHash(amount).Bytes(),
+ })
+}
+
+// event NodeAdded(address indexed NodeAddress);
+func (s *GovernanceState) emitNodeAdded(nodeAddr common.Address) {
+ s.StateDB.AddLog(&types.Log{
+ Address: GovernanceContractAddress,
+ Topics: []common.Hash{GovernanceABI.Events["NodeAdded"].Id(), nodeAddr.Hash()},
+ Data: []byte{},
+ })
+}
+
+// event NodeRemoved(address indexed NodeAddress);
+func (s *GovernanceState) emitNodeRemoved(nodeAddr common.Address) {
+ s.StateDB.AddLog(&types.Log{
+ Address: GovernanceContractAddress,
+ Topics: []common.Hash{GovernanceABI.Events["NodeRemoved"].Id(), nodeAddr.Hash()},
+ Data: []byte{},
+ })
+}
+
+// event Reported(address indexed NodeAddress, uint256 Type, bytes Arg1, bytes Arg2);
+func (s *GovernanceState) emitReported(nodeAddr common.Address, reportType *big.Int, arg1, arg2 []byte) {
+
+ t1, err := abi.NewType("uint256", nil)
+ if err != nil {
+ panic(err)
+ }
+ t2, err := abi.NewType("bytes", nil)
+ if err != nil {
+ panic(err)
+ }
+
+ arg := abi.Arguments{
+ abi.Argument{
+ Name: "ReportType",
+ Type: t1,
+ Indexed: false,
+ },
+ abi.Argument{
+ Name: "Arg1",
+ Type: t2,
+ Indexed: false,
+ },
+ abi.Argument{
+ Name: "Arg2",
+ Type: t2,
+ Indexed: false,
+ },
+ }
+
+ data, err := arg.Pack(reportType, arg1, arg2)
+ if err != nil {
+ panic(err)
+ }
+ s.StateDB.AddLog(&types.Log{
+ Address: GovernanceContractAddress,
+ Topics: []common.Hash{GovernanceABI.Events["Reported"].Id(), nodeAddr.Hash()},
+ Data: data,
+ })
+}
+
+// event Fined(address indexed NodeAddress, uint256 Amount);
+func (s *GovernanceState) emitFined(nodeAddr common.Address, amount *big.Int) {
+ s.StateDB.AddLog(&types.Log{
+ Address: GovernanceContractAddress,
+ Topics: []common.Hash{GovernanceABI.Events["Fined"].Id(), nodeAddr.Hash()},
+ Data: common.BigToHash(amount).Bytes(),
+ })
+}
+
+// event FinePaid(address indexed NodeAddress, uint256 Amount);
+func (s *GovernanceState) emitFinePaid(nodeAddr common.Address, amount *big.Int) {
+ s.StateDB.AddLog(&types.Log{
+ Address: GovernanceContractAddress,
+ Topics: []common.Hash{GovernanceABI.Events["FinePaid"].Id(), nodeAddr.Hash()},
+ Data: common.BigToHash(amount).Bytes(),
+ })
+}
+
+// event DKGReset(uint256 indexed Round, uint256 BlockHeight);
+func (s *GovernanceState) emitDKGReset(round *big.Int, blockHeight *big.Int) {
+ s.StateDB.AddLog(&types.Log{
+ Address: GovernanceContractAddress,
+ Topics: []common.Hash{GovernanceABI.Events["DKGReset"].Id(), common.BigToHash(round)},
+ Data: common.BigToHash(blockHeight).Bytes(),
+ })
+}
+
+func getRoundState(evm *EVM, round *big.Int) (*GovernanceState, error) {
+ gs := &GovernanceState{evm.StateDB}
+ height := gs.RoundHeight(round).Uint64()
+ if round.Uint64() > dexCore.ConfigRoundShift {
+ if height == 0 {
+ return nil, errExecutionReverted
+ }
+ }
+ statedb, err := evm.StateAtNumber(height)
+ return &GovernanceState{statedb}, err
+}
+
+func getConfigState(evm *EVM, round *big.Int) (*GovernanceState, error) {
+ configRound := big.NewInt(0)
+ if round.Uint64() > dexCore.ConfigRoundShift {
+ configRound = new(big.Int).Sub(round, big.NewInt(int64(dexCore.ConfigRoundShift)))
+ }
+ return getRoundState(evm, configRound)
+}
+
+type coreDKGUtils interface {
+ NewGroupPublicKey(*GovernanceState, *big.Int, int) (tsigVerifierIntf, error)
+}
+type tsigVerifierIntf interface {
+ VerifySignature(coreCommon.Hash, coreCrypto.Signature) bool
+}
+
+// GovernanceContract represents the governance contract of DEXCON.
+type GovernanceContract struct {
+ evm *EVM
+ state GovernanceState
+ contract *vm.Contract
+ coreDKGUtils coreDKGUtils
+}
+
+// defaultCoreDKGUtils implements coreDKGUtils.
+type defaultCoreDKGUtils struct {
+ gpk atomic.Value
+}
+
+func (c *defaultCoreDKGUtils) NewGroupPublicKey(
+ state *GovernanceState, round *big.Int, threshold int) (tsigVerifierIntf, error) {
+ var gpk *dkgTypes.GroupPublicKey
+ var err error
+
+ v := c.gpk.Load()
+ if v != nil {
+ gpk = v.(*dkgTypes.GroupPublicKey)
+ if gpk.Round == round.Uint64() {
+ return gpk, nil
+ }
+ }
+
+ mpks := state.DKGMasterPublicKeyItems()
+ comps := state.DKGComplaintItems()
+ gpk, err = dkgTypes.NewGroupPublicKey(round.Uint64(), mpks, comps, threshold)
+ if err != nil {
+ return nil, err
+ }
+ c.gpk.Store(gpk)
+ return gpk, nil
+}
+
+func (g *GovernanceContract) Address() common.Address {
+ return GovernanceContractAddress
+}
+
+func (g *GovernanceContract) transfer(from, to common.Address, amount *big.Int) bool {
+ // TODO(w): add this to debug trace so it shows up as internal transaction.
+ if g.evm.CanTransfer(g.evm.StateDB, from, amount) {
+ g.evm.Transfer(g.evm.StateDB, from, to, amount)
+ return true
+ }
+ return false
+}
+
+func (g *GovernanceContract) useGas(gas uint64) ([]byte, error) {
+ if !g.contract.UseGas(gas) {
+ return nil, vm.ErrOutOfGas
+ }
+ return nil, nil
+}
+
+func (g *GovernanceContract) configNotarySetSize(round *big.Int) *big.Int {
+ s, err := getConfigState(g.evm, round)
+ if err != nil {
+ return big.NewInt(0)
+ }
+ return s.NotarySetSize()
+}
+
+func (g *GovernanceContract) getNotarySet(round *big.Int) map[coreTypes.NodeID]struct{} {
+ crsRound := g.state.CRSRound()
+ var crs common.Hash
+ cmp := round.Cmp(crsRound)
+ if round.Cmp(big.NewInt(int64(dexCore.DKGDelayRound))) <= 0 {
+ state, err := getRoundState(g.evm, big.NewInt(0))
+ if err != nil {
+ return map[coreTypes.NodeID]struct{}{}
+ }
+ crs = state.CRS()
+ for i := uint64(0); i < round.Uint64(); i++ {
+ crs = crypto.Keccak256Hash(crs[:])
+ }
+ } else if cmp > 0 {
+ return map[coreTypes.NodeID]struct{}{}
+ } else if cmp == 0 {
+ crs = g.state.CRS()
+ } else {
+ state, err := getRoundState(g.evm, round)
+ if err != nil {
+ return map[coreTypes.NodeID]struct{}{}
+ }
+ crs = state.CRS()
+ }
+
+ target := coreTypes.NewNotarySetTarget(coreCommon.Hash(crs))
+ ns := coreTypes.NewNodeSet()
+
+ state, err := getConfigState(g.evm, round)
+ if err != nil {
+ return map[coreTypes.NodeID]struct{}{}
+ }
+ for _, x := range state.QualifiedNodes() {
+ mpk, err := ecdsa.NewPublicKeyFromByteSlice(x.PublicKey)
+ if err != nil {
+ panic(err)
+ }
+ ns.Add(coreTypes.NewNodeID(mpk))
+ }
+ return ns.GetSubSet(int(g.configNotarySetSize(round).Uint64()), target)
+}
+
+func (g *GovernanceContract) inNotarySet(round *big.Int, nodeID coreTypes.NodeID) bool {
+ dkgSet := g.getNotarySet(round)
+ _, ok := dkgSet[nodeID]
+ return ok
+}
+
+func (g *GovernanceContract) clearDKG() {
+ dkgSet := g.getNotarySet(g.state.DKGRound())
+ g.state.ClearDKGMasterPublicKeyOffset()
+ g.state.ClearDKGMasterPublicKeys()
+ g.state.ClearDKGComplaintProposed()
+ g.state.ClearDKGComplaints()
+ g.state.ClearDKGMPKReadys(dkgSet)
+ g.state.ResetDKGMPKReadysCount()
+ g.state.ClearDKGFinalizeds(dkgSet)
+ g.state.ResetDKGFinalizedsCount()
+ g.state.ClearDKGSuccesses(dkgSet)
+ g.state.ResetDKGSuccessesCount()
+}
+
+func (g *GovernanceContract) fineFailStopDKG(threshold int) {
+ fineNode := make(map[coreTypes.NodeID]struct{})
+ dkgSet := g.getNotarySet(g.state.DKGRound())
+ for id := range dkgSet {
+ offset := g.state.DKGMasterPublicKeyOffset(Bytes32(id.Hash))
+ if offset.Cmp(big.NewInt(0)) >= 0 {
+ continue
+ }
+ fineNode[id] = struct{}{}
+ }
+ complaintsByID := map[coreTypes.NodeID]map[coreTypes.NodeID]struct{}{}
+ for _, complaint := range g.state.DKGComplaints() {
+ comp := new(dkgTypes.Complaint)
+ if err := rlp.DecodeBytes(complaint, comp); err != nil {
+ panic(err)
+ }
+
+ if comp.IsNack() {
+ if _, exist := complaintsByID[comp.PrivateShare.ProposerID]; !exist {
+ complaintsByID[comp.PrivateShare.ProposerID] =
+ make(map[coreTypes.NodeID]struct{})
+ }
+ complaintsByID[comp.PrivateShare.ProposerID][comp.ProposerID] = struct{}{}
+ }
+ }
+ for id, complaints := range complaintsByID {
+ if len(complaints) >= threshold {
+ fineNode[id] = struct{}{}
+ }
+ }
+ nodes := make(coreTypes.NodeIDs, 0, len(fineNode))
+ for id := range fineNode {
+ nodes = append(nodes, id)
+ }
+ sort.Sort(nodes)
+ for _, id := range nodes {
+ offset := g.state.NodesOffsetByNodeKeyAddress(IdToAddress(id))
+ // Node might have been unstaked.
+ if offset.Cmp(big.NewInt(0)) < 0 {
+ continue
+ }
+
+ node := g.state.Node(offset)
+ amount := g.state.FineValue(big.NewInt(FineTypeFailStopDKG))
+ node.Fined = new(big.Int).Add(node.Fined, amount)
+ g.state.UpdateNode(offset, node)
+ g.state.emitFined(node.Owner, amount)
+ }
+}
+
+func (g *GovernanceContract) addDKGComplaint(comp []byte) ([]byte, error) {
+ caller := g.contract.Caller()
+ offset := g.state.NodesOffsetByNodeKeyAddress(caller)
+
+ // Can not add complaint if caller does not exists.
+ if offset.Cmp(big.NewInt(0)) < 0 {
+ return nil, errExecutionReverted
+ }
+
+ // Finalized caller is not allowed to propose complaint.
+ if g.state.DKGFinalized(caller) {
+ return nil, errExecutionReverted
+ }
+
+ // Calculate 2f + 1
+ threshold := 2*g.configNotarySetSize(g.evm.Round).Uint64()/3 + 1
+
+ // If 2f + 1 of DKG set is finalized, one can not propose complaint anymore.
+ if g.state.DKGFinalizedsCount().Uint64() >= threshold {
+ return nil, errExecutionReverted
+ }
+
+ var dkgComplaint dkgTypes.Complaint
+ if err := rlp.DecodeBytes(comp, &dkgComplaint); err != nil {
+ return nil, errExecutionReverted
+ }
+
+ if g.state.DKGComplaintProposed(getDKGComplaintID(&dkgComplaint)) {
+ return nil, errExecutionReverted
+ }
+ round := big.NewInt(int64(dkgComplaint.Round))
+ if round.Uint64() != g.evm.Round.Uint64()+1 {
+ return nil, errExecutionReverted
+ }
+
+ if dkgComplaint.Reset != g.state.DKGResetCount(round).Uint64() {
+ return nil, errExecutionReverted
+ }
+
+ // DKGComplaint must belongs to someone in DKG set.
+ if !g.inNotarySet(round, dkgComplaint.ProposerID) {
+ return nil, errExecutionReverted
+ }
+
+ verified, _ := coreUtils.VerifyDKGComplaintSignature(&dkgComplaint)
+ if !verified {
+ return nil, errExecutionReverted
+ }
+
+ mpkOffset := g.state.DKGMasterPublicKeyOffset(Bytes32(dkgComplaint.PrivateShare.ProposerID.Hash))
+ mpk := g.state.DKGMasterPublicKeyItem(mpkOffset)
+
+ // Verify DKG complaint is correct.
+ ok, err := coreUtils.VerifyDKGComplaint(&dkgComplaint, mpk)
+ if !ok || err != nil {
+ return nil, errExecutionReverted
+ }
+
+ // Fine the attacker.
+ need, err := coreUtils.NeedPenaltyDKGPrivateShare(&dkgComplaint, mpk)
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ if need {
+ node, err := g.state.GetNodeByID(dkgComplaint.PrivateShare.ProposerID)
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ fineValue := g.state.FineValue(big.NewInt(FineTypeInvalidDKG))
+ if err := g.fine(node.Owner, fineValue, comp, nil); err != nil {
+ return nil, errExecutionReverted
+ }
+ }
+
+ g.state.PushDKGComplaint(comp)
+ g.state.PutDKGComplaintProposed(getDKGComplaintID(&dkgComplaint), true)
+
+ return g.useGas(GovernanceActionGasCost)
+}
+
+func (g *GovernanceContract) addDKGMasterPublicKey(mpk []byte) ([]byte, error) {
+ var dkgMasterPK dkgTypes.MasterPublicKey
+ if err := rlp.DecodeBytes(mpk, &dkgMasterPK); err != nil {
+ return nil, errExecutionReverted
+ }
+ round := big.NewInt(int64(dkgMasterPK.Round))
+ if round.Uint64() != g.evm.Round.Uint64()+1 {
+ return nil, errExecutionReverted
+ }
+
+ if g.state.DKGRound().Cmp(g.evm.Round) == 0 {
+ // Clear DKG states for next round.
+ g.clearDKG()
+ g.state.SetDKGRound(round)
+ }
+
+ mpkOffset := g.state.DKGMasterPublicKeyOffset(getDKGMasterPublicKeyID(&dkgMasterPK))
+ if mpkOffset.Cmp(big.NewInt(0)) >= 0 {
+ return nil, errExecutionReverted
+ }
+
+ caller := g.contract.Caller()
+ offset := g.state.NodesOffsetByNodeKeyAddress(caller)
+
+ // Can not add dkg mpk if not staked.
+ if offset.Cmp(big.NewInt(0)) < 0 {
+ return nil, errExecutionReverted
+ }
+
+ // MPKReady caller is not allowed to propose mpk.
+ if g.state.DKGMPKReady(caller) {
+ return nil, errExecutionReverted
+ }
+
+ // Calculate 2f + 1
+ threshold := 2*g.configNotarySetSize(g.evm.Round).Uint64()/3 + 1
+
+ // If 2f + 1 of DKG set is mpk ready, one can not propose mpk anymore.
+ if g.state.DKGMPKReadysCount().Uint64() >= threshold {
+ return nil, errExecutionReverted
+ }
+
+ if dkgMasterPK.Reset != g.state.DKGResetCount(round).Uint64() {
+ return nil, errExecutionReverted
+ }
+
+ // DKGMasterPublicKey must belongs to someone in DKG set.
+ if !g.inNotarySet(round, dkgMasterPK.ProposerID) {
+ return nil, errExecutionReverted
+ }
+
+ verified, _ := coreUtils.VerifyDKGMasterPublicKeySignature(&dkgMasterPK)
+ if !verified {
+ return nil, errExecutionReverted
+ }
+
+ mpkOffset = g.state.LenDKGMasterPublicKeys()
+ g.state.PushDKGMasterPublicKey(mpk)
+ g.state.PutDKGMasterPublicKeyOffset(getDKGMasterPublicKeyID(&dkgMasterPK), mpkOffset)
+
+ return g.useGas(GovernanceActionGasCost)
+}
+
+func (g *GovernanceContract) addDKGMPKReady(ready []byte) ([]byte, error) {
+ caller := g.contract.Caller()
+
+ var dkgReady dkgTypes.MPKReady
+ if err := rlp.DecodeBytes(ready, &dkgReady); err != nil {
+ return nil, errExecutionReverted
+ }
+ round := big.NewInt(int64(dkgReady.Round))
+ if round.Uint64() != g.evm.Round.Uint64()+1 {
+ return nil, errExecutionReverted
+ }
+
+ if dkgReady.Reset != g.state.DKGResetCount(round).Uint64() {
+ return nil, errExecutionReverted
+ }
+
+ // DKGFInalize must belongs to someone in DKG set.
+ if !g.inNotarySet(round, dkgReady.ProposerID) {
+ return nil, errExecutionReverted
+ }
+
+ verified, _ := coreUtils.VerifyDKGMPKReadySignature(&dkgReady)
+ if !verified {
+ return nil, errExecutionReverted
+ }
+
+ if !g.state.DKGMPKReady(caller) {
+ g.state.PutDKGMPKReady(caller, true)
+ g.state.IncDKGMPKReadysCount()
+ }
+
+ return g.useGas(GovernanceActionGasCost)
+}
+
+func (g *GovernanceContract) addDKGFinalize(finalize []byte) ([]byte, error) {
+ caller := g.contract.Caller()
+
+ var dkgFinalize dkgTypes.Finalize
+ if err := rlp.DecodeBytes(finalize, &dkgFinalize); err != nil {
+ return nil, errExecutionReverted
+ }
+ round := big.NewInt(int64(dkgFinalize.Round))
+ if round.Uint64() != g.evm.Round.Uint64()+1 {
+ return nil, errExecutionReverted
+ }
+
+ if dkgFinalize.Reset != g.state.DKGResetCount(round).Uint64() {
+ return nil, errExecutionReverted
+ }
+
+ // DKGFInalize must belongs to someone in DKG set.
+ if !g.inNotarySet(round, dkgFinalize.ProposerID) {
+ return nil, errExecutionReverted
+ }
+
+ verified, _ := coreUtils.VerifyDKGFinalizeSignature(&dkgFinalize)
+ if !verified {
+ return nil, errExecutionReverted
+ }
+
+ if !g.state.DKGFinalized(caller) {
+ g.state.PutDKGFinalized(caller, true)
+ g.state.IncDKGFinalizedsCount()
+ }
+
+ threshold := 2*g.configNotarySetSize(g.evm.Round).Uint64()/3 + 1
+
+ if g.state.DKGFinalizedsCount().Uint64() == threshold {
+ tsigThreshold := coreUtils.GetDKGThreshold(&coreTypes.Config{
+ NotarySetSize: uint32(g.configNotarySetSize(g.evm.Round).Uint64())})
+ g.fineFailStopDKG(tsigThreshold)
+ }
+
+ return g.useGas(GovernanceActionGasCost)
+}
+
+func (g *GovernanceContract) addDKGSuccess(success []byte) ([]byte, error) {
+ caller := g.contract.Caller()
+
+ var dkgSuccess dkgTypes.Success
+ if err := rlp.DecodeBytes(success, &dkgSuccess); err != nil {
+ return nil, errExecutionReverted
+ }
+ round := big.NewInt(int64(dkgSuccess.Round))
+ if round.Uint64() != g.evm.Round.Uint64()+1 {
+ return nil, errExecutionReverted
+ }
+
+ if dkgSuccess.Reset != g.state.DKGResetCount(round).Uint64() {
+ return nil, errExecutionReverted
+ }
+
+ // DKGFInalize must belongs to someone in DKG set.
+ if !g.inNotarySet(round, dkgSuccess.ProposerID) {
+ return nil, errExecutionReverted
+ }
+
+ verified, _ := coreUtils.VerifyDKGSuccessSignature(&dkgSuccess)
+ if !verified {
+ return nil, errExecutionReverted
+ }
+
+ if !g.state.DKGSuccess(caller) {
+ g.state.PutDKGSuccess(caller, true)
+ g.state.IncDKGSuccessesCount()
+ }
+
+ return g.useGas(GovernanceActionGasCost)
+}
+
+func (g *GovernanceContract) updateConfiguration(cfg *rawConfigStruct) ([]byte, error) {
+ // Only owner can update configuration.
+ if g.contract.Caller() != g.state.Owner() {
+ return nil, errExecutionReverted
+ }
+
+ // Sanity checks.
+ if cfg.MinStake.Cmp(big.NewInt(0)) <= 0 ||
+ cfg.LockupPeriod.Cmp(big.NewInt(0)) <= 0 ||
+ cfg.BlockGasLimit.Cmp(big.NewInt(0)) <= 0 ||
+ cfg.MinGasPrice.Cmp(big.NewInt(0)) <= 0 ||
+ cfg.LambdaBA.Cmp(big.NewInt(0)) <= 0 ||
+ cfg.LambdaDKG.Cmp(big.NewInt(0)) <= 0 ||
+ cfg.RoundLength.Cmp(big.NewInt(0)) <= 0 ||
+ cfg.MinBlockInterval.Cmp(big.NewInt(0)) <= 0 {
+ return nil, errExecutionReverted
+ }
+
+ g.state.UpdateConfigurationRaw(cfg)
+ g.state.emitConfigurationChangedEvent()
+
+ return nil, nil
+}
+
+func (g *GovernanceContract) register(
+ publicKey []byte, name, email, location, url string) ([]byte, error) {
+
+ // Reject invalid inputs.
+ if len(name) >= 32 || len(email) >= 32 || len(location) >= 32 || len(url) >= 128 {
+ return nil, errExecutionReverted
+ }
+
+ caller := g.contract.Caller()
+ value := g.contract.Value()
+ offset := g.state.NodesOffsetByAddress(caller)
+
+ // Can not register if already registered.
+ if offset.Cmp(big.NewInt(0)) >= 0 {
+ return nil, errExecutionReverted
+ }
+
+ nodeKeyAddr, err := publicKeyToNodeKeyAddress(publicKey)
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+
+ offset = g.state.NodesOffsetByNodeKeyAddress(nodeKeyAddr)
+
+ // Can not register if node key is duplicate.
+ if offset.Cmp(big.NewInt(0)) >= 0 {
+ return nil, errExecutionReverted
+ }
+
+ offset = g.state.LenNodes()
+ node := &nodeInfo{
+ Owner: caller,
+ PublicKey: publicKey,
+ Staked: value,
+ Fined: big.NewInt(0),
+ Name: name,
+ Email: email,
+ Location: location,
+ Url: url,
+ Unstaked: big.NewInt(0),
+ UnstakedAt: big.NewInt(0),
+ }
+ g.state.PushNode(node)
+ g.state.PutNodeOffsets(node, offset)
+ g.state.emitNodeAdded(caller)
+
+ if value.Cmp(big.NewInt(0)) > 0 {
+ g.state.IncTotalStaked(value)
+ g.state.emitStaked(caller, value)
+ }
+ return g.useGas(GovernanceActionGasCost)
+}
+
+func (g *GovernanceContract) stake() ([]byte, error) {
+ caller := g.contract.Caller()
+ value := g.contract.Value()
+
+ if big.NewInt(0).Cmp(value) == 0 {
+ return nil, errExecutionReverted
+ }
+
+ offset := g.state.NodesOffsetByAddress(caller)
+ if offset.Cmp(big.NewInt(0)) < 0 {
+ return nil, errExecutionReverted
+ }
+
+ node := g.state.Node(offset)
+ if node.Fined.Cmp(big.NewInt(0)) > 0 {
+ return nil, errExecutionReverted
+ }
+
+ node.Staked = new(big.Int).Add(node.Staked, value)
+ g.state.UpdateNode(offset, node)
+
+ g.state.IncTotalStaked(value)
+ g.state.emitStaked(caller, value)
+
+ return g.useGas(GovernanceActionGasCost)
+}
+
+func (g *GovernanceContract) unstake(amount *big.Int) ([]byte, error) {
+ caller := g.contract.Caller()
+
+ offset := g.state.NodesOffsetByAddress(caller)
+ if offset.Cmp(big.NewInt(0)) < 0 {
+ return nil, errExecutionReverted
+ }
+
+ node := g.state.Node(offset)
+
+ // Can not unstake if there are unpaied fine.
+ if node.Fined.Cmp(big.NewInt(0)) > 0 {
+ return nil, errExecutionReverted
+ }
+
+ // Can not unstake if there are unwithdrawn stake.
+ if node.Unstaked.Cmp(big.NewInt(0)) > 0 {
+ return nil, errExecutionReverted
+ }
+ if node.Staked.Cmp(amount) < 0 {
+ return nil, errExecutionReverted
+ }
+
+ node.Staked = new(big.Int).Sub(node.Staked, amount)
+ node.Unstaked = amount
+ node.UnstakedAt = g.evm.Time
+ g.state.UpdateNode(offset, node)
+
+ g.state.DecTotalStaked(amount)
+ g.state.emitUnstaked(caller, amount)
+
+ return g.useGas(GovernanceActionGasCost)
+}
+
+func (g *GovernanceContract) withdraw() ([]byte, error) {
+ if !g.withdrawable() {
+ return nil, errExecutionReverted
+ }
+ caller := g.contract.Caller()
+
+ offset := g.state.NodesOffsetByAddress(caller)
+ if offset.Cmp(big.NewInt(0)) < 0 {
+ return nil, errExecutionReverted
+ }
+
+ node := g.state.Node(offset)
+
+ amount := node.Unstaked
+ node.Unstaked = big.NewInt(0)
+ node.UnstakedAt = big.NewInt(0)
+ g.state.UpdateNode(offset, node)
+
+ if node.Staked.Cmp(big.NewInt(0)) == 0 {
+ length := g.state.LenNodes()
+ lastIndex := new(big.Int).Sub(length, big.NewInt(1))
+
+ // Delete the node.
+ if offset.Cmp(lastIndex) != 0 {
+ lastNode := g.state.Node(lastIndex)
+ g.state.UpdateNode(offset, lastNode)
+ g.state.PutNodeOffsets(lastNode, offset)
+ }
+ g.state.DeleteNodeOffsets(node)
+ g.state.PopLastNode()
+ g.state.emitNodeRemoved(caller)
+ }
+
+ // Return the staked fund.
+ if !g.transfer(GovernanceContractAddress, node.Owner, amount) {
+ return nil, errExecutionReverted
+ }
+ g.state.emitWithdrawn(caller, amount)
+
+ return g.useGas(GovernanceActionGasCost)
+}
+
+func (g *GovernanceContract) withdrawable() bool {
+ caller := g.contract.Caller()
+
+ offset := g.state.NodesOffsetByAddress(caller)
+ if offset.Cmp(big.NewInt(0)) < 0 {
+ return false
+ }
+
+ node := g.state.Node(offset)
+
+ // Can not withdraw if there are unpaied fine.
+ if node.Fined.Cmp(big.NewInt(0)) > 0 {
+ return false
+ }
+
+ // Can not withdraw if there are no pending withdrawal.
+ if node.Unstaked.Cmp(big.NewInt(0)) == 0 {
+ return false
+ }
+
+ unlockTime := new(big.Int).Add(node.UnstakedAt, g.state.LockupPeriod())
+ return g.evm.Time.Cmp(unlockTime) > 0
+}
+
+func (g *GovernanceContract) payFine(nodeAddr common.Address) ([]byte, error) {
+ nodeOffset := g.state.NodesOffsetByAddress(nodeAddr)
+ if nodeOffset.Cmp(big.NewInt(0)) < 0 {
+ return nil, errExecutionReverted
+ }
+
+ node := g.state.Node(nodeOffset)
+ if node.Fined.Cmp(big.NewInt(0)) <= 0 || node.Fined.Cmp(g.contract.Value) < 0 {
+ return nil, errExecutionReverted
+ }
+
+ node.Fined = new(big.Int).Sub(node.Fined, g.contract.Value)
+ g.state.UpdateNode(nodeOffset, node)
+
+ // Pay the fine to governance owner.
+ g.evm.StateDB.AddBalance(g.state.Owner(), g.contract.Value)
+
+ g.state.emitFinePaid(nodeAddr, g.contract.Value)
+
+ return g.useGas(GovernanceActionGasCost)
+}
+
+func (g *GovernanceContract) proposeCRS(nextRound *big.Int, signedCRS []byte) ([]byte, error) {
+ if nextRound.Uint64() != g.evm.Round.Uint64()+1 ||
+ g.state.CRSRound().Uint64() == nextRound.Uint64() {
+ return nil, errExecutionReverted
+ }
+
+ prevCRS := g.state.CRS()
+
+ // CRS(n) = hash(CRS(n-1)) if n <= core.DKGRoundDelay
+ if g.evm.Round.Uint64() == dexCore.DKGDelayRound {
+ for i := uint64(0); i < dexCore.DKGDelayRound; i++ {
+ prevCRS = crypto.Keccak256Hash(prevCRS[:])
+ }
+ }
+
+ threshold := coreUtils.GetDKGThreshold(&coreTypes.Config{
+ NotarySetSize: uint32(g.state.NotarySetSize().Uint64())})
+ dkgGPK, err := g.coreDKGUtils.NewGroupPublicKey(&g.state, nextRound, threshold)
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ signature := coreCrypto.Signature{
+ Type: "bls",
+ Signature: signedCRS,
+ }
+ if !dkgGPK.VerifySignature(coreCommon.Hash(prevCRS), signature) {
+ return nil, errExecutionReverted
+ }
+
+ // Save new CRS into state and increase round.
+ crs := crypto.Keccak256Hash(signedCRS)
+
+ g.state.SetCRS(crs)
+ g.state.SetCRSRound(nextRound)
+ g.state.emitCRSProposed(nextRound, crs)
+
+ return g.useGas(GovernanceActionGasCost)
+}
+
+type sortBytes [][]byte
+
+func (s sortBytes) Less(i, j int) bool {
+ return bytes.Compare(s[i], s[j]) < 0
+}
+
+func (s sortBytes) Swap(i, j int) {
+ s[i], s[j] = s[j], s[i]
+}
+
+func (s sortBytes) Len() int {
+ return len(s)
+}
+
+func (g *GovernanceContract) fine(nodeAddr common.Address, amount *big.Int, payloads ...[]byte) error {
+ sort.Sort(sortBytes(payloads))
+
+ hash := Bytes32(crypto.Keccak256Hash(payloads...))
+ if g.state.FineRecords(hash) {
+ return errors.New("already fined")
+ }
+ g.state.SetFineRecords(hash, true)
+
+ nodeOffset := g.state.NodesOffsetByAddress(nodeAddr)
+ if nodeOffset.Cmp(big.NewInt(0)) < 0 {
+ return errExecutionReverted
+ }
+
+ // Set fined value.
+ node := g.state.Node(nodeOffset)
+ node.Fined = new(big.Int).Add(node.Fined, amount)
+ g.state.UpdateNode(nodeOffset, node)
+
+ g.state.emitFined(nodeAddr, amount)
+
+ return nil
+}
+
+func (g *GovernanceContract) report(reportType *big.Int, arg1, arg2 []byte) ([]byte, error) {
+ typeEnum := FineType(reportType.Uint64())
+ var reportedNodeID coreTypes.NodeID
+
+ switch typeEnum {
+ case FineTypeForkVote:
+ vote1 := new(coreTypes.Vote)
+ if err := rlp.DecodeBytes(arg1, vote1); err != nil {
+ return nil, errExecutionReverted
+ }
+ vote2 := new(coreTypes.Vote)
+ if err := rlp.DecodeBytes(arg2, vote2); err != nil {
+ return nil, errExecutionReverted
+ }
+ need, err := coreUtils.NeedPenaltyForkVote(vote1, vote2)
+ if !need || err != nil {
+ return nil, errExecutionReverted
+ }
+ reportedNodeID = vote1.ProposerID
+ case FineTypeForkBlock:
+ block1 := new(coreTypes.Block)
+ if err := rlp.DecodeBytes(arg1, block1); err != nil {
+ return nil, errExecutionReverted
+ }
+ block2 := new(coreTypes.Block)
+ if err := rlp.DecodeBytes(arg2, block2); err != nil {
+ return nil, errExecutionReverted
+ }
+ need, err := coreUtils.NeedPenaltyForkBlock(block1, block2)
+ if !need || err != nil {
+ return nil, errExecutionReverted
+ }
+ reportedNodeID = block1.ProposerID
+ default:
+ return nil, errExecutionReverted
+ }
+
+ node, err := g.state.GetNodeByID(reportedNodeID)
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+
+ g.state.emitReported(node.Owner, reportType, arg1, arg2)
+
+ fineValue := g.state.FineValue(reportType)
+ if err := g.fine(node.Owner, fineValue, arg1, arg2); err != nil {
+ return nil, errExecutionReverted
+ }
+ return nil, nil
+}
+
+func (g *GovernanceContract) resetDKG(newSignedCRS []byte) ([]byte, error) {
+ round := g.evm.Round
+ nextRound := new(big.Int).Add(round, big.NewInt(1))
+
+ // If no one call addDKGMasterPublicKey, DKG of previous round will not be
+ // cleared.
+ if g.state.DKGRound().Cmp(round) == 0 {
+ // Clear DKG states for next round.
+ g.clearDKG()
+ g.state.SetDKGRound(nextRound)
+ }
+
+ resetCount := g.state.DKGResetCount(nextRound)
+
+ // Just restart DEXON if failed at round 0.
+ if round.Cmp(big.NewInt(0)) == 0 {
+ return nil, errExecutionReverted
+ }
+
+ // Extend the the current round.
+ // target = (85 + 100 * DKGResetCount)%
+ target := new(big.Int).Add(
+ big.NewInt(85),
+ new(big.Int).Mul(big.NewInt(100), resetCount))
+
+ roundHeight := g.state.RoundHeight(round)
+ gs, err := getConfigState(g.evm, round)
+ if err != nil {
+ return nil, err
+ }
+ config := gs.Configuration()
+
+ targetBlockNum := new(big.Int).SetUint64(config.RoundLength)
+ targetBlockNum.Mul(targetBlockNum, target)
+ targetBlockNum.Quo(targetBlockNum, big.NewInt(100))
+ targetBlockNum.Add(targetBlockNum, roundHeight)
+
+ // Check if current block over 85%of current round.
+ blockHeight := g.evm.Context.BlockNumber
+ if blockHeight.Cmp(targetBlockNum) < 0 {
+ return nil, errExecutionReverted
+ }
+
+ tsigThreshold := coreUtils.GetDKGThreshold(&coreTypes.Config{
+ NotarySetSize: uint32(g.configNotarySetSize(nextRound).Uint64())})
+ // Check if next DKG has not enough of success.
+ if g.state.DKGSuccessesCount().Uint64() >=
+ uint64(coreUtils.GetDKGValidThreshold(&coreTypes.Config{
+ NotarySetSize: uint32(g.configNotarySetSize(nextRound).Uint64()),
+ })) {
+ // Check if next DKG did not success.
+ // Calculate 2f + 1
+ threshold := 2*g.configNotarySetSize(nextRound).Uint64()/3 + 1
+
+ // If 2f + 1 of DKG set is finalized, check if DKG succeeded.
+ if g.state.DKGFinalizedsCount().Uint64() >= threshold {
+ gpk, err := g.coreDKGUtils.NewGroupPublicKey(&g.state, nextRound, tsigThreshold)
+ if gpk, ok := gpk.(*dkgTypes.GroupPublicKey); ok {
+ if len(gpk.QualifyNodeIDs) < coreUtils.GetDKGValidThreshold(&coreTypes.Config{
+ NotarySetSize: uint32(g.configNotarySetSize(nextRound).Uint64())}) {
+ err = dkgTypes.ErrNotReachThreshold
+ }
+ }
+
+ // DKG success.
+ if err == nil {
+ return nil, errExecutionReverted
+ }
+ switch err {
+ case dkgTypes.ErrNotReachThreshold, dkgTypes.ErrInvalidThreshold:
+ default:
+ return nil, errExecutionReverted
+ }
+ }
+ }
+
+ // Fine fail stop DKGs.
+ g.fineFailStopDKG(tsigThreshold)
+
+ // Update CRS.
+ state, err := getRoundState(g.evm, round)
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ prevCRS := state.CRS()
+
+ // CRS(n) = hash(CRS(n-1)) if n <= core.DKGRoundDelay
+ if round.Uint64() == dexCore.DKGDelayRound {
+ for i := uint64(0); i < dexCore.DKGDelayRound; i++ {
+ prevCRS = crypto.Keccak256Hash(prevCRS[:])
+ }
+ }
+
+ for i := uint64(0); i < resetCount.Uint64()+1; i++ {
+ prevCRS = crypto.Keccak256Hash(prevCRS[:])
+ }
+
+ dkgGPK, err := g.coreDKGUtils.NewGroupPublicKey(state, round,
+ coreUtils.GetDKGThreshold(&coreTypes.Config{
+ NotarySetSize: uint32(g.configNotarySetSize(round).Uint64())}))
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ signature := coreCrypto.Signature{
+ Type: "bls",
+ Signature: newSignedCRS,
+ }
+ if !dkgGPK.VerifySignature(coreCommon.Hash(prevCRS), signature) {
+ return nil, errExecutionReverted
+ }
+
+ // Clear DKG states for next round.
+ g.clearDKG()
+ g.state.SetDKGRound(nextRound)
+
+ // Save new CRS into state and increase round.
+ newCRS := crypto.Keccak256(newSignedCRS)
+ crs := common.BytesToHash(newCRS)
+
+ g.state.SetCRS(crs)
+ g.state.SetCRSRound(nextRound)
+ g.state.emitCRSProposed(nextRound, crs)
+
+ // Increase reset count.
+ g.state.IncDKGResetCount(nextRound)
+ g.state.emitDKGReset(round, blockHeight)
+
+ return nil, nil
+}
+
+// Run executes governance contract.
+func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *vm.Contract) (ret []byte, err error) {
+ if len(input) < 4 {
+ return nil, errExecutionReverted
+ }
+
+ // Initialize contract state.
+ g.evm = evm
+ g.state = GovernanceState{evm.StateDB}
+ g.contract = contract
+
+ // Parse input.
+ method, exists := GovernanceABI.Sig2Method[string(input[:4])]
+ if !exists {
+ return nil, errExecutionReverted
+ }
+
+ arguments := input[4:]
+
+ // Dispatch method call.
+ switch method.Name {
+ case "addDKGComplaint":
+ var Complaint []byte
+ if err := method.Inputs.Unpack(&Complaint, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ return g.addDKGComplaint(Complaint)
+ case "addDKGMasterPublicKey":
+ var PublicKey []byte
+ if err := method.Inputs.Unpack(&PublicKey, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ return g.addDKGMasterPublicKey(PublicKey)
+ case "addDKGMPKReady":
+ var MPKReady []byte
+ if err := method.Inputs.Unpack(&MPKReady, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ return g.addDKGMPKReady(MPKReady)
+ case "addDKGFinalize":
+ var Finalize []byte
+ if err := method.Inputs.Unpack(&Finalize, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ return g.addDKGFinalize(Finalize)
+ case "addDKGSuccess":
+ var Success []byte
+ if err := method.Inputs.Unpack(&Success, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ return g.addDKGSuccess(Success)
+ case "nodesLength":
+ res, err := method.Outputs.Pack(g.state.LenNodes())
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "payFine":
+ address := common.Address{}
+ if err := method.Inputs.Unpack(&address, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ return g.payFine(address)
+ case "proposeCRS":
+ args := struct {
+ Round *big.Int
+ SignedCRS []byte
+ }{}
+ if err := method.Inputs.Unpack(&args, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ return g.proposeCRS(args.Round, args.SignedCRS)
+ case "report":
+ args := struct {
+ Type *big.Int
+ Arg1 []byte
+ Arg2 []byte
+ }{}
+ if err := method.Inputs.Unpack(&args, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ return g.report(args.Type, args.Arg1, args.Arg2)
+ case "resetDKG":
+ args := struct {
+ NewSignedCRS []byte
+ }{}
+ if err := method.Inputs.Unpack(&args, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ return g.resetDKG(args.NewSignedCRS)
+ case "register":
+ args := struct {
+ PublicKey []byte
+ Name string
+ Email string
+ Location string
+ Url string
+ }{}
+ if err := method.Inputs.Unpack(&args, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ return g.register(args.PublicKey, args.Name, args.Email, args.Location, args.Url)
+ case "stake":
+ return g.stake()
+ case "transferOwnership":
+ var newOwner common.Address
+ if err := method.Inputs.Unpack(&newOwner, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ return g.transferOwnership(newOwner)
+ case "transferNodeOwnership":
+ var newOwner common.Address
+ if err := method.Inputs.Unpack(&newOwner, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ return g.transferNodeOwnership(newOwner)
+ case "transferNodeOwnershipByFoundation":
+ args := struct {
+ OldOwner common.Address
+ NewOwner common.Address
+ }{}
+ if err := method.Inputs.Unpack(&args, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ return g.transferNodeOwnershipByFoundation(args.OldOwner, args.NewOwner)
+ case "unstake":
+ amount := new(big.Int)
+ if err := method.Inputs.Unpack(&amount, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ return g.unstake(amount)
+ case "updateConfiguration":
+ var cfg rawConfigStruct
+ if err := method.Inputs.Unpack(&cfg, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ return g.updateConfiguration(&cfg)
+ case "withdraw":
+ return g.withdraw()
+ case "withdrawable":
+ res, err := method.Outputs.Pack(g.withdrawable())
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+
+ // --------------------------------
+ // Solidity auto generated methods.
+ // --------------------------------
+
+ case "blockGasLimit":
+ res, err := method.Outputs.Pack(g.state.BlockGasLimit())
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "crs":
+ res, err := method.Outputs.Pack(g.state.CRS())
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "crsRound":
+ res, err := method.Outputs.Pack(g.state.CRSRound())
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "dkgComplaints":
+ offset := new(big.Int)
+ if err := method.Inputs.Unpack(&offset, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ complaint := g.state.DKGComplaint(offset)
+ res, err := method.Outputs.Pack(complaint)
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "dkgComplaintsProposed":
+ id := Bytes32{}
+ if err := method.Inputs.Unpack(&id, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ proposed := g.state.DKGComplaintProposed(id)
+ res, err := method.Outputs.Pack(proposed)
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "dkgFinalizeds":
+ addr := common.Address{}
+ if err := method.Inputs.Unpack(&addr, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ finalized := g.state.DKGFinalized(addr)
+ res, err := method.Outputs.Pack(finalized)
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "dkgFinalizedsCount":
+ count := g.state.DKGFinalizedsCount()
+ res, err := method.Outputs.Pack(count)
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "dkgSuccesses":
+ addr := common.Address{}
+ if err := method.Inputs.Unpack(&addr, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ finalized := g.state.DKGSuccess(addr)
+ res, err := method.Outputs.Pack(finalized)
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "dkgSuccessesCount":
+ count := g.state.DKGSuccessesCount()
+ res, err := method.Outputs.Pack(count)
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "dkgMasterPublicKeys":
+ offset := new(big.Int)
+ if err := method.Inputs.Unpack(&offset, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ mpk := g.state.DKGMasterPublicKey(offset)
+ res, err := method.Outputs.Pack(mpk)
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "dkgMasterPublicKeyOffset":
+ id := Bytes32{}
+ if err := method.Inputs.Unpack(&id, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ offset := g.state.DKGMasterPublicKeyOffset(id)
+ res, err := method.Outputs.Pack(offset)
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "dkgMPKReadys":
+ addr := common.Address{}
+ if err := method.Inputs.Unpack(&addr, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ ready := g.state.DKGMPKReady(addr)
+ res, err := method.Outputs.Pack(ready)
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "dkgMPKReadysCount":
+ count := g.state.DKGMPKReadysCount()
+ res, err := method.Outputs.Pack(count)
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "dkgResetCount":
+ round := new(big.Int)
+ if err := method.Inputs.Unpack(&round, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ res, err := method.Outputs.Pack(g.state.DKGResetCount(round))
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "dkgRound":
+ res, err := method.Outputs.Pack(g.state.DKGRound())
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "finedRecords":
+ record := Bytes32{}
+ if err := method.Inputs.Unpack(&record, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ value := g.state.FineRecords(record)
+ res, err := method.Outputs.Pack(value)
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "fineValues":
+ index := new(big.Int)
+ if err := method.Inputs.Unpack(&index, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ value := g.state.FineValue(index)
+ res, err := method.Outputs.Pack(value)
+ 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 "lastHalvedAmount":
+ res, err := method.Outputs.Pack(g.state.LastHalvedAmount())
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "lastProposedHeight":
+ address := common.Address{}
+ if err := method.Inputs.Unpack(&address, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ res, err := method.Outputs.Pack(g.state.LastProposedHeight(address))
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "lockupPeriod":
+ res, err := method.Outputs.Pack(g.state.LockupPeriod())
+ 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 "minGasPrice":
+ res, err := method.Outputs.Pack(g.state.MinGasPrice())
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "miningVelocity":
+ res, err := method.Outputs.Pack(g.state.MiningVelocity())
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "minStake":
+ res, err := method.Outputs.Pack(g.state.MinStake())
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "nextHalvingSupply":
+ res, err := method.Outputs.Pack(g.state.NextHalvingSupply())
+ 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, info.Fined,
+ info.Name, info.Email, info.Location, info.Url,
+ info.Unstaked, info.UnstakedAt)
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "nodesOffsetByAddress":
+ address := common.Address{}
+ if err := method.Inputs.Unpack(&address, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ res, err := method.Outputs.Pack(g.state.NodesOffsetByAddress(address))
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "nodesOffsetByNodeKeyAddress":
+ address := common.Address{}
+ if err := method.Inputs.Unpack(&address, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ res, err := method.Outputs.Pack(g.state.NodesOffsetByNodeKeyAddress(address))
+ 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 "notaryParamAlpha":
+ res, err := method.Outputs.Pack(g.state.NotaryParamAlpha())
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "notaryParamBeta":
+ res, err := method.Outputs.Pack(g.state.NotaryParamBeta())
+ 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 "replaceNodePublicKey":
+ var pk []byte
+ if err := method.Inputs.Unpack(&pk, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ return g.replaceNodePublicKey(pk)
+ 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 "roundLength":
+ res, err := method.Outputs.Pack(g.state.RoundLength())
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "totalStaked":
+ res, err := method.Outputs.Pack(g.state.TotalStaked())
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "totalSupply":
+ res, err := method.Outputs.Pack(g.state.TotalSupply())
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ }
+ return nil, errExecutionReverted
+}
+
+func (g *GovernanceContract) transferOwnership(newOwner common.Address) ([]byte, error) {
+ // Only owner can update configuration.
+ if g.contract.Caller() != g.state.Owner() {
+ return nil, errExecutionReverted
+ }
+ if newOwner == (common.Address{}) {
+ return nil, errExecutionReverted
+ }
+ g.state.SetOwner(newOwner)
+ return nil, nil
+}
+
+func (g *GovernanceContract) transferNodeOwnership(newOwner common.Address) ([]byte, error) {
+ if newOwner == (common.Address{}) {
+ return nil, errExecutionReverted
+ }
+ caller := g.contract.Caller()
+
+ offset := g.state.NodesOffsetByAddress(caller)
+ if offset.Cmp(big.NewInt(0)) < 0 {
+ return nil, errExecutionReverted
+ }
+
+ newOffset := g.state.NodesOffsetByAddress(newOwner)
+ if newOffset.Cmp(big.NewInt(0)) >= 0 {
+ return nil, errExecutionReverted
+ }
+
+ node := g.state.Node(offset)
+ g.state.DeleteNodeOffsets(node)
+
+ node.Owner = newOwner
+ g.state.PutNodeOffsets(node, offset)
+ g.state.UpdateNode(offset, node)
+
+ g.state.emitNodeOwnershipTransfered(caller, newOwner)
+
+ return nil, nil
+}
+
+func (g *GovernanceContract) transferNodeOwnershipByFoundation(oldOwner, newOwner common.Address) ([]byte, error) {
+ // Only owner can update configuration.
+ if g.contract.Caller() != g.state.Owner() {
+ return nil, errExecutionReverted
+ }
+
+ if newOwner == (common.Address{}) {
+ return nil, errExecutionReverted
+ }
+
+ offset := g.state.NodesOffsetByAddress(oldOwner)
+ if offset.Cmp(big.NewInt(0)) < 0 {
+ return nil, errExecutionReverted
+ }
+
+ newOffset := g.state.NodesOffsetByAddress(newOwner)
+ if newOffset.Cmp(big.NewInt(0)) >= 0 {
+ return nil, errExecutionReverted
+ }
+
+ node := g.state.Node(offset)
+ g.state.DeleteNodeOffsets(node)
+
+ node.Owner = newOwner
+ g.state.PutNodeOffsets(node, offset)
+ g.state.UpdateNode(offset, node)
+
+ g.state.emitNodeOwnershipTransfered(oldOwner, newOwner)
+
+ return nil, nil
+}
+
+func (g *GovernanceContract) replaceNodePublicKey(newPublicKey []byte) ([]byte, error) {
+ caller := g.contract.Caller()
+
+ offset := g.state.NodesOffsetByAddress(caller)
+ if offset.Cmp(big.NewInt(0)) < 0 {
+ return nil, errExecutionReverted
+ }
+
+ node := g.state.Node(offset)
+
+ _, err := publicKeyToNodeKeyAddress(newPublicKey)
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+
+ g.state.DeleteNodeOffsets(node)
+
+ node.PublicKey = newPublicKey
+ g.state.PutNodeOffsets(node, offset)
+ g.state.UpdateNode(offset, node)
+
+ g.state.emitNodePublicKeyReplaced(caller, newPublicKey)
+
+ return nil, nil
+}
+
+func PackProposeCRS(round uint64, signedCRS []byte) ([]byte, error) {
+ method := GovernanceABI.Name2Method["proposeCRS"]
+ res, err := method.Inputs.Pack(big.NewInt(int64(round)), signedCRS)
+ if err != nil {
+ return nil, err
+ }
+ data := append(method.Id(), res...)
+ return data, nil
+}
+
+func PackAddDKGMasterPublicKey(mpk *dkgTypes.MasterPublicKey) ([]byte, error) {
+ method := GovernanceABI.Name2Method["addDKGMasterPublicKey"]
+ encoded, err := rlp.EncodeToBytes(mpk)
+ if err != nil {
+ return nil, err
+ }
+ res, err := method.Inputs.Pack(encoded)
+ if err != nil {
+ return nil, err
+ }
+ data := append(method.Id(), res...)
+ return data, nil
+}
+
+func PackAddDKGMPKReady(ready *dkgTypes.MPKReady) ([]byte, error) {
+ method := GovernanceABI.Name2Method["addDKGMPKReady"]
+ encoded, err := rlp.EncodeToBytes(ready)
+ if err != nil {
+ return nil, err
+ }
+ res, err := method.Inputs.Pack(encoded)
+ if err != nil {
+ return nil, err
+ }
+ data := append(method.Id(), res...)
+ return data, nil
+}
+
+func PackAddDKGComplaint(complaint *dkgTypes.Complaint) ([]byte, error) {
+ method := GovernanceABI.Name2Method["addDKGComplaint"]
+ encoded, err := rlp.EncodeToBytes(complaint)
+ if err != nil {
+ return nil, err
+ }
+
+ res, err := method.Inputs.Pack(encoded)
+ if err != nil {
+ return nil, err
+ }
+ data := append(method.Id(), res...)
+ return data, nil
+}
+
+func PackAddDKGFinalize(final *dkgTypes.Finalize) ([]byte, error) {
+ method := GovernanceABI.Name2Method["addDKGFinalize"]
+ encoded, err := rlp.EncodeToBytes(final)
+ if err != nil {
+ return nil, err
+ }
+
+ res, err := method.Inputs.Pack(encoded)
+ if err != nil {
+ return nil, err
+ }
+ data := append(method.Id(), res...)
+ return data, nil
+}
+
+func PackAddDKGSuccess(final *dkgTypes.Success) ([]byte, error) {
+ method := GovernanceABI.Name2Method["addDKGSuccess"]
+ encoded, err := rlp.EncodeToBytes(final)
+ if err != nil {
+ return nil, err
+ }
+
+ res, err := method.Inputs.Pack(encoded)
+ if err != nil {
+ return nil, err
+ }
+ data := append(method.Id(), res...)
+ return data, nil
+}
+
+func PackReportForkVote(vote1, vote2 *coreTypes.Vote) ([]byte, error) {
+ method := GovernanceABI.Name2Method["report"]
+
+ vote1Bytes, err := rlp.EncodeToBytes(vote1)
+ if err != nil {
+ return nil, err
+ }
+
+ vote2Bytes, err := rlp.EncodeToBytes(vote2)
+ if err != nil {
+ return nil, err
+ }
+
+ res, err := method.Inputs.Pack(big.NewInt(FineTypeForkVote), vote1Bytes, vote2Bytes)
+ if err != nil {
+ return nil, err
+ }
+ data := append(method.Id(), res...)
+ return data, nil
+}
+
+func PackReportForkBlock(block1, block2 *coreTypes.Block) ([]byte, error) {
+ method := GovernanceABI.Name2Method["report"]
+
+ block1Bytes, err := rlp.EncodeToBytes(block1)
+ if err != nil {
+ return nil, err
+ }
+
+ block2Bytes, err := rlp.EncodeToBytes(block2)
+ if err != nil {
+ return nil, err
+ }
+
+ res, err := method.Inputs.Pack(big.NewInt(FineTypeForkBlock), block1Bytes, block2Bytes)
+ if err != nil {
+ return nil, err
+ }
+ data := append(method.Id(), res...)
+ return data, nil
+}
+
+func PackResetDKG(newSignedCRS []byte) ([]byte, error) {
+ method := GovernanceABI.Name2Method["resetDKG"]
+ res, err := method.Inputs.Pack(newSignedCRS)
+ if err != nil {
+ return nil, err
+ }
+ data := append(method.Id(), res...)
+ return data, nil
+}
diff --git a/core/vm/evm/oracle_contracts_test.go b/core/vm/evm/oracle_contracts_test.go
new file mode 100644
index 000000000..41bf0fb58
--- /dev/null
+++ b/core/vm/evm/oracle_contracts_test.go
@@ -0,0 +1,1203 @@
+// 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 evm
+
+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/core/vm"
+ "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.AddBalance(GovernanceContractAddress, big.NewInt(1))
+ 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() {
+ emptyOffset := 100
+ for j := 0; j < 50; j++ {
+ idx := big.NewInt(int64(j + emptyOffset))
+ 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(0xd78ebc5ac6200000), 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 vm.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.NotarySetSize = 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 = vm.Context{
+ CanTransfer: func(db vm.StateDB, addr common.Address, amount *big.Int) bool {
+ return db.GetBalance(addr).Cmp(amount) >= 0
+ },
+ Transfer: func(db vm.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(vm.AccountRef(caller), contractAddr, input, 10000000, value)
+ return ret, err
+}
+
+func (g *OracleContractsTestSuite) TestTransferOwnership() {
+ input, err := GovernanceABI.ABI.Pack("transferOwnership", common.Address{})
+ g.Require().NoError(err)
+ // Call with owner but invalid new owner.
+ _, err = g.call(GovernanceContractAddress, g.config.Owner, input, big.NewInt(0))
+ g.Require().NotNil(err)
+
+ _, 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)
+
+ 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)
+
+ // Call with not valid new owner.
+ input, err = GovernanceABI.ABI.Pack("transferNodeOwnership", common.Address{})
+ g.Require().NoError(err)
+ _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
+ g.Require().NotNil(err)
+
+ _, newAddr := newPrefundAccount(g.stateDB)
+
+ 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(-1, int(g.s.NodesOffsetByAddress(addr).Int64()))
+ g.Require().Equal(0, int(g.s.NodesOffsetByNodeKeyAddress(addr).Int64()))
+ g.Require().Equal(0, int(g.s.NodesOffsetByAddress(newAddr).Int64()))
+
+ // New node for duplication test.
+ 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) TestTransferNodeOwnershipByFoundation() {
+ privKey, addr := newPrefundAccount(g.stateDB)
+ pk := crypto.FromECDSAPub(&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)
+
+ _, newAddr := newPrefundAccount(g.stateDB)
+
+ // Call with not valid new owner.
+ input, err = GovernanceABI.ABI.Pack("transferNodeOwnershipByFoundation", common.Address{}, newAddr)
+ g.Require().NoError(err)
+ _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
+ g.Require().NotNil(err)
+
+ input, err = GovernanceABI.ABI.Pack("transferNodeOwnershipByFoundation", addr, newAddr)
+ g.Require().NoError(err)
+
+ // Call with gov owner.
+ _, noneOwner := newPrefundAccount(g.stateDB)
+ _, err = g.call(GovernanceContractAddress, noneOwner, input, big.NewInt(0))
+ g.Require().Error(err)
+
+ // Call with gov owner.
+ _, err = g.call(GovernanceContractAddress, g.config.Owner, input, big.NewInt(0))
+ g.Require().NoError(err)
+ g.Require().Equal(-1, int(g.s.NodesOffsetByAddress(addr).Int64()))
+ g.Require().Equal(0, int(g.s.NodesOffsetByNodeKeyAddress(addr).Int64()))
+ g.Require().Equal(0, int(g.s.NodesOffsetByAddress(newAddr).Int64()))
+}
+
+func (g *OracleContractsTestSuite) TestReplaceNodePublicKey() {
+ privKey, addr := newPrefundAccount(g.stateDB)
+ pk := crypto.FromECDSAPub(&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)
+
+ privKey2, addr2 := newPrefundAccount(g.stateDB)
+ pk2 := crypto.FromECDSAPub(&privKey2.PublicKey)
+
+ input, err = GovernanceABI.ABI.Pack("replaceNodePublicKey", pk2)
+ 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(-1, int(g.s.NodesOffsetByNodeKeyAddress(addr).Int64()))
+ g.Require().Equal(0, int(g.s.NodesOffsetByAddress(addr).Int64()))
+ g.Require().Equal(0, int(g.s.NodesOffsetByNodeKeyAddress(addr2).Int64()))
+}
+
+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())
+
+ var ok bool
+ // Withdraw immediately should fail.
+ input, err = GovernanceABI.ABI.Pack("withdrawable")
+ g.Require().NoError(err)
+ output, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
+ g.Require().NoError(err)
+ GovernanceABI.ABI.Unpack(&ok, "withdrawable", output)
+ g.Require().False(ok)
+ 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.
+ input, err = GovernanceABI.ABI.Pack("withdrawable")
+ g.Require().NoError(err)
+ output, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
+ g.Require().NoError(err)
+ GovernanceABI.ABI.Unpack(&ok, "withdrawable", output)
+ g.Require().False(ok)
+ 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("withdrawable")
+ g.Require().NoError(err)
+ output, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
+ g.Require().NoError(err)
+ GovernanceABI.ABI.Unpack(&ok, "withdrawable", output)
+ g.Require().True(ok)
+ 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), 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)
+
+ // 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(FineTypeForkBlock), 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(FineTypeForkVote), 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(FineTypeForkVote)))
+
+ // Duplicate report should fail.
+ input, err = GovernanceABI.ABI.Pack("report", big.NewInt(FineTypeForkVote), 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(FineTypeForkVote), 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(FineTypeForkBlock), 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(FineTypeForkBlock)))
+
+ // Duplicate report should fail.
+ input, err = GovernanceABI.ABI.Pack("report", big.NewInt(FineTypeForkBlock), 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.NotarySetSize; 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.NotarySetSize))
+
+ 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.ClearDKGMasterPublicKeyOffset()
+ 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.ClearDKGSuccesses(dkgSet)
+ g.s.ResetDKGSuccessesCount()
+ g.s.SetDKGRound(big.NewInt(int64(round)))
+ }
+
+ addrs[round] = []common.Address{}
+ target := coreTypes.NewNotarySetTarget(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.NotarySetSize().Uint64()), target)
+ g.Require().Len(dkgSet, int(g.config.NotarySetSize))
+ dkgSets[round] = dkgSet
+
+ i := 0
+ 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)
+ g.s.PutDKGMasterPublicKeyOffset(Bytes32(id.Hash), big.NewInt(int64(i)))
+ // 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()
+ // Prepare Success.
+ g.s.PutDKGSuccess(addr, true)
+ g.s.IncDKGSuccessesCount()
+ }
+ i += 1
+ }
+ 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))
+ }
+ g.Require().Equal(int64(dkgSetSize), g.s.DKGSuccessesCount().Int64())
+ for _, addr := range addrs[round] {
+ g.Require().True(g.s.DKGSuccess(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*85/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))
+ }
+ // Test if Success is purged.
+ g.Require().Equal(int64(0), g.s.DKGSuccessesCount().Int64())
+ for _, addr := range addrs[round+1] {
+ g.Require().False(g.s.DKGSuccess(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))
+}