// 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 // . package vm 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-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("5765692d4e696e6720536f6e696320426f6a6965") const GovernanceABIJSON = ` [ { "constant": true, "inputs": [ { "name": "", "type": "address" }, { "name": "", "type": "address" } ], "name": "delegatorsOffset", "outputs": [ { "name": "", "type": "int256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "blockReward", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "", "type": "uint256" }, { "name": "", "type": "uint256" } ], "name": "dkgComplaints", "outputs": [ { "name": "", "type": "bytes" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "notarySetSize", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "dkgSetSize", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "", "type": "uint256" } ], "name": "nodes", "outputs": [ { "name": "owner", "type": "address" }, { "name": "publicKey", "type": "bytes" }, { "name": "staked", "type": "uint256" }, { "name": "fined", "type": "uint256" }, { "name": "name", "type": "string" }, { "name": "email", "type": "string" }, { "name": "location", "type": "string" }, { "name": "url", "type": "string" }, { "name": "unstaked", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "lambdaBA", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "minStake", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "", "type": "uint256" } ], "name": "crs", "outputs": [ { "name": "", "type": "bytes32" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "phiRatio", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "", "type": "uint256" } ], "name": "dkgMPKReadysCount", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "", "type": "uint256" }, { "name": "", "type": "address" } ], "name": "dkgMPKReadys", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "", "type": "address" }, { "name": "", "type": "uint256" } ], "name": "delegators", "outputs": [ { "name": "owner", "type": "address" }, { "name": "value", "type": "uint256" }, { "name": "undelegated_at", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "blockGasLimit", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "", "type": "bytes32" } ], "name": "nodesOffsetByID", "outputs": [ { "name": "", "type": "int256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "roundInterval", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "", "type": "address" } ], "name": "nodesOffsetByAddress", "outputs": [ { "name": "", "type": "int256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "owner", "outputs": [ { "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "", "type": "bytes32" } ], "name": "finedRecords", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "lambdaDKG", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "", "type": "uint256" } ], "name": "fineValues", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "", "type": "uint256" } ], "name": "roundHeight", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "minBlockInterval", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "k", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "", "type": "uint256" }, { "name": "", "type": "uint256" } ], "name": "dkgMasterPublicKeys", "outputs": [ { "name": "", "type": "bytes" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "", "type": "uint256" }, { "name": "", "type": "address" } ], "name": "dkgFinalizeds", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "numChains", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "lockupPeriod", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "", "type": "uint256" } ], "name": "dkgFinalizedsCount", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "anonymous": false, "inputs": [], "name": "ConfigurationChanged", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "Round", "type": "uint256" }, { "indexed": false, "name": "CRS", "type": "bytes32" } ], "name": "CRSProposed", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "NodeAddress", "type": "address" } ], "name": "Staked", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "NodeAddress", "type": "address" } ], "name": "Unstaked", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "NodeAddress", "type": "address" }, { "indexed": true, "name": "DelegatorAddress", "type": "address" }, { "indexed": false, "name": "Amount", "type": "uint256" } ], "name": "Delegated", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "NodeAddress", "type": "address" }, { "indexed": true, "name": "DelegatorAddress", "type": "address" } ], "name": "Undelegated", "type": "event" }, { "constant": false, "inputs": [ { "name": "newOwner", "type": "address" } ], "name": "transferOwnership", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "MinStake", "type": "uint256" }, { "name": "LockupPeriod", "type": "uint256" }, { "name": "BlockReward", "type": "uint256" }, { "name": "BlockGasLimit", "type": "uint256" }, { "name": "NumChains", "type": "uint256" }, { "name": "LambdaBA", "type": "uint256" }, { "name": "LambdaDKG", "type": "uint256" }, { "name": "K", "type": "uint256" }, { "name": "PhiRatio", "type": "uint256" }, { "name": "NotarySetSize", "type": "uint256" }, { "name": "DKGSetSize", "type": "uint256" }, { "name": "RoundInterval", "type": "uint256" }, { "name": "MinBlockInterval", "type": "uint256" }, { "name": "FineValues", "type": "uint256[]" } ], "name": "updateConfiguration", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [], "name": "nodesLength", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "NodeAddress", "type": "address" } ], "name": "delegatorsLength", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [ { "name": "Round", "type": "uint256" }, { "name": "Height", "type": "uint256" } ], "name": "snapshotRound", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "Round", "type": "uint256" }, { "name": "SignedCRS", "type": "bytes" } ], "name": "proposeCRS", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "Round", "type": "uint256" }, { "name": "Complaint", "type": "bytes" } ], "name": "addDKGComplaint", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "Round", "type": "uint256" }, { "name": "PublicKey", "type": "bytes" } ], "name": "addDKGMasterPublicKey", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "Round", "type": "uint256" }, { "name": "MPKReady", "type": "bytes" } ], "name": "addDKGMPKReady", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "Round", "type": "uint256" }, { "name": "Finalize", "type": "bytes" } ], "name": "addDKGFinalize", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "PublicKey", "type": "bytes" }, { "name": "Name", "type": "string" }, { "name": "Email", "type": "string" }, { "name": "Location", "type": "string" }, { "name": "Url", "type": "string" } ], "name": "stake", "outputs": [], "payable": true, "stateMutability": "payable", "type": "function" }, { "constant": false, "inputs": [], "name": "unstake", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "NodeAddress", "type": "address" } ], "name": "delegate", "outputs": [], "payable": true, "stateMutability": "payable", "type": "function" }, { "constant": false, "inputs": [ { "name": "NodeAddress", "type": "address" } ], "name": "undelegate", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "NodeAddress", "type": "address" } ], "name": "withdraw", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "NodeAddress", "type": "address" } ], "name": "payFine", "outputs": [], "payable": true, "stateMutability": "payable", "type": "function" }, { "constant": false, "inputs": [ { "name": "Type", "type": "uint256" }, { "name": "Arg1", "type": "bytes" }, { "name": "Arg2", "type": "bytes" } ], "name": "report", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" } ] ` var abiObject abi.ABI var GovernanceContractName2Method map[string]abi.Method var sig2Method map[string]abi.Method var events map[string]abi.Event 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 "blockReward": res, err := method.Outputs.Pack(g.state.BlockReward()) 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 "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 "minStake": res, err := method.Outputs.Pack(g.state.MinStake()) 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, info.Unstaked) 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 } return nil, nil } // Storage position enums. const ( roundHeightLoc = iota nodesLoc nodesOffsetByAddressLoc nodesOffsetByIDLoc delegatorsLoc delegatorsOffsetLoc crsLoc dkgMasterPublicKeysLoc dkgComplaintsLoc dkgReadyLoc dkgReadysCountLoc dkgFinalizedLoc dkgFinalizedsCountLoc ownerLoc minStakeLoc lockupPeriodLoc blockRewardLoc 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) } // struct Node { // address owner; // bytes publicKey; // uint256 staked; // uint256 fined; // string name; // string email; // string location; // string url; // bool unstaked; // } // // 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 bool } const nodeStructSize = 9 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)) // Unstaked. loc = new(big.Int).Add(elementBaseLoc, big.NewInt(8)) node.Unstaked = s.getStateBigInt(loc).Cmp(big.NewInt(0)) > 0 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)) // Unstaked. loc = new(big.Int).Add(elementBaseLoc, big.NewInt(8)) val := big.NewInt(0) if n.Unstaked { val = big.NewInt(1) } s.setStateBigInt(loc, val) } 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 node.Unstaked { continue } 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 blockReward; func (s *GovernanceStateHelper) BlockReward() *big.Int { return s.getStateBigInt(big.NewInt(blockRewardLoc)) } // 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) } const phiRatioMultiplier = 1000000.0 // Configuration returns the current configuration. func (s *GovernanceStateHelper) Configuration() *params.DexconConfig { return ¶ms.DexconConfig{ MinStake: s.getStateBigInt(big.NewInt(minStakeLoc)), LockupPeriod: s.getStateBigInt(big.NewInt(lockupPeriodLoc)).Uint64(), BlockReward: s.getStateBigInt(big.NewInt(blockRewardLoc)), 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()) / phiRatioMultiplier, 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(blockRewardLoc), cfg.BlockReward) 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*phiRatioMultiplier))) 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 BlockReward *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(blockRewardLoc), cfg.BlockReward) 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{}, }) } // 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, 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) // 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) // 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) 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 } // 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)) } // Mark node as unstaked. node.Unstaked = true g.state.UpdateNode(offset, node) 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. 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) 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) 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 }