From 09607eed5571e8689ba94d1cd6f6130fbdef3864 Mon Sep 17 00:00:00 2001 From: Wei-Ning Huang Date: Fri, 25 Jan 2019 19:24:35 +0800 Subject: core: vm: refactor governance and add node info oracle (#174) --- core/vm/evm.go | 7 +- core/vm/governance.go | 2270 ------------------------------------- core/vm/governance_abi.go | 1108 ------------------ core/vm/governance_test.go | 1017 ----------------- core/vm/oracle.go | 88 ++ core/vm/oracle_contract_abi.go | 1198 ++++++++++++++++++++ core/vm/oracle_contracts.go | 2316 ++++++++++++++++++++++++++++++++++++++ core/vm/oracle_contracts_test.go | 1063 +++++++++++++++++ test/genesis.json | 2 +- 9 files changed, 4670 insertions(+), 4399 deletions(-) delete mode 100644 core/vm/governance.go delete mode 100644 core/vm/governance_abi.go delete mode 100644 core/vm/governance_test.go create mode 100644 core/vm/oracle.go create mode 100644 core/vm/oracle_contract_abi.go create mode 100644 core/vm/oracle_contracts.go create mode 100644 core/vm/oracle_contracts_test.go diff --git a/core/vm/evm.go b/core/vm/evm.go index 2eba9c2cb..422d52ccb 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -48,8 +48,8 @@ type ( // run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter. func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, error) { if contract.CodeAddr != nil { - if *contract.CodeAddr == GovernanceContractAddress { - return RunGovernanceContract(evm, input, contract) + if o := OracleContracts[*contract.CodeAddr]; o != nil { + return RunOracleContract(o, evm, input, contract) } precompiles := PrecompiledContractsHomestead if evm.ChainConfig().IsByzantium(evm.BlockNumber) { @@ -216,7 +216,8 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas if evm.ChainConfig().IsByzantium(evm.BlockNumber) { precompiles = PrecompiledContractsByzantium } - if precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 && addr != GovernanceContractAddress { + if precompiles[addr] == nil && OracleContracts[addr] == nil && + evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 { // Calling a non existing account, don't do anything, but ping the tracer if evm.vmConfig.Debug && evm.depth == 0 { evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) diff --git a/core/vm/governance.go b/core/vm/governance.go deleted file mode 100644 index 684e22104..000000000 --- a/core/vm/governance.go +++ /dev/null @@ -1,2270 +0,0 @@ -// Copyright 2018 The dexon-consensus Authors -// This file is part of the dexon-consensus library. -// -// The dexon-consensus library is free software: you can redistribute it -// and/or modify it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of the License, -// or (at your option) any later version. -// -// The dexon-consensus library is distributed in the hope that it will be -// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the dexon-consensus library. If not, see -// . - -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("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 "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) 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 ¶ms.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 - 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(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, uint256 Amount); -func (s *GovernanceStateHelper) emitUndelegated(nodeAddr, delegatorAddr common.Address, amount *big.Int) { - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{events["Undelegated"].Id(), nodeAddr.Hash(), delegatorAddr.Hash()}, - Data: common.BigToHash(amount).Bytes(), - }) -} - -// 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", nil) - 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, 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, delegator.Value) - - 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 PackProposeCRS(round uint64, signedCRS []byte) ([]byte, error) { - method := GovernanceContractName2Method["proposeCRS"] - res, err := method.Inputs.Pack(big.NewInt(int64(round)), signedCRS) - if err != nil { - return nil, err - } - data := append(method.Id(), res...) - return data, nil -} - -func PackAddDKGMasterPublicKey(round uint64, mpk *dkgTypes.MasterPublicKey) ([]byte, error) { - method := GovernanceContractName2Method["addDKGMasterPublicKey"] - encoded, err := rlp.EncodeToBytes(mpk) - if err != nil { - return nil, err - } - res, err := method.Inputs.Pack(big.NewInt(int64(round)), encoded) - if err != nil { - return nil, err - } - data := append(method.Id(), res...) - return data, nil -} - -func PackAddDKGMPKReady(round uint64, ready *dkgTypes.MPKReady) ([]byte, error) { - method := GovernanceContractName2Method["addDKGMPKReady"] - encoded, err := rlp.EncodeToBytes(ready) - if err != nil { - return nil, err - } - res, err := method.Inputs.Pack(big.NewInt(int64(round)), encoded) - if err != nil { - return nil, err - } - data := append(method.Id(), res...) - return data, nil -} - -func PackAddDKGComplaint(round uint64, complaint *dkgTypes.Complaint) ([]byte, error) { - method := GovernanceContractName2Method["addDKGComplaint"] - encoded, err := rlp.EncodeToBytes(complaint) - if err != nil { - return nil, err - } - - res, err := method.Inputs.Pack(big.NewInt(int64(round)), encoded) - if err != nil { - return nil, err - } - data := append(method.Id(), res...) - return data, nil -} - -func PackAddDKGFinalize(round uint64, final *dkgTypes.Finalize) ([]byte, error) { - method := GovernanceContractName2Method["addDKGFinalize"] - encoded, err := rlp.EncodeToBytes(final) - if err != nil { - return nil, err - } - - res, err := method.Inputs.Pack(big.NewInt(int64(round)), encoded) - if err != nil { - return nil, err - } - data := append(method.Id(), res...) - return data, nil -} - -func PackReportForkVote(vote1, vote2 *coreTypes.Vote) ([]byte, error) { - method := GovernanceContractName2Method["report"] - - vote1Bytes, err := rlp.EncodeToBytes(vote1) - if err != nil { - return nil, err - } - - vote2Bytes, err := rlp.EncodeToBytes(vote2) - if err != nil { - return nil, err - } - - res, err := method.Inputs.Pack(big.NewInt(ReportTypeForkVote), vote1Bytes, vote2Bytes) - if err != nil { - return nil, err - } - - data := append(method.Id(), res...) - return data, nil -} - -func PackReportForkBlock(block1, block2 *coreTypes.Block) ([]byte, error) { - method := GovernanceContractName2Method["report"] - - block1Bytes, err := rlp.EncodeToBytes(block1) - if err != nil { - return nil, err - } - - block2Bytes, err := rlp.EncodeToBytes(block2) - if err != nil { - return nil, err - } - - res, err := method.Inputs.Pack(big.NewInt(ReportTypeForkBlock), block1Bytes, block2Bytes) - if err != nil { - return nil, err - } - - data := append(method.Id(), res...) - return data, nil -} diff --git a/core/vm/governance_abi.go b/core/vm/governance_abi.go deleted file mode 100644 index c3ad691b6..000000000 --- a/core/vm/governance_abi.go +++ /dev/null @@ -1,1108 +0,0 @@ -// Copyright 2019 The dexon-consensus Authors -// This file is part of the dexon-consensus library. -// -// The dexon-consensus library is free software: you can redistribute it -// and/or modify it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of the License, -// or (at your option) any later version. -// -// The dexon-consensus library is distributed in the hope that it will be -// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the dexon-consensus library. If not, see -// . - -package vm - -// The governance ABI is generated from: -// https://github.com/dexon-foundation/governance-abi - -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": "", - "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": "totalSupply", - "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" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "miningVelocity", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "lambdaBA", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "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": "totalStaked", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "roundInterval", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "address" - } - ], - "name": "nodesOffsetByAddress", - "outputs": [ - { - "name": "", - "type": "int256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "nextHalvingSupply", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "owner", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "lastHalvedAmount", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "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" - }, - { - "indexed": false, - "name": "Amount", - "type": "uint256" - } - ], - "name": "Undelegated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "NodeAddress", - "type": "address" - }, - { - "indexed": false, - "name": "Amount", - "type": "uint256" - } - ], - "name": "Withdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "NodeAddress", - "type": "address" - }, - { - "indexed": false, - "name": "Type", - "type": "uint256" - }, - { - "indexed": false, - "name": "Arg1", - "type": "bytes" - }, - { - "indexed": false, - "name": "Arg2", - "type": "bytes" - } - ], - "name": "ForkReported", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "NodeAddress", - "type": "address" - }, - { - "indexed": false, - "name": "Amount", - "type": "uint256" - } - ], - "name": "Fined", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "NodeAddress", - "type": "address" - }, - { - "indexed": false, - "name": "Amount", - "type": "uint256" - } - ], - "name": "FinePaid", - "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": "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": "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" - } -] -` diff --git a/core/vm/governance_test.go b/core/vm/governance_test.go deleted file mode 100644 index 292e4ef1d..000000000 --- a/core/vm/governance_test.go +++ /dev/null @@ -1,1017 +0,0 @@ -// Copyright 2018 The dexon-consensus Authors -// This file is part of the dexon-consensus library. -// -// The dexon-consensus library is free software: you can redistribute it -// and/or modify it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of the License, -// or (at your option) any later version. -// -// The dexon-consensus library is distributed in the hope that it will be -// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the dexon-consensus library. If not, see -// . - -package vm - -import ( - "bytes" - "crypto/ecdsa" - "math/big" - "math/rand" - "sort" - "testing" - "time" - - coreCommon "github.com/dexon-foundation/dexon-consensus/common" - coreCrypto "github.com/dexon-foundation/dexon-consensus/core/crypto" - coreEcdsa "github.com/dexon-foundation/dexon-consensus/core/crypto/ecdsa" - coreTypes "github.com/dexon-foundation/dexon-consensus/core/types" - coreUtils "github.com/dexon-foundation/dexon-consensus/core/utils" - - "github.com/dexon-foundation/dexon/common" - "github.com/dexon-foundation/dexon/core/state" - "github.com/dexon-foundation/dexon/crypto" - "github.com/dexon-foundation/dexon/ethdb" - "github.com/dexon-foundation/dexon/params" - "github.com/dexon-foundation/dexon/rlp" - "github.com/stretchr/testify/suite" -) - -func init() { - rand.Seed(time.Now().UnixNano()) -} - -func randomBytes(minLength, maxLength int32) []byte { - length := rand.Int31()%(maxLength-minLength) + minLength - b := make([]byte, length) - for i := range b { - b[i] = byte(65 + rand.Int31()%60) - } - return b -} - -type GovernanceStateHelperTestSuite struct { - suite.Suite - - s *GovernanceStateHelper -} - -func (g *GovernanceStateHelperTestSuite) SetupTest() { - db := state.NewDatabase(ethdb.NewMemDatabase()) - statedb, err := state.New(common.Hash{}, db) - if err != nil { - panic(err) - } - g.s = &GovernanceStateHelper{statedb} -} - -func (g *GovernanceStateHelperTestSuite) TestReadWriteBytes() { - for i := 0; i < 100; i++ { - // Short bytes. - loc := big.NewInt(rand.Int63()) - data := randomBytes(3, 32) - g.s.writeBytes(loc, data) - read := g.s.readBytes(loc) - g.Require().Equal(0, bytes.Compare(data, read)) - - // long bytes. - loc = big.NewInt(rand.Int63()) - data = randomBytes(33, 2560) - g.s.writeBytes(loc, data) - read = g.s.readBytes(loc) - g.Require().Equal(0, bytes.Compare(data, read)) - } -} - -func TestGovernanceStateHelper(t *testing.T) { - suite.Run(t, new(GovernanceStateHelperTestSuite)) -} - -type GovernanceContractTestSuite struct { - suite.Suite - - config *params.DexconConfig - memDB *ethdb.MemDatabase - stateDB *state.StateDB - s *GovernanceStateHelper -} - -func (g *GovernanceContractTestSuite) SetupTest() { - memDB := ethdb.NewMemDatabase() - stateDB, err := state.New(common.Hash{}, state.NewDatabase(memDB)) - if err != nil { - panic(err) - } - g.memDB = memDB - g.stateDB = stateDB - g.s = &GovernanceStateHelper{stateDB} - - config := params.TestnetChainConfig.Dexcon - config.LockupPeriod = 1000 - config.NextHalvingSupply = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2.5e9)) - config.LastHalvedAmount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1.5e9)) - config.MiningVelocity = 0.1875 - - g.config = config - - // Give governance contract balance so it will not be deleted because of being an empty state object. - stateDB.AddBalance(GovernanceContractAddress, big.NewInt(1)) - - // Genesis CRS. - crs := crypto.Keccak256Hash([]byte(config.GenesisCRSText)) - g.s.PushCRS(crs) - - // Round 0 height. - g.s.PushRoundHeight(big.NewInt(0)) - - // Owner. - g.s.SetOwner(g.config.Owner) - - // Governance configuration. - g.s.UpdateConfiguration(config) - - g.stateDB.Commit(true) -} - -func (g *GovernanceContractTestSuite) newPrefundAccount() (*ecdsa.PrivateKey, common.Address) { - privKey, err := crypto.GenerateKey() - if err != nil { - panic(err) - } - address := crypto.PubkeyToAddress(privKey.PublicKey) - - g.stateDB.AddBalance(address, new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2e6))) - return privKey, address -} - -func (g *GovernanceContractTestSuite) call(caller common.Address, input []byte, value *big.Int) ([]byte, error) { - context := Context{ - CanTransfer: func(db StateDB, addr common.Address, amount *big.Int) bool { - return db.GetBalance(addr).Cmp(amount) >= 0 - }, - Transfer: func(db StateDB, sender common.Address, recipient common.Address, amount *big.Int) { - db.SubBalance(sender, amount) - db.AddBalance(recipient, amount) - }, - GetRoundHeight: func(round uint64) (uint64, bool) { - switch round { - case 0: - return 0, true - case 1: - return 1000, true - case 2: - return 2000, true - } - return 0, false - }, - Time: big.NewInt(time.Now().UnixNano() / 1000000), - BlockNumber: big.NewInt(0), - } - - evm := NewEVM(context, g.stateDB, params.TestChainConfig, Config{IsBlockProposer: true}) - ret, _, err := evm.Call(AccountRef(caller), GovernanceContractAddress, input, 10000000, value) - return ret, err -} - -func (g *GovernanceContractTestSuite) TestTransferOwnership() { - _, addr := g.newPrefundAccount() - - input, err := abiObject.Pack("transferOwnership", addr) - g.Require().NoError(err) - - // Call with non-owner. - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NotNil(err) - - // Call with owner. - _, err = g.call(g.config.Owner, input, big.NewInt(0)) - g.Require().NoError(err) - g.Require().Equal(addr, g.s.Owner()) -} - -func (g *GovernanceContractTestSuite) TestStakeUnstakeWithoutExtraDelegators() { - privKey, addr := g.newPrefundAccount() - pk := crypto.FromECDSAPub(&privKey.PublicKey) - - // Stake. - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)) - balanceBeforeStake := g.stateDB.GetBalance(addr) - input, err := abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(addr, input, amount) - g.Require().NoError(err) - - g.Require().Equal(1, int(g.s.LenNodes().Uint64())) - g.Require().Equal(1, len(g.s.QualifiedNodes())) - g.Require().Equal("Test1", g.s.Node(big.NewInt(0)).Name) - g.Require().Equal(amount.String(), g.s.TotalStaked().String()) - - // Check balance. - g.Require().Equal(new(big.Int).Sub(balanceBeforeStake, amount), g.stateDB.GetBalance(addr)) - g.Require().Equal(new(big.Int).Add(big.NewInt(1), amount), g.stateDB.GetBalance(GovernanceContractAddress)) - - // Staking again should fail. - _, err = g.call(addr, input, amount) - g.Require().NotNil(err) - - // Unstake. - input, err = abiObject.Pack("unstake") - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - g.Require().Equal(0, len(g.s.QualifiedNodes())) - g.Require().Equal(1, int(g.s.LenDelegators(addr).Uint64())) - g.Require().Equal(1, int(g.s.LenNodes().Uint64())) - - node := g.s.Node(big.NewInt(0)) - g.Require().Equal(big.NewInt(0).String(), node.Staked.String()) - g.Require().Equal(big.NewInt(0).String(), g.s.TotalStaked().String()) - - // Wait for lockup time than withdraw. - time.Sleep(time.Second * 2) - input, err = abiObject.Pack("withdraw", addr) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - g.Require().Equal(0, len(g.s.QualifiedNodes())) - g.Require().Equal(0, int(g.s.LenDelegators(addr).Uint64())) - g.Require().Equal(0, int(g.s.LenNodes().Uint64())) - - // Stake 2 nodes, and unstake the first then the second. - - // 2nd node Stake. - privKey2, addr2 := g.newPrefundAccount() - pk2 := crypto.FromECDSAPub(&privKey2.PublicKey) - input, err = abiObject.Pack("stake", pk2, "Test2", "test2@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(addr2, input, amount) - g.Require().NoError(err) - g.Require().Equal("Test2", g.s.Node(big.NewInt(0)).Name) - g.Require().Equal(0, int(g.s.NodesOffsetByAddress(addr2).Int64())) - - // 1st node Stake. - input, err = abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(addr, input, amount) - g.Require().NoError(err) - - g.Require().Equal(2, len(g.s.QualifiedNodes())) - g.Require().Equal(new(big.Int).Mul(amount, big.NewInt(2)).String(), g.s.TotalStaked().String()) - - // 2nd node Unstake. - input, err = abiObject.Pack("unstake") - g.Require().NoError(err) - _, err = g.call(addr2, input, big.NewInt(0)) - g.Require().NoError(err) - node = g.s.Node(big.NewInt(0)) - g.Require().Equal("Test2", node.Name) - g.Require().Equal(big.NewInt(0).String(), node.Staked.String()) - g.Require().Equal(1, len(g.s.QualifiedNodes())) - g.Require().Equal(amount.String(), g.s.TotalStaked().String()) - - time.Sleep(time.Second * 2) - input, err = abiObject.Pack("withdraw", addr2) - g.Require().NoError(err) - _, err = g.call(addr2, input, big.NewInt(0)) - g.Require().NoError(err) - g.Require().Equal(1, len(g.s.QualifiedNodes())) - - g.Require().Equal(1, int(g.s.LenNodes().Uint64())) - g.Require().Equal("Test1", g.s.Node(big.NewInt(0)).Name) - g.Require().Equal(-1, int(g.s.NodesOffsetByAddress(addr2).Int64())) - - // 1st node Unstake. - input, err = abiObject.Pack("unstake") - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - g.Require().Equal(0, len(g.s.QualifiedNodes())) - g.Require().Equal(big.NewInt(0).String(), g.s.TotalStaked().String()) - - time.Sleep(time.Second * 2) - input, err = abiObject.Pack("withdraw", addr) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - g.Require().Equal(0, int(g.s.LenNodes().Uint64())) - g.Require().Equal(-1, int(g.s.NodesOffsetByAddress(addr).Int64())) - g.Require().Equal(-1, int(g.s.DelegatorsOffset(addr, addr).Int64())) - - // Check balance. - g.Require().Equal(balanceBeforeStake, g.stateDB.GetBalance(addr)) - g.Require().Equal(balanceBeforeStake, g.stateDB.GetBalance(addr2)) - g.Require().Equal(big.NewInt(1), g.stateDB.GetBalance(GovernanceContractAddress)) -} - -func (g *GovernanceContractTestSuite) TestDelegateUndelegate() { - privKey, addr := g.newPrefundAccount() - pk := crypto.FromECDSAPub(&privKey.PublicKey) - - // Stake. - input, err := abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - ownerStaked := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - _, err = g.call(addr, input, ownerStaked) - g.Require().NoError(err) - g.Require().Equal(0, len(g.s.QualifiedNodes())) - g.Require().Equal(addr, g.s.Delegator(addr, big.NewInt(0)).Owner) - g.Require().Equal(ownerStaked, g.s.Node(big.NewInt(0)).Staked) - - // 1st delegator delegate to 1st node. - _, addrDelegator := g.newPrefundAccount() - - balanceBeforeDelegate := g.stateDB.GetBalance(addrDelegator) - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3e5)) - input, err = abiObject.Pack("delegate", addr) - g.Require().NoError(err) - - _, err = g.call(addrDelegator, input, amount) - g.Require().NoError(err) - g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator)) - g.Require().Equal(addrDelegator, g.s.Delegator(addr, big.NewInt(1)).Owner) - g.Require().Equal(new(big.Int).Add(amount, ownerStaked), g.s.Node(big.NewInt(0)).Staked) - g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String()) - g.Require().Equal(1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64())) - - // Same person delegate the 2nd time should fail. - _, err = g.call(addrDelegator, input, big.NewInt(1e18)) - g.Require().NotNil(err) - - // Not yet qualified. - g.Require().Equal(0, len(g.s.QualifiedNodes())) - - // 2nd delegator delegate to 1st node. - _, addrDelegator2 := g.newPrefundAccount() - _, err = g.call(addrDelegator2, input, amount) - g.Require().NoError(err) - g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator2)) - g.Require().Equal(addrDelegator2, g.s.Delegator(addr, big.NewInt(2)).Owner) - g.Require().Equal(new(big.Int).Add(ownerStaked, new(big.Int).Mul(amount, big.NewInt(2))), - g.s.Node(big.NewInt(0)).Staked) - g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String()) - g.Require().Equal(2, int(g.s.DelegatorsOffset(addr, addrDelegator2).Int64())) - - // Qualified. - g.Require().Equal(1, len(g.s.QualifiedNodes())) - - // Undelegate addrDelegator. - balanceBeforeUnDelegate := g.stateDB.GetBalance(addrDelegator) - input, err = abiObject.Pack("undelegate", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator, input, big.NewInt(0)) - g.Require().Equal(new(big.Int).Add(amount, ownerStaked), g.s.Node(big.NewInt(0)).Staked) - g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String()) - g.Require().NoError(err) - - // Undelegate the second time should fail. - _, err = g.call(addrDelegator, input, big.NewInt(0)) - g.Require().Error(err) - - // Withdraw within lockup time should fail. - input, err = abiObject.Pack("withdraw", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator, input, big.NewInt(0)) - g.Require().NotNil(err) - - g.Require().Equal(3, int(g.s.LenDelegators(addr).Uint64())) - g.Require().Equal(balanceBeforeUnDelegate, g.stateDB.GetBalance(addrDelegator)) - g.Require().NotEqual(-1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64())) - - // Wait for lockup time than withdraw. - time.Sleep(time.Second * 2) - input, err = abiObject.Pack("withdraw", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator, input, big.NewInt(0)) - g.Require().NoError(err) - - g.Require().Equal(2, int(g.s.LenDelegators(addr).Uint64())) - g.Require().Equal(new(big.Int).Add(balanceBeforeUnDelegate, amount), g.stateDB.GetBalance(addrDelegator)) - g.Require().Equal(-1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64())) - - // Withdraw when their is no delegation should fail. - time.Sleep(time.Second) - input, err = abiObject.Pack("withdraw", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator, input, big.NewInt(0)) - g.Require().Error(err) - - // Undelegate addrDelegator2. - balanceBeforeUnDelegate = g.stateDB.GetBalance(addrDelegator2) - input, err = abiObject.Pack("undelegate", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator2, input, big.NewInt(0)) - g.Require().NoError(err) - - g.Require().Equal(ownerStaked, g.s.Node(big.NewInt(0)).Staked) - g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String()) - - // Wait for lockup time than withdraw. - time.Sleep(time.Second * 2) - input, err = abiObject.Pack("withdraw", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator2, input, big.NewInt(0)) - g.Require().NoError(err) - - g.Require().Equal(1, int(g.s.LenDelegators(addr).Uint64())) - g.Require().Equal(new(big.Int).Add(balanceBeforeUnDelegate, amount), g.stateDB.GetBalance(addrDelegator2)) - g.Require().Equal(-1, int(g.s.DelegatorsOffset(addr, addrDelegator2).Int64())) - - // Unqualified - g.Require().Equal(0, len(g.s.QualifiedNodes())) - - // Owner undelegate itself. - g.Require().Equal(1, int(g.s.LenNodes().Uint64())) - g.Require().Equal(1, int(g.s.LenDelegators(addr).Uint64())) - - input, err = abiObject.Pack("undelegate", addr) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - g.Require().Equal(big.NewInt(0).String(), g.s.Node(big.NewInt(0)).Staked.String()) - g.Require().Equal(big.NewInt(0).String(), g.s.TotalStaked().String()) - - time.Sleep(time.Second * 2) - input, err = abiObject.Pack("withdraw", addr) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - - g.Require().Equal(0, int(g.s.LenNodes().Uint64())) - g.Require().Equal(0, int(g.s.LenDelegators(addr).Uint64())) -} - -func (g *GovernanceContractTestSuite) TestFine() { - privKey, addr := g.newPrefundAccount() - pk := crypto.FromECDSAPub(&privKey.PublicKey) - - // Stake. - input, err := abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - ownerStaked := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - _, err = g.call(addr, input, ownerStaked) - g.Require().NoError(err) - g.Require().Equal(0, len(g.s.QualifiedNodes())) - g.Require().Equal(addr, g.s.Delegator(addr, big.NewInt(0)).Owner) - g.Require().Equal(ownerStaked, g.s.Node(big.NewInt(0)).Staked) - - // 1st delegator delegate to 1st node. - _, addrDelegator := g.newPrefundAccount() - - balanceBeforeDelegate := g.stateDB.GetBalance(addrDelegator) - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - input, err = abiObject.Pack("delegate", addr) - g.Require().NoError(err) - - _, err = g.call(addrDelegator, input, amount) - g.Require().NoError(err) - g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator)) - g.Require().Equal(addrDelegator, g.s.Delegator(addr, big.NewInt(1)).Owner) - g.Require().Equal(new(big.Int).Add(amount, ownerStaked), g.s.Node(big.NewInt(0)).Staked) - g.Require().Equal(1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64())) - - // Qualified. - g.Require().Equal(1, len(g.s.QualifiedNodes())) - - // Paying to node without fine should fail. - input, err = abiObject.Pack("payFine", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator, input, amount) - g.Require().NotNil(err) - - // Fined. - offset := g.s.NodesOffsetByAddress(addr) - g.Require().True(offset.Cmp(big.NewInt(0)) >= 0) - node := g.s.Node(offset) - node.Fined = new(big.Int).Set(amount) - g.s.UpdateNode(offset, node) - node = g.s.Node(offset) - g.Require().Equal(0, node.Fined.Cmp(amount)) - - // Not qualified after fined. - g.Require().Equal(0, len(g.s.QualifiedNodes())) - - // Cannot undelegate before fines are paied. - input, err = abiObject.Pack("undelegate", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator, input, big.NewInt(0)) - g.Require().NotNil(err) - - // Only delegators can pay fine. - _, addrDelegator2 := g.newPrefundAccount() - input, err = abiObject.Pack("payFine", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator2, input, big.NewInt(5e5)) - g.Require().NotNil(err) - - // Paying more than fine should fail. - payAmount := new(big.Int).Add(amount, amount) - input, err = abiObject.Pack("payFine", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator, input, payAmount) - g.Require().NotNil(err) - - // Pay the fine. - input, err = abiObject.Pack("payFine", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator, input, amount) - g.Require().NoError(err) - - // Qualified. - g.Require().Equal(1, len(g.s.QualifiedNodes())) - - // Can undelegate after all fines are paied. - input, err = abiObject.Pack("undelegate", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator, input, big.NewInt(0)) - g.Require().NoError(err) -} - -func (g *GovernanceContractTestSuite) TestUnstakeWithExtraDelegators() { - privKey, addr := g.newPrefundAccount() - pk := crypto.FromECDSAPub(&privKey.PublicKey) - - // Stake. - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - input, err := abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(addr, input, amount) - g.Require().NoError(err) - - // 1st delegator delegate to 1st node. - _, addrDelegator := g.newPrefundAccount() - - balanceBeforeDelegate := g.stateDB.GetBalance(addrDelegator) - amount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3e5)) - input, err = abiObject.Pack("delegate", addr) - g.Require().NoError(err) - - _, err = g.call(addrDelegator, input, amount) - g.Require().NoError(err) - g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator)) - g.Require().Equal(addrDelegator, g.s.Delegator(addr, big.NewInt(1)).Owner) - g.Require().Equal(0, len(g.s.QualifiedNodes())) - - // 2st delegator delegate to 1st node. - _, addrDelegator2 := g.newPrefundAccount() - - balanceBeforeDelegate = g.stateDB.GetBalance(addrDelegator2) - input, err = abiObject.Pack("delegate", addr) - g.Require().NoError(err) - - _, err = g.call(addrDelegator2, input, amount) - g.Require().NoError(err) - g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator2)) - g.Require().Equal(addrDelegator2, g.s.Delegator(addr, big.NewInt(2)).Owner) - - // Node is now qualified. - g.Require().Equal(1, len(g.s.QualifiedNodes())) - - // Unstake. - input, err = abiObject.Pack("unstake") - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - time.Sleep(time.Second * 2) - input, err = abiObject.Pack("withdraw", addr) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - _, err = g.call(addrDelegator, input, big.NewInt(0)) - g.Require().NoError(err) - _, err = g.call(addrDelegator2, input, big.NewInt(0)) - g.Require().NoError(err) - - g.Require().Equal(0, int(g.s.LenDelegators(addr).Uint64())) - g.Require().Equal(0, int(g.s.LenNodes().Uint64())) - - // Check balance. - g.Require().Equal(balanceBeforeDelegate, g.stateDB.GetBalance(addr)) - g.Require().Equal(balanceBeforeDelegate, g.stateDB.GetBalance(addrDelegator)) - g.Require().Equal(balanceBeforeDelegate, g.stateDB.GetBalance(addrDelegator2)) - g.Require().Equal(big.NewInt(1), g.stateDB.GetBalance(GovernanceContractAddress)) -} - -func (g *GovernanceContractTestSuite) TestUpdateConfiguration() { - _, addr := g.newPrefundAccount() - - input, err := abiObject.Pack("updateConfiguration", - new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)), - big.NewInt(1000), - big.NewInt(8000000), - big.NewInt(6), - big.NewInt(250), - big.NewInt(2500), - big.NewInt(0), - big.NewInt(667000), - big.NewInt(4), - big.NewInt(4), - big.NewInt(600000), - big.NewInt(900), - []*big.Int{big.NewInt(1), big.NewInt(1), big.NewInt(1)}) - g.Require().NoError(err) - - // Call with non-owner. - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NotNil(err) - - // Call with owner. - _, err = g.call(g.config.Owner, input, big.NewInt(0)) - g.Require().NoError(err) -} - -func (g *GovernanceContractTestSuite) TestConfigurationReading() { - _, addr := g.newPrefundAccount() - - // CRS. - input, err := abiObject.Pack("crs", big.NewInt(0)) - g.Require().NoError(err) - res, err := g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - var crs0 [32]byte - err = abiObject.Unpack(&crs0, "crs", res) - g.Require().NoError(err) - g.Require().Equal(crypto.Keccak256Hash([]byte(g.config.GenesisCRSText)), common.BytesToHash(crs0[:])) - - // Owner. - input, err = abiObject.Pack("owner") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - var owner common.Address - err = abiObject.Unpack(&owner, "owner", res) - g.Require().NoError(err) - g.Require().Equal(g.config.Owner, owner) - - // MinStake. - input, err = abiObject.Pack("minStake") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - var value *big.Int - err = abiObject.Unpack(&value, "minStake", res) - g.Require().NoError(err) - g.Require().Equal(g.config.MinStake.String(), value.String()) - - // BlockReward. - input, err = abiObject.Pack("miningVelocity") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "miningVelocity", res) - g.Require().NoError(err) - g.Require().Equal(g.config.MiningVelocity, float32(value.Uint64())/decimalMultiplier) - - // BlockGasLimit. - input, err = abiObject.Pack("blockGasLimit") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "blockGasLimit", res) - g.Require().NoError(err) - g.Require().Equal(g.config.BlockGasLimit, value.Uint64()) - - // NumChains. - input, err = abiObject.Pack("numChains") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "numChains", res) - g.Require().NoError(err) - g.Require().Equal(g.config.NumChains, uint32(value.Uint64())) - - // LambdaBA. - input, err = abiObject.Pack("lambdaBA") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "lambdaBA", res) - g.Require().NoError(err) - g.Require().Equal(g.config.LambdaBA, value.Uint64()) - - // LambdaDKG. - input, err = abiObject.Pack("lambdaDKG") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "lambdaDKG", res) - g.Require().NoError(err) - g.Require().Equal(g.config.LambdaDKG, value.Uint64()) - - // K. - input, err = abiObject.Pack("k") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "k", res) - g.Require().NoError(err) - g.Require().Equal(g.config.K, uint32(value.Uint64())) - - // PhiRatio. - input, err = abiObject.Pack("phiRatio") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "phiRatio", res) - g.Require().NoError(err) - g.Require().Equal(g.config.PhiRatio, float32(value.Uint64())/decimalMultiplier) - - // NotarySetSize. - input, err = abiObject.Pack("notarySetSize") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "notarySetSize", res) - g.Require().NoError(err) - g.Require().Equal(g.config.NotarySetSize, uint32(value.Uint64())) - - // DKGSetSize. - input, err = abiObject.Pack("dkgSetSize") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "dkgSetSize", res) - g.Require().NoError(err) - g.Require().Equal(g.config.DKGSetSize, uint32(value.Uint64())) - - // RoundInterval. - input, err = abiObject.Pack("roundInterval") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "roundInterval", res) - g.Require().NoError(err) - g.Require().Equal(g.config.RoundInterval, value.Uint64()) - - // MinBlockInterval. - input, err = abiObject.Pack("minBlockInterval") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "minBlockInterval", res) - g.Require().NoError(err) - g.Require().Equal(g.config.MinBlockInterval, value.Uint64()) -} - -func (g *GovernanceContractTestSuite) TestReportForkVote() { - key, addr := g.newPrefundAccount() - pkBytes := crypto.FromECDSAPub(&key.PublicKey) - - // Stake. - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - input, err := abiObject.Pack("stake", pkBytes, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(addr, input, amount) - g.Require().NoError(err) - - pubKey := coreEcdsa.NewPublicKeyFromECDSA(&key.PublicKey) - privKey := coreEcdsa.NewPrivateKeyFromECDSA(key) - vote1 := coreTypes.NewVote(coreTypes.VoteCom, coreCommon.NewRandomHash(), uint64(0)) - vote1.ProposerID = coreTypes.NewNodeID(pubKey) - - vote2 := vote1.Clone() - for vote2.BlockHash == vote1.BlockHash { - vote2.BlockHash = coreCommon.NewRandomHash() - } - vote1.Signature, err = privKey.Sign(coreUtils.HashVote(vote1)) - g.Require().NoError(err) - vote2.Signature, err = privKey.Sign(coreUtils.HashVote(vote2)) - g.Require().NoError(err) - - vote1Bytes, err := rlp.EncodeToBytes(vote1) - g.Require().NoError(err) - vote2Bytes, err := rlp.EncodeToBytes(vote2) - g.Require().NoError(err) - - // Report wrong type (fork block) - input, err = abiObject.Pack("report", big.NewInt(2), vote1Bytes, vote2Bytes) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().Error(err) - - input, err = abiObject.Pack("report", big.NewInt(1), vote1Bytes, vote2Bytes) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - node := g.s.Node(big.NewInt(0)) - g.Require().Equal(node.Fined, g.s.FineValue(big.NewInt(1))) - - // Duplicate report should fail. - input, err = abiObject.Pack("report", big.NewInt(1), vote1Bytes, vote2Bytes) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().Error(err) - - // Check if finedRecords is set. - payloads := [][]byte{vote1Bytes, vote2Bytes} - sort.Sort(sortBytes(payloads)) - - hash := Bytes32(crypto.Keccak256Hash(payloads...)) - input, err = abiObject.Pack("finedRecords", hash) - g.Require().NoError(err) - res, err := g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - var value bool - err = abiObject.Unpack(&value, "finedRecords", res) - g.Require().NoError(err) - g.Require().True(value) -} - -func (g *GovernanceContractTestSuite) TestReportForkBlock() { - key, addr := g.newPrefundAccount() - pkBytes := crypto.FromECDSAPub(&key.PublicKey) - - // Stake. - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - input, err := abiObject.Pack("stake", pkBytes, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(addr, input, amount) - g.Require().NoError(err) - - privKey := coreEcdsa.NewPrivateKeyFromECDSA(key) - block1 := &coreTypes.Block{ - ProposerID: coreTypes.NewNodeID(privKey.PublicKey()), - ParentHash: coreCommon.NewRandomHash(), - Timestamp: time.Now(), - } - - block2 := block1.Clone() - for block2.ParentHash == block1.ParentHash { - block2.ParentHash = coreCommon.NewRandomHash() - } - - hashBlock := func(block *coreTypes.Block) coreCommon.Hash { - block.PayloadHash = coreCrypto.Keccak256Hash(block.Payload) - var err error - block.Hash, err = coreUtils.HashBlock(block) - g.Require().NoError(err) - return block.Hash - } - - block1.Signature, err = privKey.Sign(hashBlock(block1)) - g.Require().NoError(err) - block2.Signature, err = privKey.Sign(hashBlock(block2)) - g.Require().NoError(err) - - block1Bytes, err := rlp.EncodeToBytes(block1) - g.Require().NoError(err) - block2Bytes, err := rlp.EncodeToBytes(block2) - g.Require().NoError(err) - - // Report wrong type (fork vote) - input, err = abiObject.Pack("report", big.NewInt(1), block1Bytes, block2Bytes) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().Error(err) - - input, err = abiObject.Pack("report", big.NewInt(2), block1Bytes, block2Bytes) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - node := g.s.Node(big.NewInt(0)) - g.Require().Equal(node.Fined, g.s.FineValue(big.NewInt(2))) - - // Duplicate report should fail. - input, err = abiObject.Pack("report", big.NewInt(2), block1Bytes, block2Bytes) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().Error(err) - - // Check if finedRecords is set. - payloads := [][]byte{block1Bytes, block2Bytes} - sort.Sort(sortBytes(payloads)) - - hash := Bytes32(crypto.Keccak256Hash(payloads...)) - input, err = abiObject.Pack("finedRecords", hash) - g.Require().NoError(err) - res, err := g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - var value bool - err = abiObject.Unpack(&value, "finedRecords", res) - g.Require().NoError(err) - g.Require().True(value) -} - -func (g *GovernanceContractTestSuite) TestMiscVariableReading() { - privKey, addr := g.newPrefundAccount() - pk := crypto.FromECDSAPub(&privKey.PublicKey) - - input, err := abiObject.Pack("totalSupply") - g.Require().NoError(err) - res, err := g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - input, err = abiObject.Pack("totalStaked") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - // Stake. - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - input, err = abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(addr, input, amount) - g.Require().NoError(err) - - // 1st delegator delegate to 1st node. - _, addrDelegator := g.newPrefundAccount() - amount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3e5)) - input, err = abiObject.Pack("delegate", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator, input, amount) - g.Require().NoError(err) - - // 2st delegator delegate to 1st node. - _, addrDelegator2 := g.newPrefundAccount() - input, err = abiObject.Pack("delegate", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator2, input, amount) - g.Require().NoError(err) - - input, err = abiObject.Pack("nodes", big.NewInt(0)) - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - input, err = abiObject.Pack("nodesLength") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - var value *big.Int - err = abiObject.Unpack(&value, "nodesLength", res) - g.Require().NoError(err) - g.Require().Equal(1, int(value.Uint64())) - - input, err = abiObject.Pack("nodesOffsetByAddress", addr) - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "nodesOffsetByAddress", res) - g.Require().NoError(err) - g.Require().Equal(0, int(value.Uint64())) - - id, err := publicKeyToNodeID(pk) - g.Require().NoError(err) - input, err = abiObject.Pack("nodesOffsetByID", id) - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "nodesOffsetByID", res) - g.Require().NoError(err) - g.Require().Equal(0, int(value.Uint64())) - - input, err = abiObject.Pack("delegators", addr, big.NewInt(0)) - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - input, err = abiObject.Pack("delegatorsLength", addr) - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "delegatorsLength", res) - g.Require().NoError(err) - g.Require().Equal(3, int(value.Uint64())) - - input, err = abiObject.Pack("delegatorsOffset", addr, addrDelegator2) - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "delegatorsOffset", res) - g.Require().NoError(err) - g.Require().Equal(2, int(value.Uint64())) - - input, err = abiObject.Pack("fineValues", big.NewInt(0)) - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) -} - -func (g *GovernanceContractTestSuite) TestHalvingCondition() { - // TotalSupply 2.5B reached - g.s.MiningHalved() - g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3.25e9)).String(), - g.s.NextHalvingSupply().String()) - g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(0.75e9)).String(), - g.s.LastHalvedAmount().String()) - - // TotalSupply 3.25B reached - g.s.MiningHalved() - g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3.625e9)).String(), - g.s.NextHalvingSupply().String()) - g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(0.375e9)).String(), - g.s.LastHalvedAmount().String()) -} - -func TestGovernanceContract(t *testing.T) { - suite.Run(t, new(GovernanceContractTestSuite)) -} diff --git a/core/vm/oracle.go b/core/vm/oracle.go new file mode 100644 index 000000000..493736e8c --- /dev/null +++ b/core/vm/oracle.go @@ -0,0 +1,88 @@ +// Copyright 2019 The dexon-consensus Authors +// This file is part of the dexon-consensus library. +// +// The dexon-consensus library is free software: you can redistribute it +// and/or modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation, either version 3 of the License, +// or (at your option) any later version. +// +// The dexon-consensus library is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +// General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the dexon-consensus library. If not, see +// . + +package vm + +import ( + "strings" + + "github.com/dexon-foundation/dexon/accounts/abi" + "github.com/dexon-foundation/dexon/common" +) + +var GovernanceContractAddress = common.HexToAddress("63751838d6485578b23e8b051d40861ecc416794") +var NodeInfoOracleAddress = common.HexToAddress("58a7c88ad1f32e7252bebba54def98d3e7b3df11") + +var GovernanceABI *OracleContractABI +var NodeInfoOracleABI *OracleContractABI + +func init() { + GovernanceABI = NewOracleContractABI(GovernanceABIJSON) + NodeInfoOracleABI = NewOracleContractABI(NodeInfoOracleABIJSON) +} + +// OracleContract represent special system contracts written in Go. +type OracleContract interface { + Run(evm *EVM, input []byte, contract *Contract) (ret []byte, err error) +} + +// A map representing available system oracle contracts. +var OracleContracts = map[common.Address]OracleContract{ + GovernanceContractAddress: &GovernanceContract{}, + NodeInfoOracleAddress: &NodeInfoOracleContract{}, +} + +// Run oracle contract. +func RunOracleContract(oracle OracleContract, evm *EVM, input []byte, contract *Contract) (ret []byte, err error) { + return oracle.Run(evm, input, contract) +} + +// OracleContractABI represents ABI information for a given contract. +type OracleContractABI struct { + ABI abi.ABI + Name2Method map[string]abi.Method + Sig2Method map[string]abi.Method + Events map[string]abi.Event +} + +// NewOracleContractABI parse the ABI. +func NewOracleContractABI(abiDefinition string) *OracleContractABI { + abiObject, err := abi.JSON(strings.NewReader(abiDefinition)) + if err != nil { + panic(err) + } + + sig2Method := make(map[string]abi.Method) + name2Method := make(map[string]abi.Method) + + for _, method := range abiObject.Methods { + sig2Method[string(method.Id())] = method + name2Method[method.Name] = method + } + + events := make(map[string]abi.Event) + for _, event := range abiObject.Events { + events[event.Name] = event + } + + return &OracleContractABI{ + ABI: abiObject, + Name2Method: name2Method, + Sig2Method: sig2Method, + Events: events, + } +} diff --git a/core/vm/oracle_contract_abi.go b/core/vm/oracle_contract_abi.go new file mode 100644 index 000000000..1c630c1c8 --- /dev/null +++ b/core/vm/oracle_contract_abi.go @@ -0,0 +1,1198 @@ +// Copyright 2019 The dexon-consensus Authors +// This file is part of the dexon-consensus library. +// +// The dexon-consensus library is free software: you can redistribute it +// and/or modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation, either version 3 of the License, +// or (at your option) any later version. +// +// The dexon-consensus library is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +// General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the dexon-consensus library. If not, see +// . + +package vm + +// The governance ABI is generated from: +// https://github.com/dexon-foundation/governance-abi + +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": "", + "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": "totalSupply", + "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" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "miningVelocity", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "lambdaBA", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "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": "totalStaked", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "roundInterval", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "nodesOffsetByAddress", + "outputs": [ + { + "name": "", + "type": "int256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "nextHalvingSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "lastHalvedAmount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "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" + }, + { + "indexed": false, + "name": "Amount", + "type": "uint256" + } + ], + "name": "Undelegated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" + }, + { + "indexed": false, + "name": "Amount", + "type": "uint256" + } + ], + "name": "Withdrawn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" + }, + { + "indexed": false, + "name": "Type", + "type": "uint256" + }, + { + "indexed": false, + "name": "Arg1", + "type": "bytes" + }, + { + "indexed": false, + "name": "Arg2", + "type": "bytes" + } + ], + "name": "ForkReported", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" + }, + { + "indexed": false, + "name": "Amount", + "type": "uint256" + } + ], + "name": "Fined", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" + }, + { + "indexed": false, + "name": "Amount", + "type": "uint256" + } + ], + "name": "FinePaid", + "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": "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": "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" + } +] +` + +const NodeInfoOracleABIJSON = ` +[ + { + "constant": true, + "inputs": [ + { + "name": "Round", + "type": "uint256" + }, + { + "name": "NodeAddress", + "type": "address" + }, + { + "name": "Index", + "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": "Round", + "type": "uint256" + }, + { + "name": "NodeAddress", + "type": "address" + } + ], + "name": "delegatorsLength", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "Round", + "type": "uint256" + }, + { + "name": "NodeAddress", + "type": "address" + }, + { + "name": "DelegatorAddress", + "type": "address" + } + ], + "name": "delegatorsOffset", + "outputs": [ + { + "name": "", + "type": "int256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } +] +` diff --git a/core/vm/oracle_contracts.go b/core/vm/oracle_contracts.go new file mode 100644 index 000000000..5f83ca68f --- /dev/null +++ b/core/vm/oracle_contracts.go @@ -0,0 +1,2316 @@ +// 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" + + "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" +) + +type Bytes32 [32]byte + +type ReportType uint64 + +const ( + ReportTypeInvalidDKG = iota + ReportTypeForkVote + ReportTypeForkBlock +) + +// 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) 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 ¶ms.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 + 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(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{GovernanceABI.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{GovernanceABI.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{GovernanceABI.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{GovernanceABI.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{GovernanceABI.Events["Delegated"].Id(), nodeAddr.Hash(), delegatorAddr.Hash()}, + Data: common.BigToHash(amount).Bytes(), + }) +} + +// event Undelegated(address indexed NodeAddress, address indexed DelegatorAddress, uint256 Amount); +func (s *GovernanceStateHelper) emitUndelegated(nodeAddr, delegatorAddr common.Address, amount *big.Int) { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{GovernanceABI.Events["Undelegated"].Id(), nodeAddr.Hash(), delegatorAddr.Hash()}, + Data: common.BigToHash(amount).Bytes(), + }) +} + +// 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{GovernanceABI.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", nil) + 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{GovernanceABI.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{GovernanceABI.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{GovernanceABI.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 (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) + + // 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, delegator.Value) + + 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 +} + +// Run executes governance contract. +func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (ret []byte, err error) { + if len(input) < 4 { + return nil, errExecutionReverted + } + + // Initialize contract state. + g.evm = evm + g.state = GovernanceStateHelper{evm.StateDB} + g.contract = contract + + // Parse input. + method, exists := GovernanceABI.Sig2Method[string(input[:4])] + if !exists { + return nil, errExecutionReverted + } + + arguments := input[4:] + + // Dispatch method call. + switch method.Name { + case "addDKGComplaint": + 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 "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 +} + +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 PackProposeCRS(round uint64, signedCRS []byte) ([]byte, error) { + method := GovernanceABI.Name2Method["proposeCRS"] + res, err := method.Inputs.Pack(big.NewInt(int64(round)), signedCRS) + if err != nil { + return nil, err + } + data := append(method.Id(), res...) + return data, nil +} + +func PackAddDKGMasterPublicKey(round uint64, mpk *dkgTypes.MasterPublicKey) ([]byte, error) { + method := GovernanceABI.Name2Method["addDKGMasterPublicKey"] + encoded, err := rlp.EncodeToBytes(mpk) + if err != nil { + return nil, err + } + res, err := method.Inputs.Pack(big.NewInt(int64(round)), encoded) + if err != nil { + return nil, err + } + data := append(method.Id(), res...) + return data, nil +} + +func PackAddDKGMPKReady(round uint64, ready *dkgTypes.MPKReady) ([]byte, error) { + method := GovernanceABI.Name2Method["addDKGMPKReady"] + encoded, err := rlp.EncodeToBytes(ready) + if err != nil { + return nil, err + } + res, err := method.Inputs.Pack(big.NewInt(int64(round)), encoded) + if err != nil { + return nil, err + } + data := append(method.Id(), res...) + return data, nil +} + +func PackAddDKGComplaint(round uint64, complaint *dkgTypes.Complaint) ([]byte, error) { + method := GovernanceABI.Name2Method["addDKGComplaint"] + encoded, err := rlp.EncodeToBytes(complaint) + if err != nil { + return nil, err + } + + res, err := method.Inputs.Pack(big.NewInt(int64(round)), encoded) + if err != nil { + return nil, err + } + data := append(method.Id(), res...) + return data, nil +} + +func PackAddDKGFinalize(round uint64, final *dkgTypes.Finalize) ([]byte, error) { + method := GovernanceABI.Name2Method["addDKGFinalize"] + encoded, err := rlp.EncodeToBytes(final) + if err != nil { + return nil, err + } + + res, err := method.Inputs.Pack(big.NewInt(int64(round)), encoded) + if err != nil { + return nil, err + } + data := append(method.Id(), res...) + return data, nil +} + +func PackReportForkVote(vote1, vote2 *coreTypes.Vote) ([]byte, error) { + method := GovernanceABI.Name2Method["report"] + + vote1Bytes, err := rlp.EncodeToBytes(vote1) + if err != nil { + return nil, err + } + + vote2Bytes, err := rlp.EncodeToBytes(vote2) + if err != nil { + return nil, err + } + + res, err := method.Inputs.Pack(big.NewInt(ReportTypeForkVote), vote1Bytes, vote2Bytes) + if err != nil { + return nil, err + } + + data := append(method.Id(), res...) + return data, nil +} + +func PackReportForkBlock(block1, block2 *coreTypes.Block) ([]byte, error) { + method := GovernanceABI.Name2Method["report"] + + block1Bytes, err := rlp.EncodeToBytes(block1) + if err != nil { + return nil, err + } + + block2Bytes, err := rlp.EncodeToBytes(block2) + if err != nil { + return nil, err + } + + res, err := method.Inputs.Pack(big.NewInt(ReportTypeForkBlock), block1Bytes, block2Bytes) + if err != nil { + return nil, err + } + + data := append(method.Id(), res...) + return data, nil +} + +// NodeInfoOracleContract representing a oracle providing the node information. +type NodeInfoOracleContract struct { +} + +func (g *NodeInfoOracleContract) Run(evm *EVM, input []byte, contract *Contract) (ret []byte, err error) { + if len(input) < 4 { + return nil, errExecutionReverted + } + + // Parse input. + method, exists := NodeInfoOracleABI.Sig2Method[string(input[:4])] + if !exists { + return nil, errExecutionReverted + } + + arguments := input[4:] + + getConfigState := func(round *big.Int) (*GovernanceStateHelper, error) { + configRound := big.NewInt(0) + if round.Uint64() >= core.ConfigRoundShift { + configRound = new(big.Int).Sub(round, big.NewInt(int64(core.ConfigRoundShift))) + } + + gs := &GovernanceStateHelper{evm.StateDB} + height := gs.RoundHeight(configRound).Uint64() + if round.Uint64() > 0 && height == 0 { + return nil, errExecutionReverted + } + statedb, err := evm.StateAtNumber(height) + return &GovernanceStateHelper{statedb}, err + } + + // Dispatch method call. + switch method.Name { + case "delegators": + round, nodeAddr, index := new(big.Int), common.Address{}, new(big.Int) + args := []interface{}{&round, &nodeAddr, &index} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + state, err := getConfigState(round) + if err != nil { + return nil, err + } + delegator := 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 "delegatorsLength": + round, address := new(big.Int), common.Address{} + args := []interface{}{&round, &address} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + state, err := getConfigState(round) + if err != nil { + return nil, err + } + res, err := method.Outputs.Pack(state.LenDelegators(address)) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "delegatorsOffset": + round, nodeAddr, delegatorAddr := new(big.Int), common.Address{}, common.Address{} + args := []interface{}{&round, &nodeAddr, &delegatorAddr} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + state, err := getConfigState(round) + if err != nil { + return nil, err + } + res, err := method.Outputs.Pack(state.DelegatorsOffset(nodeAddr, delegatorAddr)) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + } + return nil, errExecutionReverted +} diff --git a/core/vm/oracle_contracts_test.go b/core/vm/oracle_contracts_test.go new file mode 100644 index 000000000..ce2ba825b --- /dev/null +++ b/core/vm/oracle_contracts_test.go @@ -0,0 +1,1063 @@ +// 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" + "crypto/ecdsa" + "math/big" + "math/rand" + "sort" + "testing" + "time" + + coreCommon "github.com/dexon-foundation/dexon-consensus/common" + coreCrypto "github.com/dexon-foundation/dexon-consensus/core/crypto" + coreEcdsa "github.com/dexon-foundation/dexon-consensus/core/crypto/ecdsa" + coreTypes "github.com/dexon-foundation/dexon-consensus/core/types" + coreUtils "github.com/dexon-foundation/dexon-consensus/core/utils" + + "github.com/dexon-foundation/dexon/common" + "github.com/dexon-foundation/dexon/core/state" + "github.com/dexon-foundation/dexon/crypto" + "github.com/dexon-foundation/dexon/ethdb" + "github.com/dexon-foundation/dexon/params" + "github.com/dexon-foundation/dexon/rlp" + "github.com/stretchr/testify/suite" +) + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +func randomBytes(minLength, maxLength int32) []byte { + length := rand.Int31()%(maxLength-minLength) + minLength + b := make([]byte, length) + for i := range b { + b[i] = byte(65 + rand.Int31()%60) + } + return b +} + +type GovernanceStateHelperTestSuite struct { + suite.Suite + + s *GovernanceStateHelper +} + +func (g *GovernanceStateHelperTestSuite) SetupTest() { + db := state.NewDatabase(ethdb.NewMemDatabase()) + statedb, err := state.New(common.Hash{}, db) + if err != nil { + panic(err) + } + g.s = &GovernanceStateHelper{statedb} +} + +func (g *GovernanceStateHelperTestSuite) TestReadWriteBytes() { + for i := 0; i < 100; i++ { + // Short bytes. + loc := big.NewInt(rand.Int63()) + data := randomBytes(3, 32) + g.s.writeBytes(loc, data) + read := g.s.readBytes(loc) + g.Require().Equal(0, bytes.Compare(data, read)) + + // long bytes. + loc = big.NewInt(rand.Int63()) + data = randomBytes(33, 2560) + g.s.writeBytes(loc, data) + read = g.s.readBytes(loc) + g.Require().Equal(0, bytes.Compare(data, read)) + } +} + +func TestGovernanceStateHelper(t *testing.T) { + suite.Run(t, new(GovernanceStateHelperTestSuite)) +} + +type OracleContractsTestSuite struct { + suite.Suite + + config *params.DexconConfig + memDB *ethdb.MemDatabase + stateDB *state.StateDB + s *GovernanceStateHelper +} + +func (g *OracleContractsTestSuite) SetupTest() { + memDB := ethdb.NewMemDatabase() + stateDB, err := state.New(common.Hash{}, state.NewDatabase(memDB)) + if err != nil { + panic(err) + } + g.memDB = memDB + g.stateDB = stateDB + g.s = &GovernanceStateHelper{stateDB} + + config := params.TestnetChainConfig.Dexcon + config.LockupPeriod = 1000 + config.NextHalvingSupply = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2.5e9)) + config.LastHalvedAmount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1.5e9)) + config.MiningVelocity = 0.1875 + + g.config = config + + // Give governance contract balance so it will not be deleted because of being an empty state object. + stateDB.AddBalance(GovernanceContractAddress, big.NewInt(1)) + + // Genesis CRS. + crs := crypto.Keccak256Hash([]byte(config.GenesisCRSText)) + g.s.PushCRS(crs) + + // Round 0 height. + g.s.PushRoundHeight(big.NewInt(0)) + + // Owner. + g.s.SetOwner(g.config.Owner) + + // Governance configuration. + g.s.UpdateConfiguration(config) + + g.stateDB.Commit(true) +} + +func (g *OracleContractsTestSuite) newPrefundAccount() (*ecdsa.PrivateKey, common.Address) { + privKey, err := crypto.GenerateKey() + if err != nil { + panic(err) + } + address := crypto.PubkeyToAddress(privKey.PublicKey) + + g.stateDB.AddBalance(address, new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2e6))) + return privKey, address +} + +func (g *OracleContractsTestSuite) call( + contractAddr common.Address, caller common.Address, input []byte, value *big.Int) ([]byte, error) { + + context := Context{ + CanTransfer: func(db StateDB, addr common.Address, amount *big.Int) bool { + return db.GetBalance(addr).Cmp(amount) >= 0 + }, + Transfer: func(db StateDB, sender common.Address, recipient common.Address, amount *big.Int) { + db.SubBalance(sender, amount) + db.AddBalance(recipient, amount) + }, + GetRoundHeight: func(round uint64) (uint64, bool) { + switch round { + case 0: + return 0, true + case 1: + return 1000, true + case 2: + return 2000, true + } + return 0, false + }, + StateAtNumber: func(n uint64) (*state.StateDB, error) { + return g.stateDB, nil + }, + Time: big.NewInt(time.Now().UnixNano() / 1000000), + BlockNumber: big.NewInt(0), + } + + evm := NewEVM(context, g.stateDB, params.TestChainConfig, Config{IsBlockProposer: true}) + ret, _, err := evm.Call(AccountRef(caller), contractAddr, input, 10000000, value) + return ret, err +} + +func (g *OracleContractsTestSuite) TestTransferOwnership() { + _, addr := g.newPrefundAccount() + + input, err := GovernanceABI.ABI.Pack("transferOwnership", addr) + g.Require().NoError(err) + + // Call with non-owner. + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NotNil(err) + + // Call with owner. + _, err = g.call(GovernanceContractAddress, g.config.Owner, input, big.NewInt(0)) + g.Require().NoError(err) + g.Require().Equal(addr, g.s.Owner()) +} + +func (g *OracleContractsTestSuite) TestStakeUnstakeWithoutExtraDelegators() { + privKey, addr := g.newPrefundAccount() + pk := crypto.FromECDSAPub(&privKey.PublicKey) + + // Stake. + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)) + balanceBeforeStake := g.stateDB.GetBalance(addr) + input, err := GovernanceABI.ABI.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, amount) + g.Require().NoError(err) + + g.Require().Equal(1, int(g.s.LenNodes().Uint64())) + g.Require().Equal(1, len(g.s.QualifiedNodes())) + g.Require().Equal("Test1", g.s.Node(big.NewInt(0)).Name) + g.Require().Equal(amount.String(), g.s.TotalStaked().String()) + + // Check balance. + g.Require().Equal(new(big.Int).Sub(balanceBeforeStake, amount), g.stateDB.GetBalance(addr)) + g.Require().Equal(new(big.Int).Add(big.NewInt(1), amount), g.stateDB.GetBalance(GovernanceContractAddress)) + + // Staking again should fail. + _, err = g.call(GovernanceContractAddress, addr, input, amount) + g.Require().NotNil(err) + + // Unstake. + input, err = GovernanceABI.ABI.Pack("unstake") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + g.Require().Equal(0, len(g.s.QualifiedNodes())) + g.Require().Equal(1, int(g.s.LenDelegators(addr).Uint64())) + g.Require().Equal(1, int(g.s.LenNodes().Uint64())) + + node := g.s.Node(big.NewInt(0)) + g.Require().Equal(big.NewInt(0).String(), node.Staked.String()) + g.Require().Equal(big.NewInt(0).String(), g.s.TotalStaked().String()) + + // Wait for lockup time than withdraw. + time.Sleep(time.Second * 2) + input, err = GovernanceABI.ABI.Pack("withdraw", addr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + g.Require().Equal(0, len(g.s.QualifiedNodes())) + g.Require().Equal(0, int(g.s.LenDelegators(addr).Uint64())) + g.Require().Equal(0, int(g.s.LenNodes().Uint64())) + + // Stake 2 nodes, and unstake the first then the second. + + // 2nd node Stake. + privKey2, addr2 := g.newPrefundAccount() + pk2 := crypto.FromECDSAPub(&privKey2.PublicKey) + input, err = GovernanceABI.ABI.Pack("stake", pk2, "Test2", "test2@dexon.org", "Taipei, Taiwan", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr2, input, amount) + g.Require().NoError(err) + g.Require().Equal("Test2", g.s.Node(big.NewInt(0)).Name) + g.Require().Equal(0, int(g.s.NodesOffsetByAddress(addr2).Int64())) + + // 1st node Stake. + input, err = GovernanceABI.ABI.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, amount) + g.Require().NoError(err) + + g.Require().Equal(2, len(g.s.QualifiedNodes())) + g.Require().Equal(new(big.Int).Mul(amount, big.NewInt(2)).String(), g.s.TotalStaked().String()) + + // 2nd node Unstake. + input, err = GovernanceABI.ABI.Pack("unstake") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr2, input, big.NewInt(0)) + g.Require().NoError(err) + node = g.s.Node(big.NewInt(0)) + g.Require().Equal("Test2", node.Name) + g.Require().Equal(big.NewInt(0).String(), node.Staked.String()) + g.Require().Equal(1, len(g.s.QualifiedNodes())) + g.Require().Equal(amount.String(), g.s.TotalStaked().String()) + + time.Sleep(time.Second * 2) + input, err = GovernanceABI.ABI.Pack("withdraw", addr2) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr2, input, big.NewInt(0)) + g.Require().NoError(err) + g.Require().Equal(1, len(g.s.QualifiedNodes())) + + g.Require().Equal(1, int(g.s.LenNodes().Uint64())) + g.Require().Equal("Test1", g.s.Node(big.NewInt(0)).Name) + g.Require().Equal(-1, int(g.s.NodesOffsetByAddress(addr2).Int64())) + + // 1st node Unstake. + input, err = GovernanceABI.ABI.Pack("unstake") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + g.Require().Equal(0, len(g.s.QualifiedNodes())) + g.Require().Equal(big.NewInt(0).String(), g.s.TotalStaked().String()) + + time.Sleep(time.Second * 2) + input, err = GovernanceABI.ABI.Pack("withdraw", addr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + g.Require().Equal(0, int(g.s.LenNodes().Uint64())) + g.Require().Equal(-1, int(g.s.NodesOffsetByAddress(addr).Int64())) + g.Require().Equal(-1, int(g.s.DelegatorsOffset(addr, addr).Int64())) + + // Check balance. + g.Require().Equal(balanceBeforeStake, g.stateDB.GetBalance(addr)) + g.Require().Equal(balanceBeforeStake, g.stateDB.GetBalance(addr2)) + g.Require().Equal(big.NewInt(1), g.stateDB.GetBalance(GovernanceContractAddress)) +} + +func (g *OracleContractsTestSuite) TestDelegateUndelegate() { + privKey, addr := g.newPrefundAccount() + pk := crypto.FromECDSAPub(&privKey.PublicKey) + + // Stake. + input, err := GovernanceABI.ABI.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + g.Require().NoError(err) + ownerStaked := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) + _, err = g.call(GovernanceContractAddress, addr, input, ownerStaked) + g.Require().NoError(err) + g.Require().Equal(0, len(g.s.QualifiedNodes())) + g.Require().Equal(addr, g.s.Delegator(addr, big.NewInt(0)).Owner) + g.Require().Equal(ownerStaked, g.s.Node(big.NewInt(0)).Staked) + + // 1st delegator delegate to 1st node. + _, addrDelegator := g.newPrefundAccount() + + balanceBeforeDelegate := g.stateDB.GetBalance(addrDelegator) + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3e5)) + input, err = GovernanceABI.ABI.Pack("delegate", addr) + g.Require().NoError(err) + + _, err = g.call(GovernanceContractAddress, addrDelegator, input, amount) + g.Require().NoError(err) + g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator)) + g.Require().Equal(addrDelegator, g.s.Delegator(addr, big.NewInt(1)).Owner) + g.Require().Equal(new(big.Int).Add(amount, ownerStaked), g.s.Node(big.NewInt(0)).Staked) + g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String()) + g.Require().Equal(1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64())) + + // Same person delegate the 2nd time should fail. + _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(1e18)) + g.Require().NotNil(err) + + // Not yet qualified. + g.Require().Equal(0, len(g.s.QualifiedNodes())) + + // 2nd delegator delegate to 1st node. + _, addrDelegator2 := g.newPrefundAccount() + _, err = g.call(GovernanceContractAddress, addrDelegator2, input, amount) + g.Require().NoError(err) + g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator2)) + g.Require().Equal(addrDelegator2, g.s.Delegator(addr, big.NewInt(2)).Owner) + g.Require().Equal(new(big.Int).Add(ownerStaked, new(big.Int).Mul(amount, big.NewInt(2))), + g.s.Node(big.NewInt(0)).Staked) + g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String()) + g.Require().Equal(2, int(g.s.DelegatorsOffset(addr, addrDelegator2).Int64())) + + // Qualified. + g.Require().Equal(1, len(g.s.QualifiedNodes())) + + // Undelegate addrDelegator. + balanceBeforeUnDelegate := g.stateDB.GetBalance(addrDelegator) + input, err = GovernanceABI.ABI.Pack("undelegate", addr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) + g.Require().Equal(new(big.Int).Add(amount, ownerStaked), g.s.Node(big.NewInt(0)).Staked) + g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String()) + g.Require().NoError(err) + + // Undelegate the second time should fail. + _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) + g.Require().Error(err) + + // Withdraw within lockup time should fail. + input, err = GovernanceABI.ABI.Pack("withdraw", addr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) + g.Require().NotNil(err) + + g.Require().Equal(3, int(g.s.LenDelegators(addr).Uint64())) + g.Require().Equal(balanceBeforeUnDelegate, g.stateDB.GetBalance(addrDelegator)) + g.Require().NotEqual(-1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64())) + + // Wait for lockup time than withdraw. + time.Sleep(time.Second * 2) + input, err = GovernanceABI.ABI.Pack("withdraw", addr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) + g.Require().NoError(err) + + g.Require().Equal(2, int(g.s.LenDelegators(addr).Uint64())) + g.Require().Equal(new(big.Int).Add(balanceBeforeUnDelegate, amount), g.stateDB.GetBalance(addrDelegator)) + g.Require().Equal(-1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64())) + + // Withdraw when their is no delegation should fail. + time.Sleep(time.Second) + input, err = GovernanceABI.ABI.Pack("withdraw", addr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) + g.Require().Error(err) + + // Undelegate addrDelegator2. + balanceBeforeUnDelegate = g.stateDB.GetBalance(addrDelegator2) + input, err = GovernanceABI.ABI.Pack("undelegate", addr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addrDelegator2, input, big.NewInt(0)) + g.Require().NoError(err) + + g.Require().Equal(ownerStaked, g.s.Node(big.NewInt(0)).Staked) + g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String()) + + // Wait for lockup time than withdraw. + time.Sleep(time.Second * 2) + input, err = GovernanceABI.ABI.Pack("withdraw", addr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addrDelegator2, input, big.NewInt(0)) + g.Require().NoError(err) + + g.Require().Equal(1, int(g.s.LenDelegators(addr).Uint64())) + g.Require().Equal(new(big.Int).Add(balanceBeforeUnDelegate, amount), g.stateDB.GetBalance(addrDelegator2)) + g.Require().Equal(-1, int(g.s.DelegatorsOffset(addr, addrDelegator2).Int64())) + + // Unqualified + g.Require().Equal(0, len(g.s.QualifiedNodes())) + + // Owner undelegate itself. + g.Require().Equal(1, int(g.s.LenNodes().Uint64())) + g.Require().Equal(1, int(g.s.LenDelegators(addr).Uint64())) + + input, err = GovernanceABI.ABI.Pack("undelegate", addr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + g.Require().Equal(big.NewInt(0).String(), g.s.Node(big.NewInt(0)).Staked.String()) + g.Require().Equal(big.NewInt(0).String(), g.s.TotalStaked().String()) + + time.Sleep(time.Second * 2) + input, err = GovernanceABI.ABI.Pack("withdraw", addr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + + g.Require().Equal(0, int(g.s.LenNodes().Uint64())) + g.Require().Equal(0, int(g.s.LenDelegators(addr).Uint64())) +} + +func (g *OracleContractsTestSuite) TestFine() { + privKey, addr := g.newPrefundAccount() + pk := crypto.FromECDSAPub(&privKey.PublicKey) + + // Stake. + input, err := GovernanceABI.ABI.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + g.Require().NoError(err) + ownerStaked := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) + _, err = g.call(GovernanceContractAddress, addr, input, ownerStaked) + g.Require().NoError(err) + g.Require().Equal(0, len(g.s.QualifiedNodes())) + g.Require().Equal(addr, g.s.Delegator(addr, big.NewInt(0)).Owner) + g.Require().Equal(ownerStaked, g.s.Node(big.NewInt(0)).Staked) + + // 1st delegator delegate to 1st node. + _, addrDelegator := g.newPrefundAccount() + + balanceBeforeDelegate := g.stateDB.GetBalance(addrDelegator) + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) + input, err = GovernanceABI.ABI.Pack("delegate", addr) + g.Require().NoError(err) + + _, err = g.call(GovernanceContractAddress, addrDelegator, input, amount) + g.Require().NoError(err) + g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator)) + g.Require().Equal(addrDelegator, g.s.Delegator(addr, big.NewInt(1)).Owner) + g.Require().Equal(new(big.Int).Add(amount, ownerStaked), g.s.Node(big.NewInt(0)).Staked) + g.Require().Equal(1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64())) + + // Qualified. + g.Require().Equal(1, len(g.s.QualifiedNodes())) + + // Paying to node without fine should fail. + input, err = GovernanceABI.ABI.Pack("payFine", addr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addrDelegator, input, amount) + g.Require().NotNil(err) + + // Fined. + offset := g.s.NodesOffsetByAddress(addr) + g.Require().True(offset.Cmp(big.NewInt(0)) >= 0) + node := g.s.Node(offset) + node.Fined = new(big.Int).Set(amount) + g.s.UpdateNode(offset, node) + node = g.s.Node(offset) + g.Require().Equal(0, node.Fined.Cmp(amount)) + + // Not qualified after fined. + g.Require().Equal(0, len(g.s.QualifiedNodes())) + + // Cannot undelegate before fines are paied. + input, err = GovernanceABI.ABI.Pack("undelegate", addr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) + g.Require().NotNil(err) + + // Only delegators can pay fine. + _, addrDelegator2 := g.newPrefundAccount() + input, err = GovernanceABI.ABI.Pack("payFine", addr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addrDelegator2, input, big.NewInt(5e5)) + g.Require().NotNil(err) + + // Paying more than fine should fail. + payAmount := new(big.Int).Add(amount, amount) + input, err = GovernanceABI.ABI.Pack("payFine", addr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addrDelegator, input, payAmount) + g.Require().NotNil(err) + + // Pay the fine. + input, err = GovernanceABI.ABI.Pack("payFine", addr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addrDelegator, input, amount) + g.Require().NoError(err) + + // Qualified. + g.Require().Equal(1, len(g.s.QualifiedNodes())) + + // Can undelegate after all fines are paied. + input, err = GovernanceABI.ABI.Pack("undelegate", addr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) + g.Require().NoError(err) +} + +func (g *OracleContractsTestSuite) TestUnstakeWithExtraDelegators() { + privKey, addr := g.newPrefundAccount() + pk := crypto.FromECDSAPub(&privKey.PublicKey) + + // Stake. + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) + input, err := GovernanceABI.ABI.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, amount) + g.Require().NoError(err) + + // 1st delegator delegate to 1st node. + _, addrDelegator := g.newPrefundAccount() + + balanceBeforeDelegate := g.stateDB.GetBalance(addrDelegator) + amount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3e5)) + input, err = GovernanceABI.ABI.Pack("delegate", addr) + g.Require().NoError(err) + + _, err = g.call(GovernanceContractAddress, addrDelegator, input, amount) + g.Require().NoError(err) + g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator)) + g.Require().Equal(addrDelegator, g.s.Delegator(addr, big.NewInt(1)).Owner) + g.Require().Equal(0, len(g.s.QualifiedNodes())) + + // 2st delegator delegate to 1st node. + _, addrDelegator2 := g.newPrefundAccount() + + balanceBeforeDelegate = g.stateDB.GetBalance(addrDelegator2) + input, err = GovernanceABI.ABI.Pack("delegate", addr) + g.Require().NoError(err) + + _, err = g.call(GovernanceContractAddress, addrDelegator2, input, amount) + g.Require().NoError(err) + g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator2)) + g.Require().Equal(addrDelegator2, g.s.Delegator(addr, big.NewInt(2)).Owner) + + // Node is now qualified. + g.Require().Equal(1, len(g.s.QualifiedNodes())) + + // Unstake. + input, err = GovernanceABI.ABI.Pack("unstake") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + time.Sleep(time.Second * 2) + input, err = GovernanceABI.ABI.Pack("withdraw", addr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addrDelegator2, input, big.NewInt(0)) + g.Require().NoError(err) + + g.Require().Equal(0, int(g.s.LenDelegators(addr).Uint64())) + g.Require().Equal(0, int(g.s.LenNodes().Uint64())) + + // Check balance. + g.Require().Equal(balanceBeforeDelegate, g.stateDB.GetBalance(addr)) + g.Require().Equal(balanceBeforeDelegate, g.stateDB.GetBalance(addrDelegator)) + g.Require().Equal(balanceBeforeDelegate, g.stateDB.GetBalance(addrDelegator2)) + g.Require().Equal(big.NewInt(1), g.stateDB.GetBalance(GovernanceContractAddress)) +} + +func (g *OracleContractsTestSuite) TestUpdateConfiguration() { + _, addr := g.newPrefundAccount() + + input, err := GovernanceABI.ABI.Pack("updateConfiguration", + new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)), + big.NewInt(1000), + big.NewInt(8000000), + big.NewInt(6), + big.NewInt(250), + big.NewInt(2500), + big.NewInt(0), + big.NewInt(667000), + big.NewInt(4), + big.NewInt(4), + big.NewInt(600000), + big.NewInt(900), + []*big.Int{big.NewInt(1), big.NewInt(1), big.NewInt(1)}) + g.Require().NoError(err) + + // Call with non-owner. + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NotNil(err) + + // Call with owner. + _, err = g.call(GovernanceContractAddress, g.config.Owner, input, big.NewInt(0)) + g.Require().NoError(err) +} + +func (g *OracleContractsTestSuite) TestConfigurationReading() { + _, addr := g.newPrefundAccount() + + // CRS. + input, err := GovernanceABI.ABI.Pack("crs", big.NewInt(0)) + g.Require().NoError(err) + res, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + var crs0 [32]byte + err = GovernanceABI.ABI.Unpack(&crs0, "crs", res) + g.Require().NoError(err) + g.Require().Equal(crypto.Keccak256Hash([]byte(g.config.GenesisCRSText)), common.BytesToHash(crs0[:])) + + // Owner. + input, err = GovernanceABI.ABI.Pack("owner") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + var owner common.Address + err = GovernanceABI.ABI.Unpack(&owner, "owner", res) + g.Require().NoError(err) + g.Require().Equal(g.config.Owner, owner) + + // MinStake. + input, err = GovernanceABI.ABI.Pack("minStake") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + var value *big.Int + err = GovernanceABI.ABI.Unpack(&value, "minStake", res) + g.Require().NoError(err) + g.Require().Equal(g.config.MinStake.String(), value.String()) + + // BlockReward. + input, err = GovernanceABI.ABI.Pack("miningVelocity") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "miningVelocity", res) + g.Require().NoError(err) + g.Require().Equal(g.config.MiningVelocity, float32(value.Uint64())/decimalMultiplier) + + // BlockGasLimit. + input, err = GovernanceABI.ABI.Pack("blockGasLimit") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "blockGasLimit", res) + g.Require().NoError(err) + g.Require().Equal(g.config.BlockGasLimit, value.Uint64()) + + // NumChains. + input, err = GovernanceABI.ABI.Pack("numChains") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "numChains", res) + g.Require().NoError(err) + g.Require().Equal(g.config.NumChains, uint32(value.Uint64())) + + // LambdaBA. + input, err = GovernanceABI.ABI.Pack("lambdaBA") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "lambdaBA", res) + g.Require().NoError(err) + g.Require().Equal(g.config.LambdaBA, value.Uint64()) + + // LambdaDKG. + input, err = GovernanceABI.ABI.Pack("lambdaDKG") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "lambdaDKG", res) + g.Require().NoError(err) + g.Require().Equal(g.config.LambdaDKG, value.Uint64()) + + // K. + input, err = GovernanceABI.ABI.Pack("k") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "k", res) + g.Require().NoError(err) + g.Require().Equal(g.config.K, uint32(value.Uint64())) + + // PhiRatio. + input, err = GovernanceABI.ABI.Pack("phiRatio") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "phiRatio", res) + g.Require().NoError(err) + g.Require().Equal(g.config.PhiRatio, float32(value.Uint64())/decimalMultiplier) + + // NotarySetSize. + input, err = GovernanceABI.ABI.Pack("notarySetSize") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "notarySetSize", res) + g.Require().NoError(err) + g.Require().Equal(g.config.NotarySetSize, uint32(value.Uint64())) + + // DKGSetSize. + input, err = GovernanceABI.ABI.Pack("dkgSetSize") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "dkgSetSize", res) + g.Require().NoError(err) + g.Require().Equal(g.config.DKGSetSize, uint32(value.Uint64())) + + // RoundInterval. + input, err = GovernanceABI.ABI.Pack("roundInterval") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "roundInterval", res) + g.Require().NoError(err) + g.Require().Equal(g.config.RoundInterval, value.Uint64()) + + // MinBlockInterval. + input, err = GovernanceABI.ABI.Pack("minBlockInterval") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "minBlockInterval", res) + g.Require().NoError(err) + g.Require().Equal(g.config.MinBlockInterval, value.Uint64()) +} + +func (g *OracleContractsTestSuite) TestReportForkVote() { + key, addr := g.newPrefundAccount() + pkBytes := crypto.FromECDSAPub(&key.PublicKey) + + // Stake. + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) + input, err := GovernanceABI.ABI.Pack("stake", pkBytes, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, amount) + g.Require().NoError(err) + + pubKey := coreEcdsa.NewPublicKeyFromECDSA(&key.PublicKey) + privKey := coreEcdsa.NewPrivateKeyFromECDSA(key) + vote1 := coreTypes.NewVote(coreTypes.VoteCom, coreCommon.NewRandomHash(), uint64(0)) + vote1.ProposerID = coreTypes.NewNodeID(pubKey) + + vote2 := vote1.Clone() + for vote2.BlockHash == vote1.BlockHash { + vote2.BlockHash = coreCommon.NewRandomHash() + } + vote1.Signature, err = privKey.Sign(coreUtils.HashVote(vote1)) + g.Require().NoError(err) + vote2.Signature, err = privKey.Sign(coreUtils.HashVote(vote2)) + g.Require().NoError(err) + + vote1Bytes, err := rlp.EncodeToBytes(vote1) + g.Require().NoError(err) + vote2Bytes, err := rlp.EncodeToBytes(vote2) + g.Require().NoError(err) + + // Report wrong type (fork block) + input, err = GovernanceABI.ABI.Pack("report", big.NewInt(2), vote1Bytes, vote2Bytes) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().Error(err) + + input, err = GovernanceABI.ABI.Pack("report", big.NewInt(1), vote1Bytes, vote2Bytes) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + node := g.s.Node(big.NewInt(0)) + g.Require().Equal(node.Fined, g.s.FineValue(big.NewInt(1))) + + // Duplicate report should fail. + input, err = GovernanceABI.ABI.Pack("report", big.NewInt(1), vote1Bytes, vote2Bytes) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().Error(err) + + // Check if finedRecords is set. + payloads := [][]byte{vote1Bytes, vote2Bytes} + sort.Sort(sortBytes(payloads)) + + hash := Bytes32(crypto.Keccak256Hash(payloads...)) + input, err = GovernanceABI.ABI.Pack("finedRecords", hash) + g.Require().NoError(err) + res, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + var value bool + err = GovernanceABI.ABI.Unpack(&value, "finedRecords", res) + g.Require().NoError(err) + g.Require().True(value) +} + +func (g *OracleContractsTestSuite) TestReportForkBlock() { + key, addr := g.newPrefundAccount() + pkBytes := crypto.FromECDSAPub(&key.PublicKey) + + // Stake. + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) + input, err := GovernanceABI.ABI.Pack("stake", pkBytes, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, amount) + g.Require().NoError(err) + + privKey := coreEcdsa.NewPrivateKeyFromECDSA(key) + block1 := &coreTypes.Block{ + ProposerID: coreTypes.NewNodeID(privKey.PublicKey()), + ParentHash: coreCommon.NewRandomHash(), + Timestamp: time.Now(), + } + + block2 := block1.Clone() + for block2.ParentHash == block1.ParentHash { + block2.ParentHash = coreCommon.NewRandomHash() + } + + hashBlock := func(block *coreTypes.Block) coreCommon.Hash { + block.PayloadHash = coreCrypto.Keccak256Hash(block.Payload) + var err error + block.Hash, err = coreUtils.HashBlock(block) + g.Require().NoError(err) + return block.Hash + } + + block1.Signature, err = privKey.Sign(hashBlock(block1)) + g.Require().NoError(err) + block2.Signature, err = privKey.Sign(hashBlock(block2)) + g.Require().NoError(err) + + block1Bytes, err := rlp.EncodeToBytes(block1) + g.Require().NoError(err) + block2Bytes, err := rlp.EncodeToBytes(block2) + g.Require().NoError(err) + + // Report wrong type (fork vote) + input, err = GovernanceABI.ABI.Pack("report", big.NewInt(1), block1Bytes, block2Bytes) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().Error(err) + + input, err = GovernanceABI.ABI.Pack("report", big.NewInt(2), block1Bytes, block2Bytes) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + node := g.s.Node(big.NewInt(0)) + g.Require().Equal(node.Fined, g.s.FineValue(big.NewInt(2))) + + // Duplicate report should fail. + input, err = GovernanceABI.ABI.Pack("report", big.NewInt(2), block1Bytes, block2Bytes) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().Error(err) + + // Check if finedRecords is set. + payloads := [][]byte{block1Bytes, block2Bytes} + sort.Sort(sortBytes(payloads)) + + hash := Bytes32(crypto.Keccak256Hash(payloads...)) + input, err = GovernanceABI.ABI.Pack("finedRecords", hash) + g.Require().NoError(err) + res, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + var value bool + err = GovernanceABI.ABI.Unpack(&value, "finedRecords", res) + g.Require().NoError(err) + g.Require().True(value) +} + +func (g *OracleContractsTestSuite) TestMiscVariableReading() { + privKey, addr := g.newPrefundAccount() + pk := crypto.FromECDSAPub(&privKey.PublicKey) + + input, err := GovernanceABI.ABI.Pack("totalSupply") + g.Require().NoError(err) + res, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + input, err = GovernanceABI.ABI.Pack("totalStaked") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + // Stake. + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) + input, err = GovernanceABI.ABI.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, amount) + g.Require().NoError(err) + + // 1st delegator delegate to 1st node. + _, addrDelegator := g.newPrefundAccount() + amount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3e5)) + input, err = GovernanceABI.ABI.Pack("delegate", addr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addrDelegator, input, amount) + g.Require().NoError(err) + + // 2st delegator delegate to 1st node. + _, addrDelegator2 := g.newPrefundAccount() + input, err = GovernanceABI.ABI.Pack("delegate", addr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addrDelegator2, input, amount) + g.Require().NoError(err) + + input, err = GovernanceABI.ABI.Pack("nodes", big.NewInt(0)) + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + input, err = GovernanceABI.ABI.Pack("nodesLength") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + var value *big.Int + err = GovernanceABI.ABI.Unpack(&value, "nodesLength", res) + g.Require().NoError(err) + g.Require().Equal(1, int(value.Uint64())) + + input, err = GovernanceABI.ABI.Pack("nodesOffsetByAddress", addr) + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "nodesOffsetByAddress", res) + g.Require().NoError(err) + g.Require().Equal(0, int(value.Uint64())) + + id, err := publicKeyToNodeID(pk) + g.Require().NoError(err) + input, err = GovernanceABI.ABI.Pack("nodesOffsetByID", id) + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "nodesOffsetByID", res) + g.Require().NoError(err) + g.Require().Equal(0, int(value.Uint64())) + + input, err = GovernanceABI.ABI.Pack("delegators", addr, big.NewInt(0)) + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + input, err = GovernanceABI.ABI.Pack("delegatorsLength", addr) + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "delegatorsLength", res) + g.Require().NoError(err) + g.Require().Equal(3, int(value.Uint64())) + + input, err = GovernanceABI.ABI.Pack("delegatorsOffset", addr, addrDelegator2) + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "delegatorsOffset", res) + g.Require().NoError(err) + g.Require().Equal(2, int(value.Uint64())) + + input, err = GovernanceABI.ABI.Pack("fineValues", big.NewInt(0)) + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) +} + +func (g *OracleContractsTestSuite) TestHalvingCondition() { + // TotalSupply 2.5B reached + g.s.MiningHalved() + g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3.25e9)).String(), + g.s.NextHalvingSupply().String()) + g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(0.75e9)).String(), + g.s.LastHalvedAmount().String()) + + // TotalSupply 3.25B reached + g.s.MiningHalved() + g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3.625e9)).String(), + g.s.NextHalvingSupply().String()) + g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(0.375e9)).String(), + g.s.LastHalvedAmount().String()) +} + +func (g *OracleContractsTestSuite) TestNodeInfoOracleContract() { + privKey, addr := g.newPrefundAccount() + pk := crypto.FromECDSAPub(&privKey.PublicKey) + + // Stake. + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) + input, err := GovernanceABI.ABI.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, amount) + g.Require().NoError(err) + + // Invalid round. + input, err = NodeInfoOracleABI.ABI.Pack("delegators", big.NewInt(100), addr, big.NewInt(0)) + g.Require().NoError(err) + res, err := g.call(NodeInfoOracleAddress, addr, input, big.NewInt(0)) + g.Require().Error(err) + + round := big.NewInt(0) + input, err = NodeInfoOracleABI.ABI.Pack("delegators", round, addr, big.NewInt(0)) + g.Require().NoError(err) + res, err = g.call(NodeInfoOracleAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + var value *big.Int + input, err = NodeInfoOracleABI.ABI.Pack("delegatorsLength", round, addr) + g.Require().NoError(err) + res, err = g.call(NodeInfoOracleAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = NodeInfoOracleABI.ABI.Unpack(&value, "delegatorsLength", res) + g.Require().NoError(err) + g.Require().Equal(1, int(value.Uint64())) + + input, err = NodeInfoOracleABI.ABI.Pack("delegatorsOffset", round, addr, addr) + g.Require().NoError(err) + res, err = g.call(NodeInfoOracleAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = NodeInfoOracleABI.ABI.Unpack(&value, "delegatorsOffset", res) + g.Require().NoError(err) + g.Require().Equal(0, int(value.Uint64())) +} + +func TestGovernanceContract(t *testing.T) { + suite.Run(t, new(OracleContractsTestSuite)) +} diff --git a/test/genesis.json b/test/genesis.json index 7ab90e48b..0785f36c7 100644 --- a/test/genesis.json +++ b/test/genesis.json @@ -1,7 +1,7 @@ { "config": { "chainId": 237, - "dMoment": 1547480026, + "dMoment": 0, "homesteadBlock": 0, "daoForkBlock": 0, "daoForkSupport": true, -- cgit v1.2.3