diff options
Diffstat (limited to 'core/vm/evm')
-rw-r--r-- | core/vm/evm/oracle.go | 91 | ||||
-rw-r--r-- | core/vm/evm/oracle_contract_abi.go (renamed from core/vm/evm/governance_abi.go) | 180 | ||||
-rw-r--r-- | core/vm/evm/oracle_contracts.go (renamed from core/vm/evm/governance.go) | 1473 | ||||
-rw-r--r-- | core/vm/evm/oracle_contracts_test.go (renamed from core/vm/evm/governance_test.go) | 688 |
4 files changed, 1622 insertions, 810 deletions
diff --git a/core/vm/evm/oracle.go b/core/vm/evm/oracle.go new file mode 100644 index 000000000..4ee20232d --- /dev/null +++ b/core/vm/evm/oracle.go @@ -0,0 +1,91 @@ +// Copyright 2019 The dexon-consensus Authors +// This file is part of the dexon-consensus library. +// +// The dexon-consensus library is free software: you can redistribute it +// and/or modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation, either version 3 of the License, +// or (at your option) any later version. +// +// The dexon-consensus library is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +// General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the dexon-consensus library. If not, see +// <http://www.gnu.org/licenses/>. + +package evm + +import ( + "strings" + + "github.com/dexon-foundation/dexon/accounts/abi" + "github.com/dexon-foundation/dexon/common" + "github.com/dexon-foundation/dexon/core/vm" +) + +var GovernanceContractAddress = common.HexToAddress("63751838d6485578b23e8b051d40861ecc416794") +var 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 *vm.Contract) (ret []byte, err error) +} + +// A map representing available system oracle contracts. +var OracleContracts = map[common.Address]OracleContract{ + GovernanceContractAddress: &GovernanceContract{ + coreDKGUtils: &defaultCoreDKGUtils{}, + }, + NodeInfoOracleAddress: &NodeInfoOracleContract{}, +} + +// Run oracle contract. +func RunOracleContract(oracle OracleContract, evm *EVM, input []byte, contract *vm.Contract) (ret []byte, err error) { + return oracle.Run(evm, input, contract) +} + +// OracleContractABI represents ABI information for a given contract. +type OracleContractABI struct { + ABI abi.ABI + Name2Method map[string]abi.Method + Sig2Method map[string]abi.Method + Events map[string]abi.Event +} + +// NewOracleContractABI parse the ABI. +func NewOracleContractABI(abiDefinition string) *OracleContractABI { + abiObject, err := abi.JSON(strings.NewReader(abiDefinition)) + if err != nil { + panic(err) + } + + sig2Method := make(map[string]abi.Method) + name2Method := make(map[string]abi.Method) + + for _, method := range abiObject.Methods { + sig2Method[string(method.Id())] = method + name2Method[method.Name] = method + } + + events := make(map[string]abi.Event) + for _, event := range abiObject.Events { + events[event.Name] = event + } + + return &OracleContractABI{ + ABI: abiObject, + Name2Method: name2Method, + Sig2Method: sig2Method, + Events: events, + } +} diff --git a/core/vm/evm/governance_abi.go b/core/vm/evm/oracle_contract_abi.go index 966c4c4f3..4fb068f26 100644 --- a/core/vm/evm/governance_abi.go +++ b/core/vm/evm/oracle_contract_abi.go @@ -98,6 +98,25 @@ const GovernanceABIJSON = ` }, { "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "DKGResetCount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, "inputs": [], "name": "totalSupply", "outputs": [ @@ -673,6 +692,18 @@ const GovernanceABIJSON = ` "indexed": true, "name": "NodeAddress", "type": "address" + } + ], + "name": "NodeRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" }, { "indexed": true, @@ -700,6 +731,11 @@ const GovernanceABIJSON = ` "indexed": true, "name": "DelegatorAddress", "type": "address" + }, + { + "indexed": false, + "name": "Amount", + "type": "uint256" } ], "name": "Undelegated", @@ -714,6 +750,11 @@ const GovernanceABIJSON = ` "type": "address" }, { + "indexed": true, + "name": "DelegatorAddress", + "type": "address" + }, + { "indexed": false, "name": "Amount", "type": "uint256" @@ -784,6 +825,23 @@ const GovernanceABIJSON = ` "type": "event" }, { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "Round", + "type": "uint256" + }, + { + "indexed": false, + "name": "BlockHeight", + "type": "uint256" + } + ], + "name": "DKGReset", + "type": "event" + }, + { "constant": false, "inputs": [ { @@ -912,24 +970,6 @@ const GovernanceABIJSON = ` "type": "uint256" }, { - "name": "Height", - "type": "uint256" - } - ], - "name": "snapshotRound", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "Round", - "type": "uint256" - }, - { "name": "SignedCRS", "type": "bytes" } @@ -1128,6 +1168,110 @@ const GovernanceABIJSON = ` "payable": false, "stateMutability": "nonpayable", "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "NewSignedCRS", + "type": "bytes" + } + ], + "name": "resetDKG", + "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/evm/governance.go b/core/vm/evm/oracle_contracts.go index 18e733342..e00f65b29 100644 --- a/core/vm/evm/governance.go +++ b/core/vm/evm/oracle_contracts.go @@ -22,11 +22,11 @@ import ( "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/core/vm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/params" "github.com/dexon-foundation/dexon/rlp" @@ -35,20 +35,12 @@ import ( "github.com/dexon-foundation/dexon-consensus/core" coreCrypto "github.com/dexon-foundation/dexon-consensus/core/crypto" coreUtils "github.com/dexon-foundation/dexon-consensus/core/utils" - "github.com/dexon-foundation/dexon/core/vm" "github.com/dexon-foundation/dexon-consensus/core/crypto/ecdsa" coreTypes "github.com/dexon-foundation/dexon-consensus/core/types" dkgTypes "github.com/dexon-foundation/dexon-consensus/core/types/dkg" ) -var GovernanceContractAddress = common.HexToAddress("63751838d6485578b23e8b051d40861ecc416794") - -var abiObject abi.ABI -var GovernanceContractName2Method map[string]abi.Method -var sig2Method map[string]abi.Method -var events map[string]abi.Event - type Bytes32 [32]byte type ReportType uint64 @@ -59,473 +51,6 @@ const ( ReportTypeForkBlock ) -func init() { - var err error - - // Parse governance contract ABI. - abiObject, err = abi.JSON(strings.NewReader(GovernanceABIJSON)) - if err != nil { - panic(err) - } - - sig2Method = make(map[string]abi.Method) - GovernanceContractName2Method = make(map[string]abi.Method) - - // Construct dispatch table. - for _, method := range abiObject.Methods { - sig2Method[string(method.Id())] = method - GovernanceContractName2Method[method.Name] = method - } - - events = make(map[string]abi.Event) - - // Event cache. - for _, event := range abiObject.Events { - events[event.Name] = event - } -} - -// RunGovernanceContract executes governance contract. -func RunGovernanceContract(evm *EVM, input []byte, contract *vm.Contract) (ret []byte, err error) { - if len(input) < 4 { - return nil, nil - } - - // Parse input. - method, exists := sig2Method[string(input[:4])] - if !exists { - return nil, errExecutionReverted - } - - // Dispatch method call. - g := newGovernanceContract(evm, contract) - arguments := input[4:] - - switch method.Name { - case "addDKGComplaint": - args := struct { - Round *big.Int - Complaint []byte - }{} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - return g.addDKGComplaint(args.Round, args.Complaint) - case "addDKGMasterPublicKey": - args := struct { - Round *big.Int - PublicKey []byte - }{} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - return g.addDKGMasterPublicKey(args.Round, args.PublicKey) - case "addDKGMPKReady": - args := struct { - Round *big.Int - MPKReady []byte - }{} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - return g.addDKGMPKReady(args.Round, args.MPKReady) - case "addDKGFinalize": - args := struct { - Round *big.Int - Finalize []byte - }{} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - return g.addDKGFinalize(args.Round, args.Finalize) - case "delegate": - address := common.Address{} - if err := method.Inputs.Unpack(&address, arguments); err != nil { - return nil, errExecutionReverted - } - return g.delegate(address) - case "delegatorsLength": - address := common.Address{} - if err := method.Inputs.Unpack(&address, arguments); err != nil { - return nil, errExecutionReverted - } - res, err := method.Outputs.Pack(g.state.LenDelegators(address)) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "nodesLength": - res, err := method.Outputs.Pack(g.state.LenNodes()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "payFine": - address := common.Address{} - if err := method.Inputs.Unpack(&address, arguments); err != nil { - return nil, errExecutionReverted - } - return g.payFine(address) - case "proposeCRS": - args := struct { - Round *big.Int - SignedCRS []byte - }{} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - return g.proposeCRS(args.Round, args.SignedCRS) - case "report": - args := struct { - Type *big.Int - Arg1 []byte - Arg2 []byte - }{} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - return g.report(args.Type, args.Arg1, args.Arg2) - case "stake": - args := struct { - PublicKey []byte - Name string - Email string - Location string - Url string - }{} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - return g.stake(args.PublicKey, args.Name, args.Email, args.Location, args.Url) - case "snapshotRound": - args := struct { - Round *big.Int - Height *big.Int - }{} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - return g.snapshotRound(args.Round, args.Height) - case "transferOwnership": - var newOwner common.Address - if err := method.Inputs.Unpack(&newOwner, arguments); err != nil { - return nil, errExecutionReverted - } - return g.transferOwnership(newOwner) - case "undelegate": - address := common.Address{} - if err := method.Inputs.Unpack(&address, arguments); err != nil { - return nil, errExecutionReverted - } - return g.undelegate(address) - case "unstake": - return g.unstake() - case "updateConfiguration": - var cfg rawConfigStruct - if err := method.Inputs.Unpack(&cfg, arguments); err != nil { - return nil, errExecutionReverted - } - return g.updateConfiguration(&cfg) - case "withdraw": - address := common.Address{} - if err := method.Inputs.Unpack(&address, arguments); err != nil { - return nil, errExecutionReverted - } - return g.withdraw(address) - - // -------------------------------- - // Solidity auto generated methods. - // -------------------------------- - - case "blockGasLimit": - res, err := method.Outputs.Pack(g.state.BlockGasLimit()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "crs": - round := new(big.Int) - if err := method.Inputs.Unpack(&round, arguments); err != nil { - return nil, errExecutionReverted - } - res, err := method.Outputs.Pack(g.state.CRS(round)) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "delegators": - nodeAddr, index := common.Address{}, new(big.Int) - args := []interface{}{&nodeAddr, &index} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - delegator := g.state.Delegator(nodeAddr, index) - res, err := method.Outputs.Pack(delegator.Owner, delegator.Value, delegator.UndelegatedAt) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "delegatorsOffset": - nodeAddr, delegatorAddr := common.Address{}, common.Address{} - args := []interface{}{&nodeAddr, &delegatorAddr} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - res, err := method.Outputs.Pack(g.state.DelegatorsOffset(nodeAddr, delegatorAddr)) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgComplaints": - round, index := new(big.Int), new(big.Int) - args := []interface{}{&round, &index} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - complaints := g.state.DKGComplaints(round) - if int(index.Uint64()) >= len(complaints) { - return nil, errExecutionReverted - } - complaint := complaints[index.Uint64()] - res, err := method.Outputs.Pack(complaint) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgReadys": - round, addr := new(big.Int), common.Address{} - args := []interface{}{&round, &addr} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - ready := g.state.DKGMPKReady(round, addr) - res, err := method.Outputs.Pack(ready) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgReadysCount": - round := new(big.Int) - if err := method.Inputs.Unpack(&round, arguments); err != nil { - return nil, errExecutionReverted - } - count := g.state.DKGMPKReadysCount(round) - res, err := method.Outputs.Pack(count) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - - case "dkgFinalizeds": - round, addr := new(big.Int), common.Address{} - args := []interface{}{&round, &addr} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - finalized := g.state.DKGFinalized(round, addr) - res, err := method.Outputs.Pack(finalized) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgFinalizedsCount": - round := new(big.Int) - if err := method.Inputs.Unpack(&round, arguments); err != nil { - return nil, errExecutionReverted - } - count := g.state.DKGFinalizedsCount(round) - res, err := method.Outputs.Pack(count) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgMasterPublicKeys": - round, index := new(big.Int), new(big.Int) - args := []interface{}{&round, &index} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - mpks := g.state.DKGMasterPublicKeys(round) - if int(index.Uint64()) >= len(mpks) { - return nil, errExecutionReverted - } - mpk := mpks[index.Uint64()] - res, err := method.Outputs.Pack(mpk) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgSetSize": - res, err := method.Outputs.Pack(g.state.DKGSetSize()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "finedRecords": - record := Bytes32{} - if err := method.Inputs.Unpack(&record, arguments); err != nil { - return nil, errExecutionReverted - } - value := g.state.FineRecords(record) - res, err := method.Outputs.Pack(value) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "fineValues": - index := new(big.Int) - if err := method.Inputs.Unpack(&index, arguments); err != nil { - return nil, errExecutionReverted - } - value := g.state.FineValue(index) - res, err := method.Outputs.Pack(value) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "k": - res, err := method.Outputs.Pack(g.state.K()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "lambdaBA": - res, err := method.Outputs.Pack(g.state.LambdaBA()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "lambdaDKG": - res, err := method.Outputs.Pack(g.state.LambdaDKG()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "lastHalvedAmount": - res, err := method.Outputs.Pack(g.state.LastHalvedAmount()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "lockupPeriod": - res, err := method.Outputs.Pack(g.state.LockupPeriod()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "minBlockInterval": - res, err := method.Outputs.Pack(g.state.MinBlockInterval()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "miningVelocity": - res, err := method.Outputs.Pack(g.state.MiningVelocity()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "minStake": - res, err := method.Outputs.Pack(g.state.MinStake()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "nextHalvingSupply": - res, err := method.Outputs.Pack(g.state.NextHalvingSupply()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "numChains": - res, err := method.Outputs.Pack(g.state.NumChains()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "nodes": - index := new(big.Int) - if err := method.Inputs.Unpack(&index, arguments); err != nil { - return nil, errExecutionReverted - } - info := g.state.Node(index) - res, err := method.Outputs.Pack( - info.Owner, info.PublicKey, info.Staked, info.Fined, - info.Name, info.Email, info.Location, info.Url) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "nodesOffsetByAddress": - address := common.Address{} - if err := method.Inputs.Unpack(&address, arguments); err != nil { - return nil, errExecutionReverted - } - res, err := method.Outputs.Pack(g.state.NodesOffsetByAddress(address)) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "nodesOffsetByID": - var id Bytes32 - if err := method.Inputs.Unpack(&id, arguments); err != nil { - return nil, errExecutionReverted - } - res, err := method.Outputs.Pack(g.state.NodesOffsetByID(id)) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "notarySetSize": - res, err := method.Outputs.Pack(g.state.NotarySetSize()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "owner": - res, err := method.Outputs.Pack(g.state.Owner()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "phiRatio": - res, err := method.Outputs.Pack(g.state.PhiRatio()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "roundHeight": - round := new(big.Int) - if err := method.Inputs.Unpack(&round, arguments); err != nil { - return nil, errExecutionReverted - } - res, err := method.Outputs.Pack(g.state.RoundHeight(round)) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "roundInterval": - res, err := method.Outputs.Pack(g.state.RoundInterval()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "totalStaked": - res, err := method.Outputs.Pack(g.state.TotalStaked()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "totalSupply": - res, err := method.Outputs.Pack(g.state.TotalSupply()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - } - return nil, errExecutionReverted -} - // Storage position enums. const ( roundHeightLoc = iota @@ -561,6 +86,7 @@ const ( minBlockIntervalLoc fineValuesLoc finedRecordsLoc + dkgResetCountLoc ) func publicKeyToNodeID(pkBytes []byte) (Bytes32, error) { @@ -681,6 +207,29 @@ func (s *GovernanceStateHelper) writeBytes(loc *big.Int, data []byte) { } } +func (s *GovernanceStateHelper) eraseBytes(loc *big.Int) { + // Length of the dynamic array (bytes). + rawLength := s.getStateBigInt(loc) + lengthByte := new(big.Int).Mod(rawLength, big.NewInt(256)) + + // Bytes length <= 31, lengthByte % 2 == 0 + // return the high 31 bytes. + if new(big.Int).Mod(lengthByte, big.NewInt(2)).Cmp(big.NewInt(0)) == 0 { + s.setStateBigInt(loc, big.NewInt(0)) + return + } + + // Actual length = (rawLength - 1) / 2 + length := new(big.Int).Div(new(big.Int).Sub( + rawLength, big.NewInt(1)), big.NewInt(2)).Uint64() + + // Fill 0. + s.writeBytes(loc, make([]byte, length)) + + // Clear slot. + s.setStateBigInt(loc, big.NewInt(0)) +} + func (s *GovernanceStateHelper) read2DByteArray(pos, index *big.Int) [][]byte { baseLoc := s.getSlotLoc(pos) loc := new(big.Int).Add(baseLoc, index) @@ -696,6 +245,7 @@ func (s *GovernanceStateHelper) read2DByteArray(pos, index *big.Int) [][]byte { return data } + func (s *GovernanceStateHelper) appendTo2DByteArray(pos, index *big.Int, data []byte) { // Find the loc of the last element. baseLoc := s.getSlotLoc(pos) @@ -711,10 +261,21 @@ func (s *GovernanceStateHelper) appendTo2DByteArray(pos, index *big.Int, data [] s.writeBytes(elementLoc, data) } -// uint256[] public roundHeight; -func (s *GovernanceStateHelper) LenRoundHeight() *big.Int { - return s.getStateBigInt(big.NewInt(roundHeightLoc)) +func (s *GovernanceStateHelper) erase2DByteArray(pos, index *big.Int) { + baseLoc := s.getSlotLoc(pos) + loc := new(big.Int).Add(baseLoc, index) + + arrayLength := s.getStateBigInt(loc) + dataLoc := s.getSlotLoc(loc) + + for i := int64(0); i < int64(arrayLength.Uint64()); i++ { + elementLoc := new(big.Int).Add(dataLoc, big.NewInt(i)) + s.eraseBytes(elementLoc) + } + s.setStateBigInt(loc, big.NewInt(0)) } + +// uint256[] public roundHeight; func (s *GovernanceStateHelper) RoundHeight(round *big.Int) *big.Int { baseLoc := s.getSlotLoc(big.NewInt(roundHeightLoc)) loc := new(big.Int).Add(baseLoc, round) @@ -1049,6 +610,16 @@ func (s *GovernanceStateHelper) PushCRS(crs common.Hash) { s.setState(common.BigToHash(loc), crs) } +func (s *GovernanceStateHelper) PopCRS() { + // decrease length by 1. + length := s.getStateBigInt(big.NewInt(crsLoc)) + s.setStateBigInt(big.NewInt(crsLoc), new(big.Int).Sub(length, big.NewInt(1))) + + baseLoc := s.getSlotLoc(big.NewInt(crsLoc)) + loc := new(big.Int).Add(baseLoc, length) + + s.setState(common.BigToHash(loc), common.Hash{}) +} func (s *GovernanceStateHelper) Round() *big.Int { return new(big.Int).Sub(s.getStateBigInt(big.NewInt(crsLoc)), big.NewInt(1)) } @@ -1093,6 +664,9 @@ func (s *GovernanceStateHelper) GetDKGMasterPublicKeyByProposerID( } return nil, errors.New("not found") } +func (s *GovernanceStateHelper) ClearDKGMasterPublicKeys(round *big.Int) { + s.erase2DByteArray(big.NewInt(dkgMasterPublicKeysLoc), round) +} // bytes[][] public dkgComplaints; func (s *GovernanceStateHelper) DKGComplaints(round *big.Int) [][]byte { @@ -1101,6 +675,9 @@ func (s *GovernanceStateHelper) DKGComplaints(round *big.Int) [][]byte { func (s *GovernanceStateHelper) PushDKGComplaint(round *big.Int, complaint []byte) { s.appendTo2DByteArray(big.NewInt(dkgComplaintsLoc), round, complaint) } +func (s *GovernanceStateHelper) ClearDKGComplaints(round *big.Int) { + s.erase2DByteArray(big.NewInt(dkgComplaintsLoc), round) +} // mapping(address => bool)[] public dkgReady; func (s *GovernanceStateHelper) DKGMPKReady(round *big.Int, addr common.Address) bool { @@ -1117,6 +694,16 @@ func (s *GovernanceStateHelper) PutDKGMPKReady(round *big.Int, addr common.Addre } s.setStateBigInt(mapLoc, res) } +func (s *GovernanceStateHelper) ClearDKGMPKReady(round *big.Int, dkgSet map[coreTypes.NodeID]struct{}) { + for id := range dkgSet { + offset := s.NodesOffsetByID(Bytes32(id.Hash)) + if offset.Cmp(big.NewInt(0)) < 0 { + panic(errors.New("DKG node does not exist")) + } + node := s.Node(offset) + s.PutDKGMPKReady(round, node.Owner, false) + } +} // uint256[] public dkgReadysCount; func (s *GovernanceStateHelper) DKGMPKReadysCount(round *big.Int) *big.Int { @@ -1128,6 +715,10 @@ func (s *GovernanceStateHelper) IncDKGMPKReadysCount(round *big.Int) { count := s.getStateBigInt(loc) s.setStateBigInt(loc, new(big.Int).Add(count, big.NewInt(1))) } +func (s *GovernanceStateHelper) ResetDKGMPKReadysCount(round *big.Int) { + loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgReadysCountLoc)), round) + s.setStateBigInt(loc, big.NewInt(0)) +} // mapping(address => bool)[] public dkgFinalized; func (s *GovernanceStateHelper) DKGFinalized(round *big.Int, addr common.Address) bool { @@ -1144,6 +735,16 @@ func (s *GovernanceStateHelper) PutDKGFinalized(round *big.Int, addr common.Addr } s.setStateBigInt(mapLoc, res) } +func (s *GovernanceStateHelper) ClearDKGFinalized(round *big.Int, dkgSet map[coreTypes.NodeID]struct{}) { + for id := range dkgSet { + offset := s.NodesOffsetByID(Bytes32(id.Hash)) + if offset.Cmp(big.NewInt(0)) < 0 { + panic(errors.New("DKG node does not exist")) + } + node := s.Node(offset) + s.PutDKGFinalized(round, node.Owner, false) + } +} // uint256[] public dkgFinalizedsCount; func (s *GovernanceStateHelper) DKGFinalizedsCount(round *big.Int) *big.Int { @@ -1155,6 +756,10 @@ func (s *GovernanceStateHelper) IncDKGFinalizedsCount(round *big.Int) { count := s.getStateBigInt(loc) s.setStateBigInt(loc, new(big.Int).Add(count, big.NewInt(1))) } +func (s *GovernanceStateHelper) ResetDKGFinalizedsCount(round *big.Int) { + loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgFinalizedsCountLoc)), round) + s.setStateBigInt(loc, big.NewInt(0)) +} // address public owner; func (s *GovernanceStateHelper) Owner() common.Address { @@ -1283,7 +888,7 @@ func (s *GovernanceStateHelper) SetFineValues(values []*big.Int) { } } -// uint256[] public fineRdecords; +// mapping(bytes32 => bool) 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 @@ -1297,6 +902,17 @@ func (s *GovernanceStateHelper) SetFineRecords(recordHash Bytes32, status bool) s.setStateBigInt(loc, big.NewInt(value)) } +// uint256[] public DKGResetCount; +func (s *GovernanceStateHelper) DKGResetCount(round *big.Int) *big.Int { + arrayBaseLoc := s.getSlotLoc(big.NewInt(dkgResetCountLoc)) + return s.getStateBigInt(new(big.Int).Add(arrayBaseLoc, round)) +} +func (s *GovernanceStateHelper) IncDKGResetCount(round *big.Int) { + loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgResetCountLoc)), round) + count := s.getStateBigInt(loc) + s.setStateBigInt(loc, new(big.Int).Add(count, big.NewInt(1))) +} + // Stake is a helper function for creating genesis state. func (s *GovernanceStateHelper) Stake( addr common.Address, publicKey []byte, staked *big.Int, @@ -1416,7 +1032,7 @@ func (s *GovernanceStateHelper) UpdateConfigurationRaw(cfg *rawConfigStruct) { func (s *GovernanceStateHelper) emitConfigurationChangedEvent() { s.StateDB.AddLog(&types.Log{ Address: GovernanceContractAddress, - Topics: []common.Hash{events["ConfigurationChanged"].Id()}, + Topics: []common.Hash{GovernanceABI.Events["ConfigurationChanged"].Id()}, Data: []byte{}, }) } @@ -1425,7 +1041,7 @@ func (s *GovernanceStateHelper) emitConfigurationChangedEvent() { 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)}, + Topics: []common.Hash{GovernanceABI.Events["CRSProposed"].Id(), common.BigToHash(round)}, Data: crs.Bytes(), }) } @@ -1434,7 +1050,7 @@ func (s *GovernanceStateHelper) emitCRSProposed(round *big.Int, crs common.Hash) func (s *GovernanceStateHelper) emitStaked(nodeAddr common.Address) { s.StateDB.AddLog(&types.Log{ Address: GovernanceContractAddress, - Topics: []common.Hash{events["Staked"].Id(), nodeAddr.Hash()}, + Topics: []common.Hash{GovernanceABI.Events["Staked"].Id(), nodeAddr.Hash()}, Data: []byte{}, }) } @@ -1443,7 +1059,16 @@ func (s *GovernanceStateHelper) emitStaked(nodeAddr common.Address) { func (s *GovernanceStateHelper) emitUnstaked(nodeAddr common.Address) { s.StateDB.AddLog(&types.Log{ Address: GovernanceContractAddress, - Topics: []common.Hash{events["Unstaked"].Id(), nodeAddr.Hash()}, + Topics: []common.Hash{GovernanceABI.Events["Unstaked"].Id(), nodeAddr.Hash()}, + Data: []byte{}, + }) +} + +// event NodeRemoved(address indexed NodeAddress); +func (s *GovernanceStateHelper) emitNodeRemoved(nodeAddr common.Address) { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{GovernanceABI.Events["NodeRemoved"].Id(), nodeAddr.Hash()}, Data: []byte{}, }) } @@ -1452,25 +1077,25 @@ func (s *GovernanceStateHelper) emitUnstaked(nodeAddr common.Address) { 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()}, + Topics: []common.Hash{GovernanceABI.Events["Delegated"].Id(), nodeAddr.Hash(), delegatorAddr.Hash()}, Data: common.BigToHash(amount).Bytes(), }) } -// event Undelegated(address indexed NodeAddress, address indexed DelegatorAddress); -func (s *GovernanceStateHelper) emitUndelegated(nodeAddr, delegatorAddr common.Address) { +// 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: []byte{}, + 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) { +// event Withdrawn(address indexed NodeAddress, address indexed DelegatorAddress, uint256 Amount); +func (s *GovernanceStateHelper) emitWithdrawn(nodeAddr common.Address, delegatorAddr common.Address, amount *big.Int) { s.StateDB.AddLog(&types.Log{ Address: GovernanceContractAddress, - Topics: []common.Hash{events["Withdrawn"].Id(), nodeAddr.Hash()}, + Topics: []common.Hash{GovernanceABI.Events["Withdrawn"].Id(), nodeAddr.Hash(), delegatorAddr.Hash()}, Data: common.BigToHash(amount).Bytes(), }) } @@ -1502,7 +1127,7 @@ func (s *GovernanceStateHelper) emitForkReported(nodeAddr common.Address, report } s.StateDB.AddLog(&types.Log{ Address: GovernanceContractAddress, - Topics: []common.Hash{events["ForkReported"].Id(), nodeAddr.Hash()}, + Topics: []common.Hash{GovernanceABI.Events["ForkReported"].Id(), nodeAddr.Hash()}, Data: data, }) } @@ -1511,7 +1136,7 @@ func (s *GovernanceStateHelper) emitForkReported(nodeAddr common.Address, report 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()}, + Topics: []common.Hash{GovernanceABI.Events["Fined"].Id(), nodeAddr.Hash()}, Data: common.BigToHash(amount).Bytes(), }) } @@ -1520,24 +1145,79 @@ func (s *GovernanceStateHelper) emitFined(nodeAddr common.Address, amount *big.I 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()}, + Topics: []common.Hash{GovernanceABI.Events["FinePaid"].Id(), nodeAddr.Hash()}, Data: common.BigToHash(amount).Bytes(), }) } +// event DKGReset(uint256 indexed Round, uint256 BlockHeight); +func (s *GovernanceStateHelper) emitDKGReset(round *big.Int, blockHeight *big.Int) { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{GovernanceABI.Events["DKGReset"].Id(), common.BigToHash(round)}, + Data: common.BigToHash(blockHeight).Bytes(), + }) +} + +func getConfigState(evm *EVM, 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-1))) + } + + gs := &GovernanceStateHelper{evm.StateDB} + height := gs.RoundHeight(configRound).Uint64() + if round.Uint64() >= core.ConfigRoundShift { + if height == 0 { + return nil, errExecutionReverted + } + height-- + } + statedb, err := evm.StateAtNumber(height) + return &GovernanceStateHelper{statedb}, err +} + +type coreDKGUtils interface { + SetState(GovernanceStateHelper) + NewGroupPublicKey(*big.Int, int) (tsigVerifierIntf, error) +} +type tsigVerifierIntf interface { + VerifySignature(coreCommon.Hash, coreCrypto.Signature) bool +} + // GovernanceContract represents the governance contract of DEXCON. type GovernanceContract struct { - evm *EVM - state GovernanceStateHelper - contract *vm.Contract + evm *EVM + state GovernanceStateHelper + contract *vm.Contract + coreDKGUtils coreDKGUtils +} + +// defaultCoreDKGUtils implements coreDKGUtils. +type defaultCoreDKGUtils struct { + state GovernanceStateHelper } -func newGovernanceContract(evm *EVM, contract *vm.Contract) *GovernanceContract { - return &GovernanceContract{ - evm: evm, - state: GovernanceStateHelper{evm.StateDB}, - contract: contract, +func (c *defaultCoreDKGUtils) SetState(state GovernanceStateHelper) { + c.state = state +} + +func (c *defaultCoreDKGUtils) NewGroupPublicKey(round *big.Int, + threshold int) (tsigVerifierIntf, error) { + // Prepare DKGMasterPublicKeys. + mpks := c.state.UniqueDKGMasterPublicKeys(round) + + // Prepare DKGComplaints. + var complaints []*dkgTypes.Complaint + for _, comp := range c.state.DKGComplaints(round) { + x := new(dkgTypes.Complaint) + if err := rlp.DecodeBytes(comp, x); err != nil { + panic(err) + } + complaints = append(complaints, x) } + + return core.NewDKGGroupPublicKey(round.Uint64(), mpks, complaints, threshold) } func (g *GovernanceContract) Address() common.Address { @@ -1565,21 +1245,21 @@ func (g *GovernanceContract) penalize() ([]byte, error) { 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))) +func (g *GovernanceContract) configDKGSetSize(round *big.Int) *big.Int { + s, err := getConfigState(g.evm, round) + if err != nil { + panic(err) } + return s.DKGSetSize() +} +func (g *GovernanceContract) getDKGSet(round *big.Int) map[coreTypes.NodeID]struct{} { + target := coreTypes.NewDKGSetTarget(coreCommon.Hash(g.state.CRS(round))) + ns := coreTypes.NewNodeSet() - statedb, err := g.evm.StateAtNumber(g.state.RoundHeight(configRound).Uint64()) + state, err := getConfigState(g.evm, round) if err != nil { panic(err) } - - state := GovernanceStateHelper{statedb} for _, x := range state.QualifiedNodes() { mpk, err := ecdsa.NewPublicKeyFromByteSlice(x.PublicKey) if err != nil { @@ -1587,8 +1267,11 @@ func (g *GovernanceContract) inDKGSet(round *big.Int, nodeID coreTypes.NodeID) b } ns.Add(coreTypes.NewNodeID(mpk)) } + return ns.GetSubSet(int(g.configDKGSetSize(round).Uint64()), target) +} - dkgSet := ns.GetSubSet(int(g.state.DKGSetSize().Uint64()), target) +func (g *GovernanceContract) inDKGSet(round *big.Int, nodeID coreTypes.NodeID) bool { + dkgSet := g.getDKGSet(round) _, ok := dkgSet[nodeID] return ok } @@ -1898,7 +1581,7 @@ func (g *GovernanceContract) undelegateHelper(nodeAddr, caller common.Address) ( // Subtract to network total staked. g.state.DecTotalStaked(delegator.Value) - g.state.emitUndelegated(nodeAddr, caller) + g.state.emitUndelegated(nodeAddr, caller, delegator.Value) return g.useGas(100000) } @@ -1949,7 +1632,7 @@ func (g *GovernanceContract) withdraw(nodeAddr common.Address) ([]byte, error) { return nil, errExecutionReverted } - g.state.emitWithdrawn(nodeAddr, delegator.Value) + g.state.emitWithdrawn(nodeAddr, delegator.Owner, 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 { @@ -1966,6 +1649,7 @@ func (g *GovernanceContract) withdraw(nodeAddr common.Address) ([]byte, error) { } g.state.DeleteNodesOffsetByAddress(nodeAddr) g.state.PopLastNode() + g.state.emitNodeRemoved(nodeAddr) } return g.useGas(100000) @@ -2036,23 +1720,10 @@ func (g *GovernanceContract) proposeCRS(nextRound *big.Int, signedCRS []byte) ([ 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) + dkgGPK, err := g.coreDKGUtils.NewGroupPublicKey( + round, threshold) if err != nil { return nil, errExecutionReverted } @@ -2163,6 +1834,556 @@ func (g *GovernanceContract) report(reportType *big.Int, arg1, arg2 []byte) ([]b return nil, nil } +func (g *GovernanceContract) resetDKG(newSignedCRS []byte) ([]byte, error) { + // Check if current block over 80% of current round. + round := g.state.Round() + resetCount := g.state.DKGResetCount(round) + // Just restart DEXON if failed at round 0. + if round.Cmp(big.NewInt(0)) == 0 { + return nil, errExecutionReverted + } + + // target = 80 + 100 * DKGResetCount + target := new(big.Int).Add( + big.NewInt(80), + new(big.Int).Mul(big.NewInt(100), resetCount)) + + // Round() is increased if CRS is signed. But we want to extend round r-1 now. + curRound := new(big.Int).Sub(round, big.NewInt(1)) + roundHeight := g.state.RoundHeight(curRound) + gs, err := getConfigState(g.evm, curRound) + if err != nil { + return nil, err + } + config := gs.Configuration() + + targetBlockNum := new(big.Int).SetUint64(config.RoundInterval / config.MinBlockInterval) + targetBlockNum.Mul(targetBlockNum, target) + targetBlockNum.Quo(targetBlockNum, big.NewInt(100)) + targetBlockNum.Add(targetBlockNum, roundHeight) + + blockHeight := g.evm.Context.BlockNumber + if blockHeight.Cmp(targetBlockNum) < 0 { + return nil, errExecutionReverted + } + + // Check if next DKG did not success. + // 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, check if DKG succeeded. + if g.state.DKGFinalizedsCount(round).Cmp(threshold) > 0 { + _, err := g.coreDKGUtils.NewGroupPublicKey( + round, int(threshold.Int64())) + // DKG success. + if err == nil { + return nil, errExecutionReverted + } + switch err { + case core.ErrNotReachThreshold, core.ErrInvalidThreshold: + default: + return nil, errExecutionReverted + } + } + // Clear dkg states for next round. + dkgSet := g.getDKGSet(round) + g.state.ClearDKGMasterPublicKeys(round) + g.state.ClearDKGComplaints(round) + g.state.ClearDKGMPKReady(round, dkgSet) + g.state.ResetDKGMPKReadysCount(round) + g.state.ClearDKGFinalized(round, dkgSet) + g.state.ResetDKGFinalizedsCount(round) + // Update CRS. + prevCRS := g.state.CRS(curRound) + for i := uint64(0); i < resetCount.Uint64()+1; i++ { + prevCRS = crypto.Keccak256Hash(prevCRS[:]) + } + + dkgGPK, err := g.coreDKGUtils.NewGroupPublicKey( + curRound, int(config.DKGSetSize/3+1)) + if err != nil { + return nil, errExecutionReverted + } + signature := coreCrypto.Signature{ + Type: "bls", + Signature: newSignedCRS, + } + if !dkgGPK.VerifySignature(coreCommon.Hash(prevCRS), signature) { + return g.penalize() + } + + // Save new CRS into state and increase round. + newCRS := crypto.Keccak256(newSignedCRS) + crs := common.BytesToHash(newCRS) + + g.state.PopCRS() + g.state.PushCRS(crs) + g.state.emitCRSProposed(round, crs) + + // Increase reset count. + g.state.IncDKGResetCount(round) + + g.state.emitDKGReset(round, blockHeight) + return nil, nil +} + +// Run executes governance contract. +func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *vm.Contract) (ret []byte, err error) { + if len(input) < 4 { + return nil, errExecutionReverted + } + + // Initialize contract state. + g.evm = evm + g.state = GovernanceStateHelper{evm.StateDB} + g.contract = contract + g.coreDKGUtils.SetState(g.state) + + // 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 "resetDKG": + args := struct { + NewSignedCRS []byte + }{} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + return g.resetDKG(args.NewSignedCRS) + 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 + case "DKGResetCount": + round := new(big.Int) + if err := method.Inputs.Unpack(&round, arguments); err != nil { + return nil, errExecutionReverted + } + res, err := method.Outputs.Pack(g.state.DKGResetCount(round)) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + } + return nil, errExecutionReverted +} + func (g *GovernanceContract) transferOwnership(newOwner common.Address) ([]byte, error) { // Only owner can update configuration. if g.contract.Caller() != g.state.Owner() { @@ -2172,27 +2393,183 @@ func (g *GovernanceContract) transferOwnership(newOwner common.Address) ([]byte, return nil, nil } -func (g *GovernanceContract) snapshotRound(round, height *big.Int) ([]byte, error) { - // Validate if this mapping is correct. Only block proposer need to verify this. - if g.evm.IsBlockProposer() { - realHeight, ok := g.evm.GetRoundHeight(round.Uint64()) - if !ok { - return g.penalize() - } +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 +} - if height.Cmp(new(big.Int).SetUint64(realHeight)) != 0 { - return g.penalize() - } +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 +} - // Only allow updating the next round. - nextRound := g.state.LenRoundHeight() - if round.Cmp(nextRound) != 0 { - // No need to penalize, since the only possibility at this point is the - // round height is already snapshoted. +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 *vm.Contract) (ret []byte, err error) { + if len(input) < 4 { return nil, errExecutionReverted } - g.state.PushRoundHeight(height) - return nil, nil + // Parse input. + method, exists := NodeInfoOracleABI.Sig2Method[string(input[:4])] + if !exists { + return nil, errExecutionReverted + } + + arguments := input[4:] + + // 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(evm, 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(evm, 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(evm, 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/evm/governance_test.go b/core/vm/evm/oracle_contracts_test.go index 5a82c7f1a..632d1dce3 100644 --- a/core/vm/evm/governance_test.go +++ b/core/vm/evm/oracle_contracts_test.go @@ -47,7 +47,10 @@ func init() { } func randomBytes(minLength, maxLength int32) []byte { - length := rand.Int31()%(maxLength-minLength) + minLength + length := minLength + if maxLength != minLength { + length += rand.Int31() % (maxLength - minLength) + } b := make([]byte, length) for i := range b { b[i] = byte(65 + rand.Int31()%60) @@ -70,7 +73,7 @@ func (g *GovernanceStateHelperTestSuite) SetupTest() { g.s = &GovernanceStateHelper{statedb} } -func (g *GovernanceStateHelperTestSuite) TestReadWriteBytes() { +func (g *GovernanceStateHelperTestSuite) TestReadWriteEraseBytes() { for i := 0; i < 100; i++ { // Short bytes. loc := big.NewInt(rand.Int63()) @@ -78,6 +81,9 @@ func (g *GovernanceStateHelperTestSuite) TestReadWriteBytes() { g.s.writeBytes(loc, data) read := g.s.readBytes(loc) g.Require().Equal(0, bytes.Compare(data, read)) + g.s.eraseBytes(loc) + read = g.s.readBytes(loc) + g.Require().Len(read, 0) // long bytes. loc = big.NewInt(rand.Int63()) @@ -85,6 +91,31 @@ func (g *GovernanceStateHelperTestSuite) TestReadWriteBytes() { g.s.writeBytes(loc, data) read = g.s.readBytes(loc) g.Require().Equal(0, bytes.Compare(data, read)) + g.s.eraseBytes(loc) + read = g.s.readBytes(loc) + g.Require().Len(read, 0) + } +} + +func (g *GovernanceStateHelperTestSuite) TestReadWriteErase2DArray() { + for i := 0; i < 50; i++ { + loc := big.NewInt(rand.Int63()) + for j := 0; j < 50; j++ { + idx := big.NewInt(int64(j)) + data := make([][]byte, 30) + for key := range data { + data[key] = randomBytes(3, 32) + g.s.appendTo2DByteArray(loc, idx, data[key]) + } + read := g.s.read2DByteArray(loc, idx) + g.Require().Len(read, len(data)) + for key := range data { + g.Require().Equal(0, bytes.Compare(data[key], read[key])) + } + g.s.erase2DByteArray(loc, idx) + read = g.s.read2DByteArray(loc, idx) + g.Require().Len(read, 0) + } } } @@ -92,16 +123,17 @@ func TestGovernanceStateHelper(t *testing.T) { suite.Run(t, new(GovernanceStateHelperTestSuite)) } -type GovernanceContractTestSuite struct { +type OracleContractsTestSuite struct { suite.Suite + context vm.Context config *params.DexconConfig memDB *ethdb.MemDatabase stateDB *state.StateDB s *GovernanceStateHelper } -func (g *GovernanceContractTestSuite) SetupTest() { +func (g *OracleContractsTestSuite) SetupTest() { memDB := ethdb.NewMemDatabase() stateDB, err := state.New(common.Hash{}, state.NewDatabase(memDB)) if err != nil { @@ -116,6 +148,7 @@ func (g *GovernanceContractTestSuite) SetupTest() { config.NextHalvingSupply = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2.5e9)) config.LastHalvedAmount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1.5e9)) config.MiningVelocity = 0.1875 + config.DKGSetSize = 7 g.config = config @@ -136,21 +169,8 @@ func (g *GovernanceContractTestSuite) SetupTest() { g.s.UpdateConfiguration(config) g.stateDB.Commit(true) -} - -func (g *GovernanceContractTestSuite) newPrefundAccount() (*ecdsa.PrivateKey, common.Address) { - privKey, err := crypto.GenerateKey() - if err != nil { - panic(err) - } - address := crypto.PubkeyToAddress(privKey.PublicKey) - - g.stateDB.AddBalance(address, new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2e6))) - return privKey, address -} -func (g *GovernanceContractTestSuite) call(caller common.Address, input []byte, value *big.Int) ([]byte, error) { - context := vm.Context{ + g.context = vm.Context{ CanTransfer: func(db vm.StateDB, addr common.Address, amount *big.Int) bool { return db.GetBalance(addr).Cmp(amount) >= 0 }, @@ -169,41 +189,65 @@ func (g *GovernanceContractTestSuite) call(caller common.Address, input []byte, } return 0, false }, - Time: big.NewInt(time.Now().UnixNano() / 1000000), + StateAtNumber: func(n uint64) (*state.StateDB, error) { + return g.stateDB, nil + }, BlockNumber: big.NewInt(0), } - evm := NewEVM(context, g.stateDB, params.TestChainConfig, Config{IsBlockProposer: true}) - ret, _, err := evm.Call(vm.AccountRef(caller), GovernanceContractAddress, input, 10000000, value) +} + +func (g *OracleContractsTestSuite) TearDownTest() { + OracleContracts[GovernanceContractAddress].(*GovernanceContract).coreDKGUtils = &defaultCoreDKGUtils{} +} + +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) { + + g.context.Time = big.NewInt(time.Now().UnixNano() / 1000000) + + evm := NewEVM(g.context, g.stateDB, params.TestChainConfig, Config{IsBlockProposer: true}) + ret, _, err := evm.Call(vm.AccountRef(caller), contractAddr, input, 10000000, value) return ret, err } -func (g *GovernanceContractTestSuite) TestTransferOwnership() { +func (g *OracleContractsTestSuite) TestTransferOwnership() { _, addr := g.newPrefundAccount() - input, err := abiObject.Pack("transferOwnership", addr) + input, err := GovernanceABI.ABI.Pack("transferOwnership", addr) g.Require().NoError(err) // Call with non-owner. - _, err = g.call(addr, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NotNil(err) // Call with owner. - _, err = g.call(g.config.Owner, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, g.config.Owner, input, big.NewInt(0)) g.Require().NoError(err) g.Require().Equal(addr, g.s.Owner()) } -func (g *GovernanceContractTestSuite) TestStakeUnstakeWithoutExtraDelegators() { +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 := abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + input, err := GovernanceABI.ABI.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") g.Require().NoError(err) - _, err = g.call(addr, input, amount) + _, err = g.call(GovernanceContractAddress, addr, input, amount) g.Require().NoError(err) g.Require().Equal(1, int(g.s.LenNodes().Uint64())) @@ -216,13 +260,13 @@ func (g *GovernanceContractTestSuite) TestStakeUnstakeWithoutExtraDelegators() { 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) + _, err = g.call(GovernanceContractAddress, addr, input, amount) g.Require().NotNil(err) // Unstake. - input, err = abiObject.Pack("unstake") + input, err = GovernanceABI.ABI.Pack("unstake") g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) + _, 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())) @@ -234,9 +278,9 @@ func (g *GovernanceContractTestSuite) TestStakeUnstakeWithoutExtraDelegators() { // Wait for lockup time than withdraw. time.Sleep(time.Second * 2) - input, err = abiObject.Pack("withdraw", addr) + input, err = GovernanceABI.ABI.Pack("withdraw", addr) g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) g.Require().Equal(0, len(g.s.QualifiedNodes())) @@ -248,26 +292,26 @@ func (g *GovernanceContractTestSuite) TestStakeUnstakeWithoutExtraDelegators() { // 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") + input, err = GovernanceABI.ABI.Pack("stake", pk2, "Test2", "test2@dexon.org", "Taipei, Taiwan", "https://dexon.org") g.Require().NoError(err) - _, err = g.call(addr2, input, amount) + _, 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 = abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + input, err = GovernanceABI.ABI.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") g.Require().NoError(err) - _, err = g.call(addr, input, amount) + _, 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 = abiObject.Pack("unstake") + input, err = GovernanceABI.ABI.Pack("unstake") g.Require().NoError(err) - _, err = g.call(addr2, input, big.NewInt(0)) + _, 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) @@ -276,9 +320,9 @@ func (g *GovernanceContractTestSuite) TestStakeUnstakeWithoutExtraDelegators() { g.Require().Equal(amount.String(), g.s.TotalStaked().String()) time.Sleep(time.Second * 2) - input, err = abiObject.Pack("withdraw", addr2) + input, err = GovernanceABI.ABI.Pack("withdraw", addr2) g.Require().NoError(err) - _, err = g.call(addr2, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, addr2, input, big.NewInt(0)) g.Require().NoError(err) g.Require().Equal(1, len(g.s.QualifiedNodes())) @@ -287,17 +331,17 @@ func (g *GovernanceContractTestSuite) TestStakeUnstakeWithoutExtraDelegators() { g.Require().Equal(-1, int(g.s.NodesOffsetByAddress(addr2).Int64())) // 1st node Unstake. - input, err = abiObject.Pack("unstake") + input, err = GovernanceABI.ABI.Pack("unstake") g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) + _, 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 = abiObject.Pack("withdraw", addr) + input, err = GovernanceABI.ABI.Pack("withdraw", addr) g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) g.Require().Equal(0, int(g.s.LenNodes().Uint64())) @@ -310,15 +354,15 @@ func (g *GovernanceContractTestSuite) TestStakeUnstakeWithoutExtraDelegators() { g.Require().Equal(big.NewInt(1), g.stateDB.GetBalance(GovernanceContractAddress)) } -func (g *GovernanceContractTestSuite) TestDelegateUndelegate() { +func (g *OracleContractsTestSuite) 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") + 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(addr, input, ownerStaked) + _, 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) @@ -329,10 +373,10 @@ func (g *GovernanceContractTestSuite) TestDelegateUndelegate() { balanceBeforeDelegate := g.stateDB.GetBalance(addrDelegator) amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3e5)) - input, err = abiObject.Pack("delegate", addr) + input, err = GovernanceABI.ABI.Pack("delegate", addr) g.Require().NoError(err) - _, err = g.call(addrDelegator, input, amount) + _, 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) @@ -341,7 +385,7 @@ func (g *GovernanceContractTestSuite) TestDelegateUndelegate() { 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)) + _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(1e18)) g.Require().NotNil(err) // Not yet qualified. @@ -349,7 +393,7 @@ func (g *GovernanceContractTestSuite) TestDelegateUndelegate() { // 2nd delegator delegate to 1st node. _, addrDelegator2 := g.newPrefundAccount() - _, err = g.call(addrDelegator2, input, amount) + _, 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) @@ -363,21 +407,21 @@ func (g *GovernanceContractTestSuite) TestDelegateUndelegate() { // Undelegate addrDelegator. balanceBeforeUnDelegate := g.stateDB.GetBalance(addrDelegator) - input, err = abiObject.Pack("undelegate", addr) + input, err = GovernanceABI.ABI.Pack("undelegate", addr) g.Require().NoError(err) - _, err = g.call(addrDelegator, input, big.NewInt(0)) + _, 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(addrDelegator, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) g.Require().Error(err) // Withdraw within lockup time should fail. - input, err = abiObject.Pack("withdraw", addr) + input, err = GovernanceABI.ABI.Pack("withdraw", addr) g.Require().NoError(err) - _, err = g.call(addrDelegator, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) g.Require().NotNil(err) g.Require().Equal(3, int(g.s.LenDelegators(addr).Uint64())) @@ -386,9 +430,9 @@ func (g *GovernanceContractTestSuite) TestDelegateUndelegate() { // Wait for lockup time than withdraw. time.Sleep(time.Second * 2) - input, err = abiObject.Pack("withdraw", addr) + input, err = GovernanceABI.ABI.Pack("withdraw", addr) g.Require().NoError(err) - _, err = g.call(addrDelegator, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) g.Require().NoError(err) g.Require().Equal(2, int(g.s.LenDelegators(addr).Uint64())) @@ -397,16 +441,16 @@ func (g *GovernanceContractTestSuite) TestDelegateUndelegate() { // Withdraw when their is no delegation should fail. time.Sleep(time.Second) - input, err = abiObject.Pack("withdraw", addr) + input, err = GovernanceABI.ABI.Pack("withdraw", addr) g.Require().NoError(err) - _, err = g.call(addrDelegator, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) g.Require().Error(err) // Undelegate addrDelegator2. balanceBeforeUnDelegate = g.stateDB.GetBalance(addrDelegator2) - input, err = abiObject.Pack("undelegate", addr) + input, err = GovernanceABI.ABI.Pack("undelegate", addr) g.Require().NoError(err) - _, err = g.call(addrDelegator2, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, addrDelegator2, input, big.NewInt(0)) g.Require().NoError(err) g.Require().Equal(ownerStaked, g.s.Node(big.NewInt(0)).Staked) @@ -414,9 +458,9 @@ func (g *GovernanceContractTestSuite) TestDelegateUndelegate() { // Wait for lockup time than withdraw. time.Sleep(time.Second * 2) - input, err = abiObject.Pack("withdraw", addr) + input, err = GovernanceABI.ABI.Pack("withdraw", addr) g.Require().NoError(err) - _, err = g.call(addrDelegator2, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, addrDelegator2, input, big.NewInt(0)) g.Require().NoError(err) g.Require().Equal(1, int(g.s.LenDelegators(addr).Uint64())) @@ -430,31 +474,31 @@ func (g *GovernanceContractTestSuite) TestDelegateUndelegate() { 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) + input, err = GovernanceABI.ABI.Pack("undelegate", addr) g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) + _, 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 = abiObject.Pack("withdraw", addr) + input, err = GovernanceABI.ABI.Pack("withdraw", addr) g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) + _, 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 *GovernanceContractTestSuite) TestFine() { +func (g *OracleContractsTestSuite) 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") + 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(addr, input, ownerStaked) + _, 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) @@ -465,10 +509,10 @@ func (g *GovernanceContractTestSuite) TestFine() { balanceBeforeDelegate := g.stateDB.GetBalance(addrDelegator) amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - input, err = abiObject.Pack("delegate", addr) + input, err = GovernanceABI.ABI.Pack("delegate", addr) g.Require().NoError(err) - _, err = g.call(addrDelegator, input, amount) + _, 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) @@ -479,9 +523,9 @@ func (g *GovernanceContractTestSuite) TestFine() { g.Require().Equal(1, len(g.s.QualifiedNodes())) // Paying to node without fine should fail. - input, err = abiObject.Pack("payFine", addr) + input, err = GovernanceABI.ABI.Pack("payFine", addr) g.Require().NoError(err) - _, err = g.call(addrDelegator, input, amount) + _, err = g.call(GovernanceContractAddress, addrDelegator, input, amount) g.Require().NotNil(err) // Fined. @@ -497,50 +541,50 @@ func (g *GovernanceContractTestSuite) TestFine() { g.Require().Equal(0, len(g.s.QualifiedNodes())) // Cannot undelegate before fines are paied. - input, err = abiObject.Pack("undelegate", addr) + input, err = GovernanceABI.ABI.Pack("undelegate", addr) g.Require().NoError(err) - _, err = g.call(addrDelegator, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) g.Require().NotNil(err) // Only delegators can pay fine. _, addrDelegator2 := g.newPrefundAccount() - input, err = abiObject.Pack("payFine", addr) + input, err = GovernanceABI.ABI.Pack("payFine", addr) g.Require().NoError(err) - _, err = g.call(addrDelegator2, input, big.NewInt(5e5)) + _, 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 = abiObject.Pack("payFine", addr) + input, err = GovernanceABI.ABI.Pack("payFine", addr) g.Require().NoError(err) - _, err = g.call(addrDelegator, input, payAmount) + _, err = g.call(GovernanceContractAddress, addrDelegator, input, payAmount) g.Require().NotNil(err) // Pay the fine. - input, err = abiObject.Pack("payFine", addr) + input, err = GovernanceABI.ABI.Pack("payFine", addr) g.Require().NoError(err) - _, err = g.call(addrDelegator, input, amount) + _, 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 = abiObject.Pack("undelegate", addr) + input, err = GovernanceABI.ABI.Pack("undelegate", addr) g.Require().NoError(err) - _, err = g.call(addrDelegator, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) g.Require().NoError(err) } -func (g *GovernanceContractTestSuite) TestUnstakeWithExtraDelegators() { +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 := abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + input, err := GovernanceABI.ABI.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") g.Require().NoError(err) - _, err = g.call(addr, input, amount) + _, err = g.call(GovernanceContractAddress, addr, input, amount) g.Require().NoError(err) // 1st delegator delegate to 1st node. @@ -548,10 +592,10 @@ func (g *GovernanceContractTestSuite) TestUnstakeWithExtraDelegators() { balanceBeforeDelegate := g.stateDB.GetBalance(addrDelegator) amount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3e5)) - input, err = abiObject.Pack("delegate", addr) + input, err = GovernanceABI.ABI.Pack("delegate", addr) g.Require().NoError(err) - _, err = g.call(addrDelegator, input, amount) + _, 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) @@ -561,10 +605,10 @@ func (g *GovernanceContractTestSuite) TestUnstakeWithExtraDelegators() { _, addrDelegator2 := g.newPrefundAccount() balanceBeforeDelegate = g.stateDB.GetBalance(addrDelegator2) - input, err = abiObject.Pack("delegate", addr) + input, err = GovernanceABI.ABI.Pack("delegate", addr) g.Require().NoError(err) - _, err = g.call(addrDelegator2, input, amount) + _, 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) @@ -573,19 +617,19 @@ func (g *GovernanceContractTestSuite) TestUnstakeWithExtraDelegators() { g.Require().Equal(1, len(g.s.QualifiedNodes())) // Unstake. - input, err = abiObject.Pack("unstake") + input, err = GovernanceABI.ABI.Pack("unstake") g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) time.Sleep(time.Second * 2) - input, err = abiObject.Pack("withdraw", addr) + input, err = GovernanceABI.ABI.Pack("withdraw", addr) g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) - _, err = g.call(addrDelegator, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) g.Require().NoError(err) - _, err = g.call(addrDelegator2, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, addrDelegator2, input, big.NewInt(0)) g.Require().NoError(err) g.Require().Equal(0, int(g.s.LenDelegators(addr).Uint64())) @@ -598,10 +642,10 @@ func (g *GovernanceContractTestSuite) TestUnstakeWithExtraDelegators() { g.Require().Equal(big.NewInt(1), g.stateDB.GetBalance(GovernanceContractAddress)) } -func (g *GovernanceContractTestSuite) TestUpdateConfiguration() { +func (g *OracleContractsTestSuite) TestUpdateConfiguration() { _, addr := g.newPrefundAccount() - input, err := abiObject.Pack("updateConfiguration", + input, err := GovernanceABI.ABI.Pack("updateConfiguration", new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)), big.NewInt(1000), big.NewInt(0.1875*decimalMultiplier), @@ -621,196 +665,156 @@ func (g *GovernanceContractTestSuite) TestUpdateConfiguration() { g.Require().NoError(err) // Call with non-owner. - _, err = g.call(addr, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NotNil(err) // Call with owner. - _, err = g.call(g.config.Owner, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, g.config.Owner, input, big.NewInt(0)) g.Require().NoError(err) } -func (g *GovernanceContractTestSuite) TestSnapshotRound() { - _, addr := g.newPrefundAccount() - - // Wrong height. - input, err := abiObject.Pack("snapshotRound", big.NewInt(1), big.NewInt(666)) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NotNil(err) - - // Invalid round. - input, err = abiObject.Pack("snapshotRound", big.NewInt(2), big.NewInt(2000)) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NotNil(err) - - // Correct. - input, err = abiObject.Pack("snapshotRound", big.NewInt(1), big.NewInt(1000)) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - // Duplicate round. - input, err = abiObject.Pack("snapshotRound", big.NewInt(1), big.NewInt(1000)) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NotNil(err) - - // Invalid round. - input, err = abiObject.Pack("snapshotRound", big.NewInt(3), big.NewInt(3000)) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NotNil(err) - - // Correct. - input, err = abiObject.Pack("snapshotRound", big.NewInt(2), big.NewInt(2000)) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) -} - -func (g *GovernanceContractTestSuite) TestConfigurationReading() { +func (g *OracleContractsTestSuite) TestConfigurationReading() { _, addr := g.newPrefundAccount() // CRS. - input, err := abiObject.Pack("crs", big.NewInt(0)) + input, err := GovernanceABI.ABI.Pack("crs", big.NewInt(0)) g.Require().NoError(err) - res, err := g.call(addr, input, big.NewInt(0)) + res, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) var crs0 [32]byte - err = abiObject.Unpack(&crs0, "crs", res) + 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 = abiObject.Pack("owner") + input, err = GovernanceABI.ABI.Pack("owner") g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) var owner common.Address - err = abiObject.Unpack(&owner, "owner", res) + err = GovernanceABI.ABI.Unpack(&owner, "owner", res) g.Require().NoError(err) g.Require().Equal(g.config.Owner, owner) // MinStake. - input, err = abiObject.Pack("minStake") + input, err = GovernanceABI.ABI.Pack("minStake") g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) var value *big.Int - err = abiObject.Unpack(&value, "minStake", res) + err = GovernanceABI.ABI.Unpack(&value, "minStake", res) g.Require().NoError(err) g.Require().Equal(g.config.MinStake.String(), value.String()) // BlockReward. - input, err = abiObject.Pack("miningVelocity") + input, err = GovernanceABI.ABI.Pack("miningVelocity") g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) - err = abiObject.Unpack(&value, "miningVelocity", res) + err = GovernanceABI.ABI.Unpack(&value, "miningVelocity", res) g.Require().NoError(err) g.Require().Equal(g.config.MiningVelocity, float32(value.Uint64())/decimalMultiplier) // BlockGasLimit. - input, err = abiObject.Pack("blockGasLimit") + input, err = GovernanceABI.ABI.Pack("blockGasLimit") g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) - err = abiObject.Unpack(&value, "blockGasLimit", res) + err = GovernanceABI.ABI.Unpack(&value, "blockGasLimit", res) g.Require().NoError(err) g.Require().Equal(g.config.BlockGasLimit, value.Uint64()) // NumChains. - input, err = abiObject.Pack("numChains") + input, err = GovernanceABI.ABI.Pack("numChains") g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) - err = abiObject.Unpack(&value, "numChains", res) + err = GovernanceABI.ABI.Unpack(&value, "numChains", res) g.Require().NoError(err) g.Require().Equal(g.config.NumChains, uint32(value.Uint64())) // LambdaBA. - input, err = abiObject.Pack("lambdaBA") + input, err = GovernanceABI.ABI.Pack("lambdaBA") g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) - err = abiObject.Unpack(&value, "lambdaBA", res) + err = GovernanceABI.ABI.Unpack(&value, "lambdaBA", res) g.Require().NoError(err) g.Require().Equal(g.config.LambdaBA, value.Uint64()) // LambdaDKG. - input, err = abiObject.Pack("lambdaDKG") + input, err = GovernanceABI.ABI.Pack("lambdaDKG") g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) - err = abiObject.Unpack(&value, "lambdaDKG", res) + err = GovernanceABI.ABI.Unpack(&value, "lambdaDKG", res) g.Require().NoError(err) g.Require().Equal(g.config.LambdaDKG, value.Uint64()) // K. - input, err = abiObject.Pack("k") + input, err = GovernanceABI.ABI.Pack("k") g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) - err = abiObject.Unpack(&value, "k", res) + err = GovernanceABI.ABI.Unpack(&value, "k", res) g.Require().NoError(err) g.Require().Equal(g.config.K, uint32(value.Uint64())) // PhiRatio. - input, err = abiObject.Pack("phiRatio") + input, err = GovernanceABI.ABI.Pack("phiRatio") g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) - err = abiObject.Unpack(&value, "phiRatio", res) + err = GovernanceABI.ABI.Unpack(&value, "phiRatio", res) g.Require().NoError(err) g.Require().Equal(g.config.PhiRatio, float32(value.Uint64())/decimalMultiplier) // NotarySetSize. - input, err = abiObject.Pack("notarySetSize") + input, err = GovernanceABI.ABI.Pack("notarySetSize") g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) - err = abiObject.Unpack(&value, "notarySetSize", res) + err = GovernanceABI.ABI.Unpack(&value, "notarySetSize", res) g.Require().NoError(err) g.Require().Equal(g.config.NotarySetSize, uint32(value.Uint64())) // DKGSetSize. - input, err = abiObject.Pack("dkgSetSize") + input, err = GovernanceABI.ABI.Pack("dkgSetSize") g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) - err = abiObject.Unpack(&value, "dkgSetSize", res) + err = GovernanceABI.ABI.Unpack(&value, "dkgSetSize", res) g.Require().NoError(err) g.Require().Equal(g.config.DKGSetSize, uint32(value.Uint64())) // RoundInterval. - input, err = abiObject.Pack("roundInterval") + input, err = GovernanceABI.ABI.Pack("roundInterval") g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) - err = abiObject.Unpack(&value, "roundInterval", res) + err = GovernanceABI.ABI.Unpack(&value, "roundInterval", res) g.Require().NoError(err) g.Require().Equal(g.config.RoundInterval, value.Uint64()) // MinBlockInterval. - input, err = abiObject.Pack("minBlockInterval") + input, err = GovernanceABI.ABI.Pack("minBlockInterval") g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) - err = abiObject.Unpack(&value, "minBlockInterval", res) + err = GovernanceABI.ABI.Unpack(&value, "minBlockInterval", res) g.Require().NoError(err) g.Require().Equal(g.config.MinBlockInterval, value.Uint64()) } -func (g *GovernanceContractTestSuite) TestReportForkVote() { +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 := abiObject.Pack("stake", pkBytes, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + input, err := GovernanceABI.ABI.Pack("stake", pkBytes, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") g.Require().NoError(err) - _, err = g.call(addr, input, amount) + _, err = g.call(GovernanceContractAddress, addr, input, amount) g.Require().NoError(err) pubKey := coreEcdsa.NewPublicKeyFromECDSA(&key.PublicKey) @@ -833,23 +837,23 @@ func (g *GovernanceContractTestSuite) TestReportForkVote() { g.Require().NoError(err) // Report wrong type (fork block) - input, err = abiObject.Pack("report", big.NewInt(2), vote1Bytes, vote2Bytes) + input, err = GovernanceABI.ABI.Pack("report", big.NewInt(2), vote1Bytes, vote2Bytes) g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().Error(err) - input, err = abiObject.Pack("report", big.NewInt(1), vote1Bytes, vote2Bytes) + input, err = GovernanceABI.ABI.Pack("report", big.NewInt(1), vote1Bytes, vote2Bytes) g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) + _, 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 = abiObject.Pack("report", big.NewInt(1), vote1Bytes, vote2Bytes) + input, err = GovernanceABI.ABI.Pack("report", big.NewInt(1), vote1Bytes, vote2Bytes) g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().Error(err) // Check if finedRecords is set. @@ -857,26 +861,26 @@ func (g *GovernanceContractTestSuite) TestReportForkVote() { sort.Sort(sortBytes(payloads)) hash := Bytes32(crypto.Keccak256Hash(payloads...)) - input, err = abiObject.Pack("finedRecords", hash) + input, err = GovernanceABI.ABI.Pack("finedRecords", hash) g.Require().NoError(err) - res, err := g.call(addr, input, big.NewInt(0)) + res, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) var value bool - err = abiObject.Unpack(&value, "finedRecords", res) + err = GovernanceABI.ABI.Unpack(&value, "finedRecords", res) g.Require().NoError(err) g.Require().True(value) } -func (g *GovernanceContractTestSuite) TestReportForkBlock() { +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 := abiObject.Pack("stake", pkBytes, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + input, err := GovernanceABI.ABI.Pack("stake", pkBytes, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") g.Require().NoError(err) - _, err = g.call(addr, input, amount) + _, err = g.call(GovernanceContractAddress, addr, input, amount) g.Require().NoError(err) privKey := coreEcdsa.NewPrivateKeyFromECDSA(key) @@ -910,23 +914,23 @@ func (g *GovernanceContractTestSuite) TestReportForkBlock() { g.Require().NoError(err) // Report wrong type (fork vote) - input, err = abiObject.Pack("report", big.NewInt(1), block1Bytes, block2Bytes) + input, err = GovernanceABI.ABI.Pack("report", big.NewInt(1), block1Bytes, block2Bytes) g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().Error(err) - input, err = abiObject.Pack("report", big.NewInt(2), block1Bytes, block2Bytes) + input, err = GovernanceABI.ABI.Pack("report", big.NewInt(2), block1Bytes, block2Bytes) g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) + _, 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 = abiObject.Pack("report", big.NewInt(2), block1Bytes, block2Bytes) + input, err = GovernanceABI.ABI.Pack("report", big.NewInt(2), block1Bytes, block2Bytes) g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().Error(err) // Check if finedRecords is set. @@ -934,113 +938,113 @@ func (g *GovernanceContractTestSuite) TestReportForkBlock() { sort.Sort(sortBytes(payloads)) hash := Bytes32(crypto.Keccak256Hash(payloads...)) - input, err = abiObject.Pack("finedRecords", hash) + input, err = GovernanceABI.ABI.Pack("finedRecords", hash) g.Require().NoError(err) - res, err := g.call(addr, input, big.NewInt(0)) + res, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) var value bool - err = abiObject.Unpack(&value, "finedRecords", res) + err = GovernanceABI.ABI.Unpack(&value, "finedRecords", res) g.Require().NoError(err) g.Require().True(value) } -func (g *GovernanceContractTestSuite) TestMiscVariableReading() { +func (g *OracleContractsTestSuite) TestMiscVariableReading() { privKey, addr := g.newPrefundAccount() pk := crypto.FromECDSAPub(&privKey.PublicKey) - input, err := abiObject.Pack("totalSupply") + input, err := GovernanceABI.ABI.Pack("totalSupply") g.Require().NoError(err) - res, err := g.call(addr, input, big.NewInt(0)) + res, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) - input, err = abiObject.Pack("totalStaked") + input, err = GovernanceABI.ABI.Pack("totalStaked") g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) + 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 = abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + input, err = GovernanceABI.ABI.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") g.Require().NoError(err) - _, err = g.call(addr, input, amount) + _, 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 = abiObject.Pack("delegate", addr) + input, err = GovernanceABI.ABI.Pack("delegate", addr) g.Require().NoError(err) - _, err = g.call(addrDelegator, input, amount) + _, err = g.call(GovernanceContractAddress, addrDelegator, input, amount) g.Require().NoError(err) // 2st delegator delegate to 1st node. _, addrDelegator2 := g.newPrefundAccount() - input, err = abiObject.Pack("delegate", addr) + input, err = GovernanceABI.ABI.Pack("delegate", addr) g.Require().NoError(err) - _, err = g.call(addrDelegator2, input, amount) + _, err = g.call(GovernanceContractAddress, addrDelegator2, input, amount) g.Require().NoError(err) - input, err = abiObject.Pack("nodes", big.NewInt(0)) + input, err = GovernanceABI.ABI.Pack("nodes", big.NewInt(0)) g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) - input, err = abiObject.Pack("nodesLength") + input, err = GovernanceABI.ABI.Pack("nodesLength") g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) var value *big.Int - err = abiObject.Unpack(&value, "nodesLength", res) + err = GovernanceABI.ABI.Unpack(&value, "nodesLength", res) g.Require().NoError(err) g.Require().Equal(1, int(value.Uint64())) - input, err = abiObject.Pack("nodesOffsetByAddress", addr) + input, err = GovernanceABI.ABI.Pack("nodesOffsetByAddress", addr) g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) - err = abiObject.Unpack(&value, "nodesOffsetByAddress", res) + 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 = abiObject.Pack("nodesOffsetByID", id) + input, err = GovernanceABI.ABI.Pack("nodesOffsetByID", id) g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) - err = abiObject.Unpack(&value, "nodesOffsetByID", res) + err = GovernanceABI.ABI.Unpack(&value, "nodesOffsetByID", res) g.Require().NoError(err) g.Require().Equal(0, int(value.Uint64())) - input, err = abiObject.Pack("delegators", addr, big.NewInt(0)) + input, err = GovernanceABI.ABI.Pack("delegators", addr, big.NewInt(0)) g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) - input, err = abiObject.Pack("delegatorsLength", addr) + input, err = GovernanceABI.ABI.Pack("delegatorsLength", addr) g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) - err = abiObject.Unpack(&value, "delegatorsLength", res) + err = GovernanceABI.ABI.Unpack(&value, "delegatorsLength", res) g.Require().NoError(err) g.Require().Equal(3, int(value.Uint64())) - input, err = abiObject.Pack("delegatorsOffset", addr, addrDelegator2) + input, err = GovernanceABI.ABI.Pack("delegatorsOffset", addr, addrDelegator2) g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) - err = abiObject.Unpack(&value, "delegatorsOffset", res) + err = GovernanceABI.ABI.Unpack(&value, "delegatorsOffset", res) g.Require().NoError(err) g.Require().Equal(2, int(value.Uint64())) - input, err = abiObject.Pack("fineValues", big.NewInt(0)) + input, err = GovernanceABI.ABI.Pack("fineValues", big.NewInt(0)) g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) } -func (g *GovernanceContractTestSuite) TestHalvingCondition() { +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(), @@ -1056,6 +1060,202 @@ func (g *GovernanceContractTestSuite) TestHalvingCondition() { 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())) +} + +type testCoreMock struct { + newDKGGPKError error + tsigReturn bool +} + +func (m *testCoreMock) SetState(GovernanceStateHelper) {} + +func (m *testCoreMock) NewGroupPublicKey(*big.Int, int) (tsigVerifierIntf, error) { + if m.newDKGGPKError != nil { + return nil, m.newDKGGPKError + } + return &testTSigVerifierMock{m.tsigReturn}, nil +} + +type testTSigVerifierMock struct { + ret bool +} + +func (v *testTSigVerifierMock) VerifySignature(coreCommon.Hash, coreCrypto.Signature) bool { + return v.ret +} + +func (g *OracleContractsTestSuite) TestResetDKG() { + for i := uint32(0); i < g.config.DKGSetSize; i++ { + privKey, addr := g.newPrefundAccount() + pk := crypto.FromECDSAPub(&privKey.PublicKey) + + // Stake. + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)) + 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().Len(g.s.QualifiedNodes(), int(g.config.DKGSetSize)) + + addrs := make(map[int][]common.Address) + addDKG := func(round int, final bool) { + addrs[round] = []common.Address{} + r := big.NewInt(int64(round)) + target := coreTypes.NewDKGSetTarget(coreCommon.Hash(g.s.CRS(r))) + ns := coreTypes.NewNodeSet() + + for _, x := range g.s.QualifiedNodes() { + mpk, err := coreEcdsa.NewPublicKeyFromByteSlice(x.PublicKey) + if err != nil { + panic(err) + } + ns.Add(coreTypes.NewNodeID(mpk)) + } + dkgSet := ns.GetSubSet(int(g.s.DKGSetSize().Uint64()), target) + g.Require().Len(dkgSet, int(g.config.DKGSetSize)) + + for id := range dkgSet { + offset := g.s.NodesOffsetByID(Bytes32(id.Hash)) + if offset.Cmp(big.NewInt(0)) < 0 { + panic("DKG node does not exist") + } + node := g.s.Node(offset) + // Prepare MPK. + g.s.PushDKGMasterPublicKey(r, randomBytes(32, 64)) + // Prepare Complaint. + g.s.PushDKGComplaint(r, randomBytes(32, 64)) + addr := node.Owner + addrs[round] = append(addrs[round], addr) + // Prepare MPK Ready. + g.s.PutDKGMPKReady(r, addr, true) + g.s.IncDKGMPKReadysCount(r) + if final { + // Prepare Finalized. + g.s.PutDKGFinalized(r, addr, true) + g.s.IncDKGFinalizedsCount(r) + } + } + dkgSetSize := len(dkgSet) + g.Require().Len(g.s.DKGMasterPublicKeys(r), dkgSetSize) + g.Require().Len(g.s.DKGComplaints(r), dkgSetSize) + g.Require().Equal(0, g.s.DKGMPKReadysCount(r).Cmp(big.NewInt(int64(dkgSetSize)))) + for _, addr := range addrs[round] { + g.Require().True(g.s.DKGMPKReady(r, addr)) + } + if final { + g.Require().Equal(0, g.s.DKGFinalizedsCount(r).Cmp(big.NewInt(int64(dkgSetSize)))) + for _, addr := range addrs[round] { + g.Require().True(g.s.DKGFinalized(r, addr)) + } + } + } + + // Fill data for previous rounds. + roundHeight := int64(g.config.RoundInterval / g.config.MinBlockInterval) + round := 3 + for i := 0; i <= round; i++ { + // Prepare CRS. + crs := common.BytesToHash(randomBytes(common.HashLength, common.HashLength)) + g.s.PushCRS(crs) + // Prepare Round Height + if i != 0 { + g.s.PushRoundHeight(big.NewInt(int64(i) * roundHeight)) + } + g.Require().Equal(0, g.s.LenCRS().Cmp(big.NewInt(int64(i+2)))) + g.Require().Equal(crs, g.s.CurrentCRS()) + } + for i := 0; i <= round; i++ { + addDKG(i, true) + } + + mock := &testCoreMock{ + tsigReturn: true, + } + OracleContracts[GovernanceContractAddress].(*GovernanceContract).coreDKGUtils = mock + repeat := 3 + for r := 0; r < repeat; r++ { + addDKG(round+1, false) + // Add one finalized for test. + roundPlusOne := big.NewInt(int64(round + 1)) + g.s.PutDKGFinalized(roundPlusOne, addrs[round+1][0], true) + g.s.IncDKGFinalizedsCount(roundPlusOne) + + g.context.BlockNumber = big.NewInt(roundHeight*int64(round) + roundHeight*int64(r) + roundHeight*80/100) + _, addr := g.newPrefundAccount() + newCRS := randomBytes(common.HashLength, common.HashLength) + input, err := GovernanceABI.ABI.Pack("resetDKG", newCRS) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + // Test if CRS is reset. + newCRSHash := crypto.Keccak256Hash(newCRS) + g.Require().Equal(0, g.s.LenCRS().Cmp(big.NewInt(int64(round+2)))) + g.Require().Equal(newCRSHash, g.s.CurrentCRS()) + g.Require().Equal(newCRSHash, g.s.CRS(big.NewInt(int64(round+1)))) + + // Test if MPK is purged. + g.Require().Len(g.s.DKGMasterPublicKeys(big.NewInt(int64(round+1))), 0) + // Test if MPKReady is purged. + g.Require().Equal(0, + g.s.DKGMPKReadysCount(big.NewInt(int64(round+1))).Cmp(big.NewInt(0))) + for _, addr := range addrs[round+1] { + g.Require().False(g.s.DKGMPKReady(big.NewInt(int64(round+1)), addr)) + } + // Test if Complaint is purged. + g.Require().Len(g.s.DKGComplaints(big.NewInt(int64(round+1))), 0) + // Test if Finalized is purged. + g.Require().Equal(0, + g.s.DKGFinalizedsCount(big.NewInt(int64(round+1))).Cmp(big.NewInt(0))) + for _, addr := range addrs[round+1] { + g.Require().False(g.s.DKGFinalized(big.NewInt(int64(round+1)), addr)) + } + + g.Require().Equal(0, + g.s.DKGResetCount(roundPlusOne).Cmp(big.NewInt(int64(r+1)))) + } +} + func TestGovernanceContract(t *testing.T) { - suite.Run(t, new(GovernanceContractTestSuite)) + suite.Run(t, new(OracleContractsTestSuite)) } |