aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm/evm/governance.go
diff options
context:
space:
mode:
Diffstat (limited to 'core/vm/evm/governance.go')
-rw-r--r--core/vm/evm/governance.go2198
1 files changed, 2198 insertions, 0 deletions
diff --git a/core/vm/evm/governance.go b/core/vm/evm/governance.go
new file mode 100644
index 000000000..8b31d3a01
--- /dev/null
+++ b/core/vm/evm/governance.go
@@ -0,0 +1,2198 @@
+// 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 *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 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 *Contract
+}
+
+func newGovernanceContract(evm *EVM, contract *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
+}