From 156e8c3e6a06a7ba3fc35ac7dd1162493090ce29 Mon Sep 17 00:00:00 2001 From: Jhih-Ming Huang Date: Tue, 19 Feb 2019 11:26:49 +0800 Subject: core: rebase dev and fix lint --- consensus/dexcon/fake_dexcon.go | 4 +- core/chain_makers.go | 4 +- core/dexon_chain_makers.go | 4 +- core/vm/evm/governance.go | 2198 -------------------------- core/vm/evm/governance_abi.go | 1133 ------------- core/vm/evm/governance_test.go | 1061 ------------- core/vm/evm/oracle.go | 89 ++ core/vm/evm/oracle_contract_abi.go | 1221 ++++++++++++++ core/vm/evm/oracle_contracts.go | 2885 ++++++++++++++++++++++++++++++++++ core/vm/evm/oracle_contracts_test.go | 1203 ++++++++++++++ core/vm/oracle.go | 88 -- core/vm/oracle_contract_abi.go | 1221 -------------- core/vm/oracle_contracts.go | 2884 --------------------------------- core/vm/oracle_contracts_test.go | 1202 -------------- 14 files changed, 5404 insertions(+), 9793 deletions(-) delete mode 100644 core/vm/evm/governance.go delete mode 100644 core/vm/evm/governance_abi.go delete mode 100644 core/vm/evm/governance_test.go create mode 100644 core/vm/evm/oracle.go create mode 100644 core/vm/evm/oracle_contract_abi.go create mode 100644 core/vm/evm/oracle_contracts.go create mode 100644 core/vm/evm/oracle_contracts_test.go delete mode 100644 core/vm/oracle.go delete mode 100644 core/vm/oracle_contract_abi.go delete mode 100644 core/vm/oracle_contracts.go delete mode 100644 core/vm/oracle_contracts_test.go diff --git a/consensus/dexcon/fake_dexcon.go b/consensus/dexcon/fake_dexcon.go index 430d9bc6b..befda7514 100644 --- a/consensus/dexcon/fake_dexcon.go +++ b/consensus/dexcon/fake_dexcon.go @@ -16,7 +16,7 @@ import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/consensus" "github.com/dexon-foundation/dexon/core/types" - "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/rlp" ) @@ -140,7 +140,7 @@ func (n *Node) DKGFinalize(round uint64) *coreTypesDKG.Finalize { func (n *Node) CreateGovTx(nonce uint64, data []byte) *types.Transaction { tx, err := types.SignTx(types.NewTransaction( nonce, - vm.GovernanceContractAddress, + evm.GovernanceContractAddress, big.NewInt(0), uint64(2000000), big.NewInt(1e10), diff --git a/core/chain_makers.go b/core/chain_makers.go index f57eb37ff..50a537964 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -27,7 +27,7 @@ import ( "github.com/dexon-foundation/dexon/consensus/misc" "github.com/dexon-foundation/dexon/core/state" "github.com/dexon-foundation/dexon/core/types" - "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" ) @@ -103,7 +103,7 @@ func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) { b.SetCoinbase(common.Address{}) } b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs)) - receipt, _, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{}) + receipt, _, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, evm.Config{}) if err != nil { panic(err) } diff --git a/core/dexon_chain_makers.go b/core/dexon_chain_makers.go index 010b30c84..6901a8bc2 100644 --- a/core/dexon_chain_makers.go +++ b/core/dexon_chain_makers.go @@ -28,7 +28,7 @@ import ( "github.com/dexon-foundation/dexon/consensus" "github.com/dexon-foundation/dexon/core/state" "github.com/dexon-foundation/dexon/core/types" - "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" "github.com/dexon-foundation/dexon/rlp" @@ -110,7 +110,7 @@ func (b *DexonBlockGen) ProcessTransactions(c ChainContext) { for _, tx := range b.txs { b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs)) // TODO: fix the chain context parameter - receipt, _, err := ApplyTransaction(b.config, c, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{}) + receipt, _, err := ApplyTransaction(b.config, c, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, evm.Config{}) if err != nil { panic(err) } diff --git a/core/vm/evm/governance.go b/core/vm/evm/governance.go deleted file mode 100644 index 18e733342..000000000 --- a/core/vm/evm/governance.go +++ /dev/null @@ -1,2198 +0,0 @@ -// Copyright 2018 The dexon-consensus Authors -// This file is part of the dexon-consensus library. -// -// The dexon-consensus library is free software: you can redistribute it -// and/or modify it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of the License, -// or (at your option) any later version. -// -// The dexon-consensus library is distributed in the hope that it will be -// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the dexon-consensus library. If not, see -// . - -package evm - -import ( - "bytes" - "errors" - "math/big" - "sort" - "strings" - - "github.com/dexon-foundation/dexon/accounts/abi" - "github.com/dexon-foundation/dexon/common" - "github.com/dexon-foundation/dexon/core/types" - "github.com/dexon-foundation/dexon/crypto" - "github.com/dexon-foundation/dexon/params" - "github.com/dexon-foundation/dexon/rlp" - - coreCommon "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core" - coreCrypto "github.com/dexon-foundation/dexon-consensus/core/crypto" - coreUtils "github.com/dexon-foundation/dexon-consensus/core/utils" - "github.com/dexon-foundation/dexon/core/vm" - - "github.com/dexon-foundation/dexon-consensus/core/crypto/ecdsa" - coreTypes "github.com/dexon-foundation/dexon-consensus/core/types" - dkgTypes "github.com/dexon-foundation/dexon-consensus/core/types/dkg" -) - -var GovernanceContractAddress = common.HexToAddress("63751838d6485578b23e8b051d40861ecc416794") - -var abiObject abi.ABI -var GovernanceContractName2Method map[string]abi.Method -var sig2Method map[string]abi.Method -var events map[string]abi.Event - -type Bytes32 [32]byte - -type ReportType uint64 - -const ( - ReportTypeInvalidDKG = iota - ReportTypeForkVote - ReportTypeForkBlock -) - -func init() { - var err error - - // Parse governance contract ABI. - abiObject, err = abi.JSON(strings.NewReader(GovernanceABIJSON)) - if err != nil { - panic(err) - } - - sig2Method = make(map[string]abi.Method) - GovernanceContractName2Method = make(map[string]abi.Method) - - // Construct dispatch table. - for _, method := range abiObject.Methods { - sig2Method[string(method.Id())] = method - GovernanceContractName2Method[method.Name] = method - } - - events = make(map[string]abi.Event) - - // Event cache. - for _, event := range abiObject.Events { - events[event.Name] = event - } -} - -// RunGovernanceContract executes governance contract. -func RunGovernanceContract(evm *EVM, input []byte, contract *vm.Contract) (ret []byte, err error) { - if len(input) < 4 { - return nil, nil - } - - // Parse input. - method, exists := sig2Method[string(input[:4])] - if !exists { - return nil, errExecutionReverted - } - - // Dispatch method call. - g := newGovernanceContract(evm, contract) - arguments := input[4:] - - switch method.Name { - case "addDKGComplaint": - args := struct { - Round *big.Int - Complaint []byte - }{} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - return g.addDKGComplaint(args.Round, args.Complaint) - case "addDKGMasterPublicKey": - args := struct { - Round *big.Int - PublicKey []byte - }{} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - return g.addDKGMasterPublicKey(args.Round, args.PublicKey) - case "addDKGMPKReady": - args := struct { - Round *big.Int - MPKReady []byte - }{} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - return g.addDKGMPKReady(args.Round, args.MPKReady) - case "addDKGFinalize": - args := struct { - Round *big.Int - Finalize []byte - }{} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - return g.addDKGFinalize(args.Round, args.Finalize) - case "delegate": - address := common.Address{} - if err := method.Inputs.Unpack(&address, arguments); err != nil { - return nil, errExecutionReverted - } - return g.delegate(address) - case "delegatorsLength": - address := common.Address{} - if err := method.Inputs.Unpack(&address, arguments); err != nil { - return nil, errExecutionReverted - } - res, err := method.Outputs.Pack(g.state.LenDelegators(address)) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "nodesLength": - res, err := method.Outputs.Pack(g.state.LenNodes()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "payFine": - address := common.Address{} - if err := method.Inputs.Unpack(&address, arguments); err != nil { - return nil, errExecutionReverted - } - return g.payFine(address) - case "proposeCRS": - args := struct { - Round *big.Int - SignedCRS []byte - }{} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - return g.proposeCRS(args.Round, args.SignedCRS) - case "report": - args := struct { - Type *big.Int - Arg1 []byte - Arg2 []byte - }{} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - return g.report(args.Type, args.Arg1, args.Arg2) - case "stake": - args := struct { - PublicKey []byte - Name string - Email string - Location string - Url string - }{} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - return g.stake(args.PublicKey, args.Name, args.Email, args.Location, args.Url) - case "snapshotRound": - args := struct { - Round *big.Int - Height *big.Int - }{} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - return g.snapshotRound(args.Round, args.Height) - case "transferOwnership": - var newOwner common.Address - if err := method.Inputs.Unpack(&newOwner, arguments); err != nil { - return nil, errExecutionReverted - } - return g.transferOwnership(newOwner) - case "undelegate": - address := common.Address{} - if err := method.Inputs.Unpack(&address, arguments); err != nil { - return nil, errExecutionReverted - } - return g.undelegate(address) - case "unstake": - return g.unstake() - case "updateConfiguration": - var cfg rawConfigStruct - if err := method.Inputs.Unpack(&cfg, arguments); err != nil { - return nil, errExecutionReverted - } - return g.updateConfiguration(&cfg) - case "withdraw": - address := common.Address{} - if err := method.Inputs.Unpack(&address, arguments); err != nil { - return nil, errExecutionReverted - } - return g.withdraw(address) - - // -------------------------------- - // Solidity auto generated methods. - // -------------------------------- - - case "blockGasLimit": - res, err := method.Outputs.Pack(g.state.BlockGasLimit()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "crs": - round := new(big.Int) - if err := method.Inputs.Unpack(&round, arguments); err != nil { - return nil, errExecutionReverted - } - res, err := method.Outputs.Pack(g.state.CRS(round)) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "delegators": - nodeAddr, index := common.Address{}, new(big.Int) - args := []interface{}{&nodeAddr, &index} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - delegator := g.state.Delegator(nodeAddr, index) - res, err := method.Outputs.Pack(delegator.Owner, delegator.Value, delegator.UndelegatedAt) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "delegatorsOffset": - nodeAddr, delegatorAddr := common.Address{}, common.Address{} - args := []interface{}{&nodeAddr, &delegatorAddr} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - res, err := method.Outputs.Pack(g.state.DelegatorsOffset(nodeAddr, delegatorAddr)) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgComplaints": - round, index := new(big.Int), new(big.Int) - args := []interface{}{&round, &index} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - complaints := g.state.DKGComplaints(round) - if int(index.Uint64()) >= len(complaints) { - return nil, errExecutionReverted - } - complaint := complaints[index.Uint64()] - res, err := method.Outputs.Pack(complaint) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgReadys": - round, addr := new(big.Int), common.Address{} - args := []interface{}{&round, &addr} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - ready := g.state.DKGMPKReady(round, addr) - res, err := method.Outputs.Pack(ready) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgReadysCount": - round := new(big.Int) - if err := method.Inputs.Unpack(&round, arguments); err != nil { - return nil, errExecutionReverted - } - count := g.state.DKGMPKReadysCount(round) - res, err := method.Outputs.Pack(count) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - - case "dkgFinalizeds": - round, addr := new(big.Int), common.Address{} - args := []interface{}{&round, &addr} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - finalized := g.state.DKGFinalized(round, addr) - res, err := method.Outputs.Pack(finalized) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgFinalizedsCount": - round := new(big.Int) - if err := method.Inputs.Unpack(&round, arguments); err != nil { - return nil, errExecutionReverted - } - count := g.state.DKGFinalizedsCount(round) - res, err := method.Outputs.Pack(count) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgMasterPublicKeys": - round, index := new(big.Int), new(big.Int) - args := []interface{}{&round, &index} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - mpks := g.state.DKGMasterPublicKeys(round) - if int(index.Uint64()) >= len(mpks) { - return nil, errExecutionReverted - } - mpk := mpks[index.Uint64()] - res, err := method.Outputs.Pack(mpk) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgSetSize": - res, err := method.Outputs.Pack(g.state.DKGSetSize()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "finedRecords": - record := Bytes32{} - if err := method.Inputs.Unpack(&record, arguments); err != nil { - return nil, errExecutionReverted - } - value := g.state.FineRecords(record) - res, err := method.Outputs.Pack(value) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "fineValues": - index := new(big.Int) - if err := method.Inputs.Unpack(&index, arguments); err != nil { - return nil, errExecutionReverted - } - value := g.state.FineValue(index) - res, err := method.Outputs.Pack(value) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "k": - res, err := method.Outputs.Pack(g.state.K()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "lambdaBA": - res, err := method.Outputs.Pack(g.state.LambdaBA()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "lambdaDKG": - res, err := method.Outputs.Pack(g.state.LambdaDKG()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "lastHalvedAmount": - res, err := method.Outputs.Pack(g.state.LastHalvedAmount()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "lockupPeriod": - res, err := method.Outputs.Pack(g.state.LockupPeriod()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "minBlockInterval": - res, err := method.Outputs.Pack(g.state.MinBlockInterval()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "miningVelocity": - res, err := method.Outputs.Pack(g.state.MiningVelocity()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "minStake": - res, err := method.Outputs.Pack(g.state.MinStake()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "nextHalvingSupply": - res, err := method.Outputs.Pack(g.state.NextHalvingSupply()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "numChains": - res, err := method.Outputs.Pack(g.state.NumChains()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "nodes": - index := new(big.Int) - if err := method.Inputs.Unpack(&index, arguments); err != nil { - return nil, errExecutionReverted - } - info := g.state.Node(index) - res, err := method.Outputs.Pack( - info.Owner, info.PublicKey, info.Staked, info.Fined, - info.Name, info.Email, info.Location, info.Url) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "nodesOffsetByAddress": - address := common.Address{} - if err := method.Inputs.Unpack(&address, arguments); err != nil { - return nil, errExecutionReverted - } - res, err := method.Outputs.Pack(g.state.NodesOffsetByAddress(address)) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "nodesOffsetByID": - var id Bytes32 - if err := method.Inputs.Unpack(&id, arguments); err != nil { - return nil, errExecutionReverted - } - res, err := method.Outputs.Pack(g.state.NodesOffsetByID(id)) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "notarySetSize": - res, err := method.Outputs.Pack(g.state.NotarySetSize()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "owner": - res, err := method.Outputs.Pack(g.state.Owner()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "phiRatio": - res, err := method.Outputs.Pack(g.state.PhiRatio()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "roundHeight": - round := new(big.Int) - if err := method.Inputs.Unpack(&round, arguments); err != nil { - return nil, errExecutionReverted - } - res, err := method.Outputs.Pack(g.state.RoundHeight(round)) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "roundInterval": - res, err := method.Outputs.Pack(g.state.RoundInterval()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "totalStaked": - res, err := method.Outputs.Pack(g.state.TotalStaked()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "totalSupply": - res, err := method.Outputs.Pack(g.state.TotalSupply()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - } - return nil, errExecutionReverted -} - -// Storage position enums. -const ( - roundHeightLoc = iota - totalSupplyLoc - totalStakedLoc - nodesLoc - nodesOffsetByAddressLoc - nodesOffsetByIDLoc - delegatorsLoc - delegatorsOffsetLoc - crsLoc - dkgMasterPublicKeysLoc - dkgComplaintsLoc - dkgReadyLoc - dkgReadysCountLoc - dkgFinalizedLoc - dkgFinalizedsCountLoc - ownerLoc - minStakeLoc - lockupPeriodLoc - miningVelocityLoc - nextHalvingSupplyLoc - lastHalvedAmountLoc - blockGasLimitLoc - numChainsLoc - lambdaBALoc - lambdaDKGLoc - kLoc - phiRatioLoc - notarySetSizeLoc - dkgSetSizeLoc - roundIntervalLoc - minBlockIntervalLoc - fineValuesLoc - finedRecordsLoc -) - -func publicKeyToNodeID(pkBytes []byte) (Bytes32, error) { - pk, err := crypto.UnmarshalPubkey(pkBytes) - if err != nil { - return Bytes32{}, err - } - id := Bytes32(coreTypes.NewNodeID(ecdsa.NewPublicKeyFromECDSA(pk)).Hash) - return id, nil -} - -// State manipulation helper fro the governance contract. -type GovernanceStateHelper struct { - StateDB vm.StateDB -} - -func (s *GovernanceStateHelper) getState(loc common.Hash) common.Hash { - return s.StateDB.GetState(GovernanceContractAddress, loc) -} - -func (s *GovernanceStateHelper) setState(loc common.Hash, val common.Hash) { - s.StateDB.SetState(GovernanceContractAddress, loc, val) -} - -func (s *GovernanceStateHelper) getStateBigInt(loc *big.Int) *big.Int { - res := s.StateDB.GetState(GovernanceContractAddress, common.BigToHash(loc)) - return new(big.Int).SetBytes(res.Bytes()) -} - -func (s *GovernanceStateHelper) setStateBigInt(loc *big.Int, val *big.Int) { - s.setState(common.BigToHash(loc), common.BigToHash(val)) -} - -func (s *GovernanceStateHelper) getSlotLoc(loc *big.Int) *big.Int { - return new(big.Int).SetBytes(crypto.Keccak256(common.BigToHash(loc).Bytes())) -} - -func (s *GovernanceStateHelper) getMapLoc(pos *big.Int, key []byte) *big.Int { - return new(big.Int).SetBytes(crypto.Keccak256(key, common.BigToHash(pos).Bytes())) -} - -func (s *GovernanceStateHelper) readBytes(loc *big.Int) []byte { - // Length of the dynamic array (bytes). - rawLength := s.getStateBigInt(loc) - lengthByte := new(big.Int).Mod(rawLength, big.NewInt(256)) - - // Bytes length <= 31, lengthByte % 2 == 0 - // return the high 31 bytes. - if new(big.Int).Mod(lengthByte, big.NewInt(2)).Cmp(big.NewInt(0)) == 0 { - length := new(big.Int).Div(lengthByte, big.NewInt(2)).Uint64() - return rawLength.Bytes()[:length] - } - - // Actual length = (rawLength - 1) / 2 - length := new(big.Int).Div(new(big.Int).Sub(rawLength, big.NewInt(1)), big.NewInt(2)).Uint64() - - // Data address. - dataLoc := s.getSlotLoc(loc) - - // Read continuously for length bytes. - carry := int64(0) - if length%32 > 0 { - carry = 1 - } - chunks := int64(length/32) + carry - var data []byte - for i := int64(0); i < chunks; i++ { - loc = new(big.Int).Add(dataLoc, big.NewInt(i)) - data = append(data, s.getState(common.BigToHash(loc)).Bytes()...) - } - data = data[:length] - return data -} - -func (s *GovernanceStateHelper) writeBytes(loc *big.Int, data []byte) { - length := int64(len(data)) - - if length == 0 { - s.setState(common.BigToHash(loc), common.Hash{}) - return - } - - // Short bytes (length <= 31). - if length < 32 { - data2 := append([]byte(nil), data...) - // Right pad with zeros - for len(data2) < 31 { - data2 = append(data2, byte(0)) - } - data2 = append(data2, byte(length*2)) - s.setState(common.BigToHash(loc), common.BytesToHash(data2)) - return - } - - // Write 2 * length + 1. - storedLength := new(big.Int).Add(new(big.Int).Mul( - big.NewInt(length), big.NewInt(2)), big.NewInt(1)) - s.setStateBigInt(loc, storedLength) - // Write data chunck. - dataLoc := s.getSlotLoc(loc) - carry := int64(0) - if length%32 > 0 { - carry = 1 - } - chunks := length/32 + carry - for i := int64(0); i < chunks; i++ { - loc = new(big.Int).Add(dataLoc, big.NewInt(i)) - maxLoc := (i + 1) * 32 - if maxLoc > length { - maxLoc = length - } - data2 := data[i*32 : maxLoc] - // Right pad with zeros. - for len(data2) < 32 { - data2 = append(data2, byte(0)) - } - s.setState(common.BigToHash(loc), common.BytesToHash(data2)) - } -} - -func (s *GovernanceStateHelper) read2DByteArray(pos, index *big.Int) [][]byte { - baseLoc := s.getSlotLoc(pos) - loc := new(big.Int).Add(baseLoc, index) - - arrayLength := s.getStateBigInt(loc) - dataLoc := s.getSlotLoc(loc) - - data := [][]byte{} - for i := int64(0); i < int64(arrayLength.Uint64()); i++ { - elementLoc := new(big.Int).Add(dataLoc, big.NewInt(i)) - data = append(data, s.readBytes(elementLoc)) - } - - return data -} -func (s *GovernanceStateHelper) appendTo2DByteArray(pos, index *big.Int, data []byte) { - // Find the loc of the last element. - baseLoc := s.getSlotLoc(pos) - loc := new(big.Int).Add(baseLoc, index) - - // Increase length by 1. - arrayLength := s.getStateBigInt(loc) - s.setStateBigInt(loc, new(big.Int).Add(arrayLength, big.NewInt(1))) - - // Write element. - dataLoc := s.getSlotLoc(loc) - elementLoc := new(big.Int).Add(dataLoc, arrayLength) - s.writeBytes(elementLoc, data) -} - -// uint256[] public roundHeight; -func (s *GovernanceStateHelper) LenRoundHeight() *big.Int { - return s.getStateBigInt(big.NewInt(roundHeightLoc)) -} -func (s *GovernanceStateHelper) RoundHeight(round *big.Int) *big.Int { - baseLoc := s.getSlotLoc(big.NewInt(roundHeightLoc)) - loc := new(big.Int).Add(baseLoc, round) - return s.getStateBigInt(loc) -} -func (s *GovernanceStateHelper) PushRoundHeight(height *big.Int) { - // Increase length by 1. - length := s.getStateBigInt(big.NewInt(roundHeightLoc)) - s.setStateBigInt(big.NewInt(roundHeightLoc), new(big.Int).Add(length, big.NewInt(1))) - - baseLoc := s.getSlotLoc(big.NewInt(roundHeightLoc)) - loc := new(big.Int).Add(baseLoc, length) - - s.setStateBigInt(loc, height) -} - -// uint256 public totalSupply; -func (s *GovernanceStateHelper) TotalSupply() *big.Int { - return s.getStateBigInt(big.NewInt(totalSupplyLoc)) -} -func (s *GovernanceStateHelper) IncTotalSupply(amount *big.Int) { - s.setStateBigInt(big.NewInt(totalSupplyLoc), new(big.Int).Add(s.TotalSupply(), amount)) -} -func (s *GovernanceStateHelper) DecTotalSupply(amount *big.Int) { - s.setStateBigInt(big.NewInt(totalSupplyLoc), new(big.Int).Sub(s.TotalSupply(), amount)) -} - -// uint256 public totalStaked; -func (s *GovernanceStateHelper) TotalStaked() *big.Int { - return s.getStateBigInt(big.NewInt(totalStakedLoc)) -} -func (s *GovernanceStateHelper) IncTotalStaked(amount *big.Int) { - s.setStateBigInt(big.NewInt(totalStakedLoc), new(big.Int).Add(s.TotalStaked(), amount)) -} -func (s *GovernanceStateHelper) DecTotalStaked(amount *big.Int) { - s.setStateBigInt(big.NewInt(totalStakedLoc), new(big.Int).Sub(s.TotalStaked(), amount)) -} - -// struct Node { -// address owner; -// bytes publicKey; -// uint256 staked; -// uint256 fined; -// string name; -// string email; -// string location; -// string url; -// } -// -// Node[] nodes; - -type nodeInfo struct { - Owner common.Address - PublicKey []byte - Staked *big.Int - Fined *big.Int - Name string - Email string - Location string - Url string -} - -const nodeStructSize = 8 - -func (s *GovernanceStateHelper) LenNodes() *big.Int { - return s.getStateBigInt(big.NewInt(nodesLoc)) -} -func (s *GovernanceStateHelper) Node(index *big.Int) *nodeInfo { - node := new(nodeInfo) - - arrayBaseLoc := s.getSlotLoc(big.NewInt(nodesLoc)) - elementBaseLoc := new(big.Int).Add(arrayBaseLoc, - new(big.Int).Mul(index, big.NewInt(nodeStructSize))) - - // Owner. - loc := elementBaseLoc - node.Owner = common.BytesToAddress(s.getState(common.BigToHash(elementBaseLoc)).Bytes()) - - // PublicKey. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(1)) - node.PublicKey = s.readBytes(loc) - - // Staked. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(2)) - node.Staked = s.getStateBigInt(loc) - - // Fined. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(3)) - node.Fined = s.getStateBigInt(loc) - - // Name. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(4)) - node.Name = string(s.readBytes(loc)) - - // Email. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(5)) - node.Email = string(s.readBytes(loc)) - - // Location. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(6)) - node.Location = string(s.readBytes(loc)) - - // Url. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(7)) - node.Url = string(s.readBytes(loc)) - - return node -} -func (s *GovernanceStateHelper) PushNode(n *nodeInfo) { - // Increase length by 1. - arrayLength := s.LenNodes() - s.setStateBigInt(big.NewInt(nodesLoc), new(big.Int).Add(arrayLength, big.NewInt(1))) - - s.UpdateNode(arrayLength, n) -} -func (s *GovernanceStateHelper) UpdateNode(index *big.Int, n *nodeInfo) { - arrayBaseLoc := s.getSlotLoc(big.NewInt(nodesLoc)) - elementBaseLoc := new(big.Int).Add(arrayBaseLoc, - new(big.Int).Mul(index, big.NewInt(nodeStructSize))) - - // Owner. - loc := elementBaseLoc - s.setState(common.BigToHash(loc), n.Owner.Hash()) - - // PublicKey. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(1)) - s.writeBytes(loc, n.PublicKey) - - // Staked. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(2)) - s.setStateBigInt(loc, n.Staked) - - // Fined. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(3)) - s.setStateBigInt(loc, n.Fined) - - // Name. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(4)) - s.writeBytes(loc, []byte(n.Name)) - - // Email. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(5)) - s.writeBytes(loc, []byte(n.Email)) - - // Location. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(6)) - s.writeBytes(loc, []byte(n.Location)) - - // Url. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(7)) - s.writeBytes(loc, []byte(n.Url)) -} -func (s *GovernanceStateHelper) PopLastNode() { - // Decrease length by 1. - arrayLength := s.LenNodes() - newArrayLength := new(big.Int).Sub(arrayLength, big.NewInt(1)) - s.setStateBigInt(big.NewInt(nodesLoc), newArrayLength) - - s.UpdateNode(newArrayLength, &nodeInfo{ - Staked: big.NewInt(0), - Fined: big.NewInt(0), - }) -} -func (s *GovernanceStateHelper) Nodes() []*nodeInfo { - var nodes []*nodeInfo - for i := int64(0); i < int64(s.LenNodes().Uint64()); i++ { - nodes = append(nodes, s.Node(big.NewInt(i))) - } - return nodes -} -func (s *GovernanceStateHelper) QualifiedNodes() []*nodeInfo { - var nodes []*nodeInfo - for i := int64(0); i < int64(s.LenNodes().Uint64()); i++ { - node := s.Node(big.NewInt(i)) - if new(big.Int).Sub(node.Staked, node.Fined).Cmp(s.MinStake()) >= 0 { - nodes = append(nodes, node) - } - } - return nodes -} - -// mapping(address => uint256) public nodeOffsetByAddress; -func (s *GovernanceStateHelper) NodesOffsetByAddress(addr common.Address) *big.Int { - loc := s.getMapLoc(big.NewInt(nodesOffsetByAddressLoc), addr.Bytes()) - return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1)) -} -func (s *GovernanceStateHelper) PutNodesOffsetByAddress(addr common.Address, offset *big.Int) { - loc := s.getMapLoc(big.NewInt(nodesOffsetByAddressLoc), addr.Bytes()) - s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1))) -} -func (s *GovernanceStateHelper) DeleteNodesOffsetByAddress(addr common.Address) { - loc := s.getMapLoc(big.NewInt(nodesOffsetByAddressLoc), addr.Bytes()) - s.setStateBigInt(loc, big.NewInt(0)) -} - -// mapping(address => uint256) public nodeOffsetByID; -func (s *GovernanceStateHelper) NodesOffsetByID(id Bytes32) *big.Int { - loc := s.getMapLoc(big.NewInt(nodesOffsetByIDLoc), id[:]) - return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1)) -} -func (s *GovernanceStateHelper) PutNodesOffsetByID(id Bytes32, offset *big.Int) { - loc := s.getMapLoc(big.NewInt(nodesOffsetByIDLoc), id[:]) - s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1))) -} -func (s *GovernanceStateHelper) DeleteNodesOffsetByID(id Bytes32) { - loc := s.getMapLoc(big.NewInt(nodesOffsetByIDLoc), id[:]) - s.setStateBigInt(loc, big.NewInt(0)) -} - -func (s *GovernanceStateHelper) PutNodeOffsets(n *nodeInfo, offset *big.Int) error { - id, err := publicKeyToNodeID(n.PublicKey) - if err != nil { - return err - } - s.PutNodesOffsetByID(id, offset) - s.PutNodesOffsetByAddress(n.Owner, offset) - return nil -} - -// struct Delegator { -// address node; -// address owner; -// uint256 value; -// uint256 undelegated_at; -// } - -type delegatorInfo struct { - Owner common.Address - Value *big.Int - UndelegatedAt *big.Int -} - -const delegatorStructSize = 3 - -// mapping(address => Delegator[]) public delegators; -func (s *GovernanceStateHelper) LenDelegators(nodeAddr common.Address) *big.Int { - loc := s.getMapLoc(big.NewInt(delegatorsLoc), nodeAddr.Bytes()) - return s.getStateBigInt(loc) -} -func (s *GovernanceStateHelper) Delegator(nodeAddr common.Address, offset *big.Int) *delegatorInfo { - delegator := new(delegatorInfo) - - loc := s.getMapLoc(big.NewInt(delegatorsLoc), nodeAddr.Bytes()) - arrayBaseLoc := s.getSlotLoc(loc) - elementBaseLoc := new(big.Int).Add(arrayBaseLoc, new(big.Int).Mul(big.NewInt(delegatorStructSize), offset)) - - // Owner. - loc = elementBaseLoc - delegator.Owner = common.BytesToAddress(s.getState(common.BigToHash(elementBaseLoc)).Bytes()) - - // Value. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(1)) - delegator.Value = s.getStateBigInt(loc) - - // UndelegatedAt. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(2)) - delegator.UndelegatedAt = s.getStateBigInt(loc) - - return delegator -} -func (s *GovernanceStateHelper) PushDelegator(nodeAddr common.Address, delegator *delegatorInfo) { - // Increase length by 1. - arrayLength := s.LenDelegators(nodeAddr) - loc := s.getMapLoc(big.NewInt(delegatorsLoc), nodeAddr.Bytes()) - s.setStateBigInt(loc, new(big.Int).Add(arrayLength, big.NewInt(1))) - - s.UpdateDelegator(nodeAddr, arrayLength, delegator) -} -func (s *GovernanceStateHelper) UpdateDelegator(nodeAddr common.Address, offset *big.Int, delegator *delegatorInfo) { - loc := s.getMapLoc(big.NewInt(delegatorsLoc), nodeAddr.Bytes()) - arrayBaseLoc := s.getSlotLoc(loc) - elementBaseLoc := new(big.Int).Add(arrayBaseLoc, new(big.Int).Mul(big.NewInt(delegatorStructSize), offset)) - - // Owner. - loc = elementBaseLoc - s.setState(common.BigToHash(loc), delegator.Owner.Hash()) - - // Value. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(1)) - s.setStateBigInt(loc, delegator.Value) - - // UndelegatedAt. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(2)) - s.setStateBigInt(loc, delegator.UndelegatedAt) -} -func (s *GovernanceStateHelper) PopLastDelegator(nodeAddr common.Address) { - // Decrease length by 1. - arrayLength := s.LenDelegators(nodeAddr) - newArrayLength := new(big.Int).Sub(arrayLength, big.NewInt(1)) - loc := s.getMapLoc(big.NewInt(delegatorsLoc), nodeAddr.Bytes()) - s.setStateBigInt(loc, newArrayLength) - - s.UpdateDelegator(nodeAddr, newArrayLength, &delegatorInfo{ - Value: big.NewInt(0), - UndelegatedAt: big.NewInt(0), - }) -} - -// mapping(address => mapping(address => uint256)) delegatorsOffset; -func (s *GovernanceStateHelper) DelegatorsOffset(nodeAddr, delegatorAddr common.Address) *big.Int { - loc := s.getMapLoc(s.getMapLoc(big.NewInt(delegatorsOffsetLoc), nodeAddr.Bytes()), delegatorAddr.Bytes()) - return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1)) -} -func (s *GovernanceStateHelper) PutDelegatorOffset(nodeAddr, delegatorAddr common.Address, offset *big.Int) { - loc := s.getMapLoc(s.getMapLoc(big.NewInt(delegatorsOffsetLoc), nodeAddr.Bytes()), delegatorAddr.Bytes()) - s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1))) -} -func (s *GovernanceStateHelper) DeleteDelegatorsOffset(nodeAddr, delegatorAddr common.Address) { - loc := s.getMapLoc(s.getMapLoc(big.NewInt(delegatorsOffsetLoc), nodeAddr.Bytes()), delegatorAddr.Bytes()) - s.setStateBigInt(loc, big.NewInt(0)) -} - -// bytes32[] public crs; -func (s *GovernanceStateHelper) LenCRS() *big.Int { - return s.getStateBigInt(big.NewInt(crsLoc)) -} -func (s *GovernanceStateHelper) CRS(index *big.Int) common.Hash { - baseLoc := s.getSlotLoc(big.NewInt(crsLoc)) - loc := new(big.Int).Add(baseLoc, index) - return s.getState(common.BigToHash(loc)) -} -func (s *GovernanceStateHelper) CurrentCRS() common.Hash { - return s.CRS(new(big.Int).Sub(s.LenCRS(), big.NewInt(1))) -} -func (s *GovernanceStateHelper) PushCRS(crs common.Hash) { - // increase length by 1. - length := s.getStateBigInt(big.NewInt(crsLoc)) - s.setStateBigInt(big.NewInt(crsLoc), new(big.Int).Add(length, big.NewInt(1))) - - baseLoc := s.getSlotLoc(big.NewInt(crsLoc)) - loc := new(big.Int).Add(baseLoc, length) - - s.setState(common.BigToHash(loc), crs) -} -func (s *GovernanceStateHelper) Round() *big.Int { - return new(big.Int).Sub(s.getStateBigInt(big.NewInt(crsLoc)), big.NewInt(1)) -} - -// bytes[][] public dkgMasterPublicKeys; -func (s *GovernanceStateHelper) DKGMasterPublicKeys(round *big.Int) [][]byte { - return s.read2DByteArray(big.NewInt(dkgMasterPublicKeysLoc), round) -} -func (s *GovernanceStateHelper) PushDKGMasterPublicKey(round *big.Int, mpk []byte) { - s.appendTo2DByteArray(big.NewInt(dkgMasterPublicKeysLoc), round, mpk) -} -func (s *GovernanceStateHelper) UniqueDKGMasterPublicKeys(round *big.Int) []*dkgTypes.MasterPublicKey { - // Prepare DKGMasterPublicKeys. - var dkgMasterPKs []*dkgTypes.MasterPublicKey - existence := make(map[coreTypes.NodeID]struct{}) - for _, mpk := range s.DKGMasterPublicKeys(round) { - x := new(dkgTypes.MasterPublicKey) - if err := rlp.DecodeBytes(mpk, x); err != nil { - panic(err) - } - - // Only the first DKG MPK submission is valid. - if _, exists := existence[x.ProposerID]; exists { - continue - } - existence[x.ProposerID] = struct{}{} - dkgMasterPKs = append(dkgMasterPKs, x) - } - return dkgMasterPKs -} -func (s *GovernanceStateHelper) GetDKGMasterPublicKeyByProposerID( - round *big.Int, proposerID coreTypes.NodeID) (*dkgTypes.MasterPublicKey, error) { - - for _, mpk := range s.DKGMasterPublicKeys(round) { - x := new(dkgTypes.MasterPublicKey) - if err := rlp.DecodeBytes(mpk, x); err != nil { - panic(err) - } - if x.ProposerID.Equal(proposerID) { - return x, nil - } - } - return nil, errors.New("not found") -} - -// bytes[][] public dkgComplaints; -func (s *GovernanceStateHelper) DKGComplaints(round *big.Int) [][]byte { - return s.read2DByteArray(big.NewInt(dkgComplaintsLoc), round) -} -func (s *GovernanceStateHelper) PushDKGComplaint(round *big.Int, complaint []byte) { - s.appendTo2DByteArray(big.NewInt(dkgComplaintsLoc), round, complaint) -} - -// mapping(address => bool)[] public dkgReady; -func (s *GovernanceStateHelper) DKGMPKReady(round *big.Int, addr common.Address) bool { - baseLoc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgReadyLoc)), round) - mapLoc := s.getMapLoc(baseLoc, addr.Bytes()) - return s.getStateBigInt(mapLoc).Cmp(big.NewInt(0)) != 0 -} -func (s *GovernanceStateHelper) PutDKGMPKReady(round *big.Int, addr common.Address, ready bool) { - baseLoc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgReadyLoc)), round) - mapLoc := s.getMapLoc(baseLoc, addr.Bytes()) - res := big.NewInt(0) - if ready { - res = big.NewInt(1) - } - s.setStateBigInt(mapLoc, res) -} - -// uint256[] public dkgReadysCount; -func (s *GovernanceStateHelper) DKGMPKReadysCount(round *big.Int) *big.Int { - loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgReadysCountLoc)), round) - return s.getStateBigInt(loc) -} -func (s *GovernanceStateHelper) IncDKGMPKReadysCount(round *big.Int) { - loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgReadysCountLoc)), round) - count := s.getStateBigInt(loc) - s.setStateBigInt(loc, new(big.Int).Add(count, big.NewInt(1))) -} - -// mapping(address => bool)[] public dkgFinalized; -func (s *GovernanceStateHelper) DKGFinalized(round *big.Int, addr common.Address) bool { - baseLoc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgFinalizedLoc)), round) - mapLoc := s.getMapLoc(baseLoc, addr.Bytes()) - return s.getStateBigInt(mapLoc).Cmp(big.NewInt(0)) != 0 -} -func (s *GovernanceStateHelper) PutDKGFinalized(round *big.Int, addr common.Address, finalized bool) { - baseLoc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgFinalizedLoc)), round) - mapLoc := s.getMapLoc(baseLoc, addr.Bytes()) - res := big.NewInt(0) - if finalized { - res = big.NewInt(1) - } - s.setStateBigInt(mapLoc, res) -} - -// uint256[] public dkgFinalizedsCount; -func (s *GovernanceStateHelper) DKGFinalizedsCount(round *big.Int) *big.Int { - loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgFinalizedsCountLoc)), round) - return s.getStateBigInt(loc) -} -func (s *GovernanceStateHelper) IncDKGFinalizedsCount(round *big.Int) { - loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgFinalizedsCountLoc)), round) - count := s.getStateBigInt(loc) - s.setStateBigInt(loc, new(big.Int).Add(count, big.NewInt(1))) -} - -// address public owner; -func (s *GovernanceStateHelper) Owner() common.Address { - val := s.getState(common.BigToHash(big.NewInt(ownerLoc))) - return common.BytesToAddress(val.Bytes()) -} -func (s *GovernanceStateHelper) SetOwner(newOwner common.Address) { - s.setState(common.BigToHash(big.NewInt(ownerLoc)), newOwner.Hash()) -} - -// uint256 public minStake; -func (s *GovernanceStateHelper) MinStake() *big.Int { - return s.getStateBigInt(big.NewInt(minStakeLoc)) -} - -// uint256 public lockupPeriod; -func (s *GovernanceStateHelper) LockupPeriod() *big.Int { - return s.getStateBigInt(big.NewInt(lockupPeriodLoc)) -} - -// uint256 public miningVelocity; -func (s *GovernanceStateHelper) MiningVelocity() *big.Int { - return s.getStateBigInt(big.NewInt(miningVelocityLoc)) -} -func (s *GovernanceStateHelper) HalfMiningVelocity() { - s.setStateBigInt(big.NewInt(miningVelocityLoc), - new(big.Int).Div(s.MiningVelocity(), big.NewInt(2))) -} - -// uint256 public nextHalvingSupply; -func (s *GovernanceStateHelper) NextHalvingSupply() *big.Int { - return s.getStateBigInt(big.NewInt(nextHalvingSupplyLoc)) -} -func (s *GovernanceStateHelper) IncNextHalvingSupply(amount *big.Int) { - s.setStateBigInt(big.NewInt(nextHalvingSupplyLoc), - new(big.Int).Add(s.NextHalvingSupply(), amount)) -} - -// uint256 public lastHalvedAmount; -func (s *GovernanceStateHelper) LastHalvedAmount() *big.Int { - return s.getStateBigInt(big.NewInt(lastHalvedAmountLoc)) -} -func (s *GovernanceStateHelper) HalfLastHalvedAmount() { - s.setStateBigInt(big.NewInt(lastHalvedAmountLoc), - new(big.Int).Div(s.LastHalvedAmount(), big.NewInt(2))) -} - -func (s *GovernanceStateHelper) MiningHalved() { - s.HalfMiningVelocity() - s.HalfLastHalvedAmount() - s.IncNextHalvingSupply(s.LastHalvedAmount()) -} - -// uint256 public blockGasLimit; -func (s *GovernanceStateHelper) BlockGasLimit() *big.Int { - return s.getStateBigInt(big.NewInt(blockGasLimitLoc)) -} -func (s *GovernanceStateHelper) SetBlockGasLimit(reward *big.Int) { - s.setStateBigInt(big.NewInt(blockGasLimitLoc), reward) -} - -// uint256 public numChains; -func (s *GovernanceStateHelper) NumChains() *big.Int { - return s.getStateBigInt(big.NewInt(numChainsLoc)) -} - -// uint256 public lambdaBA; -func (s *GovernanceStateHelper) LambdaBA() *big.Int { - return s.getStateBigInt(big.NewInt(lambdaBALoc)) -} - -// uint256 public lambdaDKG; -func (s *GovernanceStateHelper) LambdaDKG() *big.Int { - return s.getStateBigInt(big.NewInt(lambdaDKGLoc)) -} - -// uint256 public k; -func (s *GovernanceStateHelper) K() *big.Int { - return s.getStateBigInt(big.NewInt(kLoc)) -} - -// uint256 public phiRatio; // stored as PhiRatio * 10^6 -func (s *GovernanceStateHelper) PhiRatio() *big.Int { - return s.getStateBigInt(big.NewInt(phiRatioLoc)) -} - -// uint256 public notarySetSize; -func (s *GovernanceStateHelper) NotarySetSize() *big.Int { - return s.getStateBigInt(big.NewInt(notarySetSizeLoc)) -} - -// uint256 public dkgSetSize; -func (s *GovernanceStateHelper) DKGSetSize() *big.Int { - return s.getStateBigInt(big.NewInt(dkgSetSizeLoc)) -} - -// uint256 public roundInterval; -func (s *GovernanceStateHelper) RoundInterval() *big.Int { - return s.getStateBigInt(big.NewInt(roundIntervalLoc)) -} - -// uint256 public minBlockInterval; -func (s *GovernanceStateHelper) MinBlockInterval() *big.Int { - return s.getStateBigInt(big.NewInt(minBlockIntervalLoc)) -} - -// uint256[] public fineValues; -func (s *GovernanceStateHelper) FineValue(index *big.Int) *big.Int { - arrayBaseLoc := s.getSlotLoc(big.NewInt(fineValuesLoc)) - return s.getStateBigInt(new(big.Int).Add(arrayBaseLoc, index)) -} -func (s *GovernanceStateHelper) FineValues() []*big.Int { - len := s.getStateBigInt(big.NewInt(fineValuesLoc)) - result := make([]*big.Int, len.Uint64()) - for i := 0; i < int(len.Uint64()); i++ { - result[i] = s.FineValue(big.NewInt(int64(i))) - } - return result -} -func (s *GovernanceStateHelper) SetFineValues(values []*big.Int) { - s.setStateBigInt(big.NewInt(fineValuesLoc), big.NewInt(int64(len(values)))) - - arrayBaseLoc := s.getSlotLoc(big.NewInt(fineValuesLoc)) - for i, v := range values { - s.setStateBigInt(new(big.Int).Add(arrayBaseLoc, big.NewInt(int64(i))), v) - } -} - -// uint256[] public fineRdecords; -func (s *GovernanceStateHelper) FineRecords(recordHash Bytes32) bool { - loc := s.getMapLoc(big.NewInt(finedRecordsLoc), recordHash[:]) - return s.getStateBigInt(loc).Cmp(big.NewInt(0)) > 0 -} -func (s *GovernanceStateHelper) SetFineRecords(recordHash Bytes32, status bool) { - loc := s.getMapLoc(big.NewInt(finedRecordsLoc), recordHash[:]) - value := int64(0) - if status { - value = int64(1) - } - s.setStateBigInt(loc, big.NewInt(value)) -} - -// Stake is a helper function for creating genesis state. -func (s *GovernanceStateHelper) Stake( - addr common.Address, publicKey []byte, staked *big.Int, - name, email, location, url string) { - offset := s.LenNodes() - node := &nodeInfo{ - Owner: addr, - PublicKey: publicKey, - Staked: staked, - Fined: big.NewInt(0), - Name: name, - Email: email, - Location: location, - Url: url, - } - s.PushNode(node) - if err := s.PutNodeOffsets(node, offset); err != nil { - panic(err) - } - - if staked.Cmp(big.NewInt(0)) == 0 { - return - } - - offset = s.LenDelegators(addr) - s.PushDelegator(addr, &delegatorInfo{ - Owner: addr, - Value: staked, - UndelegatedAt: big.NewInt(0), - }) - s.PutDelegatorOffset(addr, addr, offset) - - // Add to network total staked. - s.IncTotalStaked(staked) -} - -const decimalMultiplier = 100000000.0 - -// Configuration returns the current configuration. -func (s *GovernanceStateHelper) Configuration() *params.DexconConfig { - return ¶ms.DexconConfig{ - MinStake: s.getStateBigInt(big.NewInt(minStakeLoc)), - LockupPeriod: s.getStateBigInt(big.NewInt(lockupPeriodLoc)).Uint64(), - MiningVelocity: float32(s.getStateBigInt(big.NewInt(miningVelocityLoc)).Uint64()) / decimalMultiplier, - NextHalvingSupply: s.getStateBigInt(big.NewInt(nextHalvingSupplyLoc)), - LastHalvedAmount: s.getStateBigInt(big.NewInt(lastHalvedAmountLoc)), - BlockGasLimit: s.getStateBigInt(big.NewInt(blockGasLimitLoc)).Uint64(), - NumChains: uint32(s.getStateBigInt(big.NewInt(numChainsLoc)).Uint64()), - LambdaBA: s.getStateBigInt(big.NewInt(lambdaBALoc)).Uint64(), - LambdaDKG: s.getStateBigInt(big.NewInt(lambdaDKGLoc)).Uint64(), - K: uint32(s.getStateBigInt(big.NewInt(kLoc)).Uint64()), - PhiRatio: float32(s.getStateBigInt(big.NewInt(phiRatioLoc)).Uint64()) / decimalMultiplier, - NotarySetSize: uint32(s.getStateBigInt(big.NewInt(notarySetSizeLoc)).Uint64()), - DKGSetSize: uint32(s.getStateBigInt(big.NewInt(dkgSetSizeLoc)).Uint64()), - RoundInterval: s.getStateBigInt(big.NewInt(roundIntervalLoc)).Uint64(), - MinBlockInterval: s.getStateBigInt(big.NewInt(minBlockIntervalLoc)).Uint64(), - FineValues: s.FineValues(), - } -} - -// UpdateConfiguration updates system configuration. -func (s *GovernanceStateHelper) UpdateConfiguration(cfg *params.DexconConfig) { - s.setStateBigInt(big.NewInt(minStakeLoc), cfg.MinStake) - s.setStateBigInt(big.NewInt(lockupPeriodLoc), big.NewInt(int64(cfg.LockupPeriod))) - s.setStateBigInt(big.NewInt(miningVelocityLoc), big.NewInt(int64(cfg.MiningVelocity*decimalMultiplier))) - s.setStateBigInt(big.NewInt(nextHalvingSupplyLoc), cfg.NextHalvingSupply) - s.setStateBigInt(big.NewInt(lastHalvedAmountLoc), cfg.LastHalvedAmount) - s.setStateBigInt(big.NewInt(blockGasLimitLoc), big.NewInt(int64(cfg.BlockGasLimit))) - s.setStateBigInt(big.NewInt(numChainsLoc), big.NewInt(int64(cfg.NumChains))) - s.setStateBigInt(big.NewInt(lambdaBALoc), big.NewInt(int64(cfg.LambdaBA))) - s.setStateBigInt(big.NewInt(lambdaDKGLoc), big.NewInt(int64(cfg.LambdaDKG))) - s.setStateBigInt(big.NewInt(kLoc), big.NewInt(int64(cfg.K))) - s.setStateBigInt(big.NewInt(phiRatioLoc), big.NewInt(int64(cfg.PhiRatio*decimalMultiplier))) - s.setStateBigInt(big.NewInt(notarySetSizeLoc), big.NewInt(int64(cfg.NotarySetSize))) - s.setStateBigInt(big.NewInt(dkgSetSizeLoc), big.NewInt(int64(cfg.DKGSetSize))) - s.setStateBigInt(big.NewInt(roundIntervalLoc), big.NewInt(int64(cfg.RoundInterval))) - s.setStateBigInt(big.NewInt(minBlockIntervalLoc), big.NewInt(int64(cfg.MinBlockInterval))) - s.SetFineValues(cfg.FineValues) -} - -type rawConfigStruct struct { - MinStake *big.Int - LockupPeriod *big.Int - MiningVelocity *big.Int - BlockGasLimit *big.Int - NumChains *big.Int - LambdaBA *big.Int - LambdaDKG *big.Int - K *big.Int - PhiRatio *big.Int - NotarySetSize *big.Int - DKGSetSize *big.Int - RoundInterval *big.Int - MinBlockInterval *big.Int - FineValues []*big.Int -} - -// UpdateConfigurationRaw updates system configuration. -func (s *GovernanceStateHelper) UpdateConfigurationRaw(cfg *rawConfigStruct) { - s.setStateBigInt(big.NewInt(minStakeLoc), cfg.MinStake) - s.setStateBigInt(big.NewInt(lockupPeriodLoc), cfg.LockupPeriod) - s.setStateBigInt(big.NewInt(miningVelocityLoc), cfg.MiningVelocity) - s.setStateBigInt(big.NewInt(blockGasLimitLoc), cfg.BlockGasLimit) - s.setStateBigInt(big.NewInt(numChainsLoc), cfg.NumChains) - s.setStateBigInt(big.NewInt(lambdaBALoc), cfg.LambdaBA) - s.setStateBigInt(big.NewInt(lambdaDKGLoc), cfg.LambdaDKG) - s.setStateBigInt(big.NewInt(kLoc), cfg.K) - s.setStateBigInt(big.NewInt(phiRatioLoc), cfg.PhiRatio) - s.setStateBigInt(big.NewInt(notarySetSizeLoc), cfg.NotarySetSize) - s.setStateBigInt(big.NewInt(dkgSetSizeLoc), cfg.DKGSetSize) - s.setStateBigInt(big.NewInt(roundIntervalLoc), cfg.RoundInterval) - s.setStateBigInt(big.NewInt(minBlockIntervalLoc), cfg.MinBlockInterval) - s.SetFineValues(cfg.FineValues) -} - -// event ConfigurationChanged(); -func (s *GovernanceStateHelper) emitConfigurationChangedEvent() { - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{events["ConfigurationChanged"].Id()}, - Data: []byte{}, - }) -} - -// event CRSProposed(uint256 round, bytes32 crs); -func (s *GovernanceStateHelper) emitCRSProposed(round *big.Int, crs common.Hash) { - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{events["CRSProposed"].Id(), common.BigToHash(round)}, - Data: crs.Bytes(), - }) -} - -// event Staked(address indexed NodeAddress, uint256 Amount); -func (s *GovernanceStateHelper) emitStaked(nodeAddr common.Address) { - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{events["Staked"].Id(), nodeAddr.Hash()}, - Data: []byte{}, - }) -} - -// event Unstaked(address indexed NodeAddress); -func (s *GovernanceStateHelper) emitUnstaked(nodeAddr common.Address) { - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{events["Unstaked"].Id(), nodeAddr.Hash()}, - Data: []byte{}, - }) -} - -// event Delegated(address indexed NodeAddress, address indexed DelegatorAddress, uint256 Amount); -func (s *GovernanceStateHelper) emitDelegated(nodeAddr, delegatorAddr common.Address, amount *big.Int) { - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{events["Delegated"].Id(), nodeAddr.Hash(), delegatorAddr.Hash()}, - Data: common.BigToHash(amount).Bytes(), - }) -} - -// event Undelegated(address indexed NodeAddress, address indexed DelegatorAddress); -func (s *GovernanceStateHelper) emitUndelegated(nodeAddr, delegatorAddr common.Address) { - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{events["Undelegated"].Id(), nodeAddr.Hash(), delegatorAddr.Hash()}, - Data: []byte{}, - }) -} - -// event Withdrawn(address indexed NodeAddress, uint256 Amount); -func (s *GovernanceStateHelper) emitWithdrawn(nodeAddr common.Address, amount *big.Int) { - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{events["Withdrawn"].Id(), nodeAddr.Hash()}, - Data: common.BigToHash(amount).Bytes(), - }) -} - -// event ForkReported(address indexed NodeAddress, address indexed Type, bytes Arg1, bytes Arg2); -func (s *GovernanceStateHelper) emitForkReported(nodeAddr common.Address, reportType *big.Int, arg1, arg2 []byte) { - - t, err := abi.NewType("bytes") - if err != nil { - panic(err) - } - - arg := abi.Arguments{ - abi.Argument{ - Name: "Arg1", - Type: t, - Indexed: false, - }, - abi.Argument{ - Name: "Arg2", - Type: t, - Indexed: false, - }, - } - - data, err := arg.Pack(arg1, arg2) - if err != nil { - panic(err) - } - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{events["ForkReported"].Id(), nodeAddr.Hash()}, - Data: data, - }) -} - -// event Fined(address indexed NodeAddress, uint256 Amount); -func (s *GovernanceStateHelper) emitFined(nodeAddr common.Address, amount *big.Int) { - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{events["Fined"].Id(), nodeAddr.Hash()}, - Data: common.BigToHash(amount).Bytes(), - }) -} - -// event FinePaid(address indexed NodeAddress, uint256 Amount); -func (s *GovernanceStateHelper) emitFinePaid(nodeAddr common.Address, amount *big.Int) { - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{events["FinePaid"].Id(), nodeAddr.Hash()}, - Data: common.BigToHash(amount).Bytes(), - }) -} - -// GovernanceContract represents the governance contract of DEXCON. -type GovernanceContract struct { - evm *EVM - state GovernanceStateHelper - contract *vm.Contract -} - -func newGovernanceContract(evm *EVM, contract *vm.Contract) *GovernanceContract { - return &GovernanceContract{ - evm: evm, - state: GovernanceStateHelper{evm.StateDB}, - contract: contract, - } -} - -func (g *GovernanceContract) Address() common.Address { - return GovernanceContractAddress -} - -func (g *GovernanceContract) transfer(from, to common.Address, amount *big.Int) bool { - // TODO(w): add this to debug trace so it shows up as internal transaction. - if g.evm.CanTransfer(g.evm.StateDB, from, amount) { - g.evm.Transfer(g.evm.StateDB, from, to, amount) - return true - } - return false -} - -func (g *GovernanceContract) useGas(gas uint64) ([]byte, error) { - if !g.contract.UseGas(gas) { - return nil, vm.ErrOutOfGas - } - return nil, nil -} - -func (g *GovernanceContract) penalize() ([]byte, error) { - g.useGas(g.contract.Gas) - return nil, errExecutionReverted -} - -func (g *GovernanceContract) inDKGSet(round *big.Int, nodeID coreTypes.NodeID) bool { - target := coreTypes.NewDKGSetTarget(coreCommon.Hash(g.state.CurrentCRS())) - ns := coreTypes.NewNodeSet() - - configRound := big.NewInt(0) // If round < core.ConfigRoundShift, use 0. - if round.Uint64() >= core.ConfigRoundShift { - configRound = new(big.Int).Sub(round, big.NewInt(int64(core.ConfigRoundShift))) - } - - statedb, err := g.evm.StateAtNumber(g.state.RoundHeight(configRound).Uint64()) - if err != nil { - panic(err) - } - - state := GovernanceStateHelper{statedb} - for _, x := range state.QualifiedNodes() { - mpk, err := ecdsa.NewPublicKeyFromByteSlice(x.PublicKey) - if err != nil { - panic(err) - } - ns.Add(coreTypes.NewNodeID(mpk)) - } - - dkgSet := ns.GetSubSet(int(g.state.DKGSetSize().Uint64()), target) - _, ok := dkgSet[nodeID] - return ok -} - -func (g *GovernanceContract) addDKGComplaint(round *big.Int, comp []byte) ([]byte, error) { - if round.Cmp(g.state.Round()) != 0 { - return g.penalize() - } - - caller := g.contract.Caller() - - // Finalized caller is not allowed to propose complaint. - if g.state.DKGFinalized(round, caller) { - return g.penalize() - } - - // Calculate 2f - threshold := new(big.Int).Mul( - big.NewInt(2), - new(big.Int).Div(g.state.DKGSetSize(), big.NewInt(3))) - - // If 2f + 1 of DKG set is finalized, one can not propose complaint anymore. - if g.state.DKGFinalizedsCount(round).Cmp(threshold) > 0 { - return nil, errExecutionReverted - } - - var dkgComplaint dkgTypes.Complaint - if err := rlp.DecodeBytes(comp, &dkgComplaint); err != nil { - return g.penalize() - } - - // DKGComplaint must belongs to someone in DKG set. - if !g.inDKGSet(round, dkgComplaint.ProposerID) { - return g.penalize() - } - - verified, _ := coreUtils.VerifyDKGComplaintSignature(&dkgComplaint) - if !verified { - return g.penalize() - } - - mpk, err := g.state.GetDKGMasterPublicKeyByProposerID( - round, dkgComplaint.PrivateShare.ProposerID) - if err != nil { - return g.penalize() - } - - // Verify DKG complaint is correct. - ok, err := coreUtils.VerifyDKGComplaint(&dkgComplaint, mpk) - if !ok || err != nil { - return g.penalize() - } - - // Fine the attacker. - need, err := coreUtils.NeedPenaltyDKGPrivateShare(&dkgComplaint, mpk) - if err != nil { - return g.penalize() - } - if need { - fineValue := g.state.FineValue(big.NewInt(ReportTypeInvalidDKG)) - offset := g.state.NodesOffsetByID(Bytes32(dkgComplaint.PrivateShare.ProposerID.Hash)) - node := g.state.Node(offset) - if err := g.fine(node.Owner, fineValue, comp, nil); err != nil { - return g.penalize() - } - } - - g.state.PushDKGComplaint(round, comp) - - // Set this to relatively high to prevent spamming - return g.useGas(5000000) -} - -func (g *GovernanceContract) addDKGMasterPublicKey(round *big.Int, mpk []byte) ([]byte, error) { - // Can only add DKG master public key of current and next round. - if round.Cmp(new(big.Int).Add(g.state.Round(), big.NewInt(1))) > 0 { - return g.penalize() - } - - caller := g.contract.Caller() - offset := g.state.NodesOffsetByAddress(caller) - - // Can not add dkg mpk if not staked. - if offset.Cmp(big.NewInt(0)) < 0 { - return nil, errExecutionReverted - } - - // MPKReady caller is not allowed to propose mpk. - if g.state.DKGMPKReady(round, caller) { - return g.penalize() - } - - // Calculate 2f - threshold := new(big.Int).Mul( - big.NewInt(2), - new(big.Int).Div(g.state.DKGSetSize(), big.NewInt(3))) - - // If 2f + 1 of DKG set is mpk ready, one can not propose mpk anymore. - if g.state.DKGMPKReadysCount(round).Cmp(threshold) > 0 { - return nil, errExecutionReverted - } - - var dkgMasterPK dkgTypes.MasterPublicKey - if err := rlp.DecodeBytes(mpk, &dkgMasterPK); err != nil { - return g.penalize() - } - - // DKGMasterPublicKey must belongs to someone in DKG set. - if !g.inDKGSet(round, dkgMasterPK.ProposerID) { - return g.penalize() - } - - verified, _ := coreUtils.VerifyDKGMasterPublicKeySignature(&dkgMasterPK) - if !verified { - return g.penalize() - } - - g.state.PushDKGMasterPublicKey(round, mpk) - - return g.useGas(100000) -} - -func (g *GovernanceContract) addDKGMPKReady(round *big.Int, ready []byte) ([]byte, error) { - if round.Cmp(g.state.Round()) != 0 { - return g.penalize() - } - - caller := g.contract.Caller() - - var dkgReady dkgTypes.MPKReady - if err := rlp.DecodeBytes(ready, &dkgReady); err != nil { - return g.penalize() - } - - // DKGFInalize must belongs to someone in DKG set. - if !g.inDKGSet(round, dkgReady.ProposerID) { - return g.penalize() - } - - verified, _ := coreUtils.VerifyDKGMPKReadySignature(&dkgReady) - if !verified { - return g.penalize() - } - - if !g.state.DKGMPKReady(round, caller) { - g.state.PutDKGMPKReady(round, caller, true) - g.state.IncDKGMPKReadysCount(round) - } - - return g.useGas(100000) -} -func (g *GovernanceContract) addDKGFinalize(round *big.Int, finalize []byte) ([]byte, error) { - if round.Cmp(g.state.Round()) != 0 { - return g.penalize() - } - - caller := g.contract.Caller() - - var dkgFinalize dkgTypes.Finalize - if err := rlp.DecodeBytes(finalize, &dkgFinalize); err != nil { - return g.penalize() - } - - // DKGFInalize must belongs to someone in DKG set. - if !g.inDKGSet(round, dkgFinalize.ProposerID) { - return g.penalize() - } - - verified, _ := coreUtils.VerifyDKGFinalizeSignature(&dkgFinalize) - if !verified { - return g.penalize() - } - - if !g.state.DKGFinalized(round, caller) { - g.state.PutDKGFinalized(round, caller, true) - g.state.IncDKGFinalizedsCount(round) - } - - return g.useGas(100000) -} - -func (g *GovernanceContract) delegate(nodeAddr common.Address) ([]byte, error) { - offset := g.state.NodesOffsetByAddress(nodeAddr) - if offset.Cmp(big.NewInt(0)) < 0 { - return nil, errExecutionReverted - } - - caller := g.contract.Caller() - value := g.contract.Value - - // Can not delegate if no fund was sent. - if value.Cmp(big.NewInt(0)) == 0 { - return nil, errExecutionReverted - } - - // Can not delegate if already delegated. - delegatorOffset := g.state.DelegatorsOffset(nodeAddr, caller) - if delegatorOffset.Cmp(big.NewInt(0)) >= 0 { - return nil, errExecutionReverted - } - - // Add to the total staked of node. - node := g.state.Node(offset) - node.Staked = new(big.Int).Add(node.Staked, g.contract.Value) - g.state.UpdateNode(offset, node) - - // Add to network total staked. - g.state.IncTotalStaked(g.contract.Value) - - // Push delegator record. - offset = g.state.LenDelegators(nodeAddr) - g.state.PushDelegator(nodeAddr, &delegatorInfo{ - Owner: caller, - Value: value, - UndelegatedAt: big.NewInt(0), - }) - g.state.PutDelegatorOffset(nodeAddr, caller, offset) - g.state.emitDelegated(nodeAddr, caller, value) - - return g.useGas(200000) -} - -func (g *GovernanceContract) updateConfiguration(cfg *rawConfigStruct) ([]byte, error) { - // Only owner can update configuration. - if g.contract.Caller() != g.state.Owner() { - return nil, errExecutionReverted - } - - g.state.UpdateConfigurationRaw(cfg) - g.state.emitConfigurationChangedEvent() - return nil, nil -} - -func (g *GovernanceContract) stake( - publicKey []byte, name, email, location, url string) ([]byte, error) { - - // Reject invalid inputs. - if len(name) >= 32 || len(email) >= 32 || len(location) >= 32 || len(url) >= 128 { - return g.penalize() - } - - caller := g.contract.Caller() - offset := g.state.NodesOffsetByAddress(caller) - - // Can not stake if already staked. - if offset.Cmp(big.NewInt(0)) >= 0 { - return nil, errExecutionReverted - } - - offset = g.state.LenNodes() - node := &nodeInfo{ - Owner: caller, - PublicKey: publicKey, - Staked: big.NewInt(0), - Fined: big.NewInt(0), - Name: name, - Email: email, - Location: location, - Url: url, - } - g.state.PushNode(node) - if err := g.state.PutNodeOffsets(node, offset); err != nil { - return g.penalize() - } - - // Delegate fund to itself. - if g.contract.Value.Cmp(big.NewInt(0)) > 0 { - if ret, err := g.delegate(caller); err != nil { - return ret, err - } - } - - g.state.emitStaked(caller) - return g.useGas(100000) -} - -func (g *GovernanceContract) undelegateHelper(nodeAddr, caller common.Address) ([]byte, error) { - nodeOffset := g.state.NodesOffsetByAddress(nodeAddr) - if nodeOffset.Cmp(big.NewInt(0)) < 0 { - return nil, errExecutionReverted - } - - offset := g.state.DelegatorsOffset(nodeAddr, caller) - if offset.Cmp(big.NewInt(0)) < 0 { - return nil, errExecutionReverted - } - - node := g.state.Node(nodeOffset) - if node.Fined.Cmp(big.NewInt(0)) > 0 { - return nil, errExecutionReverted - } - - delegator := g.state.Delegator(nodeAddr, offset) - - if delegator.UndelegatedAt.Cmp(big.NewInt(0)) != 0 { - return nil, errExecutionReverted - } - - // Set undelegate time. - delegator.UndelegatedAt = g.evm.Time - g.state.UpdateDelegator(nodeAddr, offset, delegator) - - // Subtract from the total staked of node. - node.Staked = new(big.Int).Sub(node.Staked, delegator.Value) - g.state.UpdateNode(nodeOffset, node) - - // Subtract to network total staked. - g.state.DecTotalStaked(delegator.Value) - - g.state.emitUndelegated(nodeAddr, caller) - - return g.useGas(100000) -} - -func (g *GovernanceContract) undelegate(nodeAddr common.Address) ([]byte, error) { - return g.undelegateHelper(nodeAddr, g.contract.Caller()) -} - -func (g *GovernanceContract) withdraw(nodeAddr common.Address) ([]byte, error) { - caller := g.contract.Caller() - - nodeOffset := g.state.NodesOffsetByAddress(nodeAddr) - if nodeOffset.Cmp(big.NewInt(0)) < 0 { - return nil, errExecutionReverted - } - - offset := g.state.DelegatorsOffset(nodeAddr, caller) - if offset.Cmp(big.NewInt(0)) < 0 { - return nil, errExecutionReverted - } - - delegator := g.state.Delegator(nodeAddr, offset) - - // Not yet undelegated. - if delegator.UndelegatedAt.Cmp(big.NewInt(0)) == 0 { - return g.penalize() - } - - unlockTime := new(big.Int).Add(delegator.UndelegatedAt, g.state.LockupPeriod()) - if g.evm.Time.Cmp(unlockTime) <= 0 { - return g.penalize() - } - - length := g.state.LenDelegators(nodeAddr) - lastIndex := new(big.Int).Sub(length, big.NewInt(1)) - - // Delete the delegator. - if offset.Cmp(lastIndex) != 0 { - lastNode := g.state.Delegator(nodeAddr, lastIndex) - g.state.UpdateDelegator(nodeAddr, offset, lastNode) - g.state.PutDelegatorOffset(nodeAddr, lastNode.Owner, offset) - } - g.state.DeleteDelegatorsOffset(nodeAddr, caller) - g.state.PopLastDelegator(nodeAddr) - - // Return the staked fund. - if !g.transfer(GovernanceContractAddress, delegator.Owner, delegator.Value) { - return nil, errExecutionReverted - } - - g.state.emitWithdrawn(nodeAddr, delegator.Value) - - // We are the last delegator to withdraw the fund, remove the node info. - if g.state.LenDelegators(nodeAddr).Cmp(big.NewInt(0)) == 0 { - length := g.state.LenNodes() - lastIndex := new(big.Int).Sub(length, big.NewInt(1)) - - // Delete the node. - if offset.Cmp(lastIndex) != 0 { - lastNode := g.state.Node(lastIndex) - g.state.UpdateNode(offset, lastNode) - if err := g.state.PutNodeOffsets(lastNode, offset); err != nil { - panic(err) - } - } - g.state.DeleteNodesOffsetByAddress(nodeAddr) - g.state.PopLastNode() - } - - return g.useGas(100000) -} - -func (g *GovernanceContract) unstake() ([]byte, error) { - caller := g.contract.Caller() - offset := g.state.NodesOffsetByAddress(caller) - if offset.Cmp(big.NewInt(0)) < 0 { - return nil, errExecutionReverted - } - - node := g.state.Node(offset) - if node.Fined.Cmp(big.NewInt(0)) > 0 { - return nil, errExecutionReverted - } - - // Undelegate all delegators. - lenDelegators := g.state.LenDelegators(caller) - i := new(big.Int).Sub(lenDelegators, big.NewInt(1)) - for i.Cmp(big.NewInt(0)) >= 0 { - delegator := g.state.Delegator(caller, i) - if ret, err := g.undelegateHelper(caller, delegator.Owner); err != nil { - return ret, err - } - i = i.Sub(i, big.NewInt(1)) - } - - g.state.emitUnstaked(caller) - - return g.useGas(100000) -} - -func (g *GovernanceContract) payFine(nodeAddr common.Address) ([]byte, error) { - caller := g.contract.Caller() - - nodeOffset := g.state.NodesOffsetByAddress(nodeAddr) - if nodeOffset.Cmp(big.NewInt(0)) < 0 { - return nil, errExecutionReverted - } - - offset := g.state.DelegatorsOffset(nodeAddr, caller) - if offset.Cmp(big.NewInt(0)) < 0 { - return nil, errExecutionReverted - } - - node := g.state.Node(nodeOffset) - if node.Fined.Cmp(big.NewInt(0)) <= 0 || node.Fined.Cmp(g.contract.Value) < 0 { - return nil, errExecutionReverted - } - - node.Fined = new(big.Int).Sub(node.Fined, g.contract.Value) - g.state.UpdateNode(nodeOffset, node) - - // TODO: paid fine should be added to award pool. - - g.state.emitFinePaid(nodeAddr, g.contract.Value) - - return g.useGas(100000) -} - -func (g *GovernanceContract) proposeCRS(nextRound *big.Int, signedCRS []byte) ([]byte, error) { - round := g.state.Round() - - if nextRound.Cmp(round) <= 0 { - return nil, errExecutionReverted - } - - prevCRS := g.state.CRS(round) - - // Prepare DKGMasterPublicKeys. - dkgMasterPKs := g.state.UniqueDKGMasterPublicKeys(round) - - // Prepare DKGComplaints. - var dkgComplaints []*dkgTypes.Complaint - for _, comp := range g.state.DKGComplaints(round) { - x := new(dkgTypes.Complaint) - if err := rlp.DecodeBytes(comp, x); err != nil { - panic(err) - } - dkgComplaints = append(dkgComplaints, x) - } - - threshold := int(g.state.DKGSetSize().Uint64()/3 + 1) - - dkgGPK, err := core.NewDKGGroupPublicKey( - round.Uint64(), dkgMasterPKs, dkgComplaints, threshold) - if err != nil { - return nil, errExecutionReverted - } - signature := coreCrypto.Signature{ - Type: "bls", - Signature: signedCRS, - } - if !dkgGPK.VerifySignature(coreCommon.Hash(prevCRS), signature) { - return g.penalize() - } - - // Save new CRS into state and increase round. - newCRS := crypto.Keccak256(signedCRS) - crs := common.BytesToHash(newCRS) - - g.state.PushCRS(crs) - g.state.emitCRSProposed(nextRound, crs) - - // To encourage DKG set to propose the correct value, correctly submitting - // this should cause nothing. - return g.useGas(0) -} - -type sortBytes [][]byte - -func (s sortBytes) Less(i, j int) bool { - return bytes.Compare(s[i], s[j]) < 0 -} - -func (s sortBytes) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -func (s sortBytes) Len() int { - return len(s) -} - -func (g *GovernanceContract) fine(nodeAddr common.Address, amount *big.Int, payloads ...[]byte) error { - sort.Sort(sortBytes(payloads)) - - hash := Bytes32(crypto.Keccak256Hash(payloads...)) - if g.state.FineRecords(hash) { - return errors.New("already fined") - } - g.state.SetFineRecords(hash, true) - - nodeOffset := g.state.NodesOffsetByAddress(nodeAddr) - if nodeOffset.Cmp(big.NewInt(0)) < 0 { - return errExecutionReverted - } - - // Set fined value. - node := g.state.Node(nodeOffset) - node.Fined = new(big.Int).Add(node.Fined, amount) - g.state.UpdateNode(nodeOffset, node) - - g.state.emitFined(nodeAddr, amount) - - return nil -} - -func (g *GovernanceContract) report(reportType *big.Int, arg1, arg2 []byte) ([]byte, error) { - typeEnum := ReportType(reportType.Uint64()) - var reportedNodeID coreTypes.NodeID - - switch typeEnum { - case ReportTypeForkVote: - vote1 := new(coreTypes.Vote) - if err := rlp.DecodeBytes(arg1, vote1); err != nil { - return g.penalize() - } - vote2 := new(coreTypes.Vote) - if err := rlp.DecodeBytes(arg2, vote2); err != nil { - return g.penalize() - } - need, err := coreUtils.NeedPenaltyForkVote(vote1, vote2) - if !need || err != nil { - return g.penalize() - } - reportedNodeID = vote1.ProposerID - case ReportTypeForkBlock: - block1 := new(coreTypes.Block) - if err := rlp.DecodeBytes(arg1, block1); err != nil { - return g.penalize() - } - block2 := new(coreTypes.Block) - if err := rlp.DecodeBytes(arg2, block2); err != nil { - return g.penalize() - } - need, err := coreUtils.NeedPenaltyForkBlock(block1, block2) - if !need || err != nil { - return g.penalize() - } - reportedNodeID = block1.ProposerID - default: - return g.penalize() - } - - offset := g.state.NodesOffsetByID(Bytes32(reportedNodeID.Hash)) - node := g.state.Node(offset) - - g.state.emitForkReported(node.Owner, reportType, arg1, arg2) - - fineValue := g.state.FineValue(reportType) - if err := g.fine(node.Owner, fineValue, arg1, arg2); err != nil { - return nil, errExecutionReverted - } - return nil, nil -} - -func (g *GovernanceContract) transferOwnership(newOwner common.Address) ([]byte, error) { - // Only owner can update configuration. - if g.contract.Caller() != g.state.Owner() { - return nil, errExecutionReverted - } - g.state.SetOwner(newOwner) - return nil, nil -} - -func (g *GovernanceContract) snapshotRound(round, height *big.Int) ([]byte, error) { - // Validate if this mapping is correct. Only block proposer need to verify this. - if g.evm.IsBlockProposer() { - realHeight, ok := g.evm.GetRoundHeight(round.Uint64()) - if !ok { - return g.penalize() - } - - if height.Cmp(new(big.Int).SetUint64(realHeight)) != 0 { - return g.penalize() - } - } - - // Only allow updating the next round. - nextRound := g.state.LenRoundHeight() - if round.Cmp(nextRound) != 0 { - // No need to penalize, since the only possibility at this point is the - // round height is already snapshoted. - return nil, errExecutionReverted - } - - g.state.PushRoundHeight(height) - return nil, nil -} diff --git a/core/vm/evm/governance_abi.go b/core/vm/evm/governance_abi.go deleted file mode 100644 index 966c4c4f3..000000000 --- a/core/vm/evm/governance_abi.go +++ /dev/null @@ -1,1133 +0,0 @@ -// Copyright 2019 The dexon-consensus Authors -// This file is part of the dexon-consensus library. -// -// The dexon-consensus library is free software: you can redistribute it -// and/or modify it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of the License, -// or (at your option) any later version. -// -// The dexon-consensus library is distributed in the hope that it will be -// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the dexon-consensus library. If not, see -// . - -package evm - -// The governance ABI is generated from: -// https://github.com/dexon-foundation/governance-abi - -const GovernanceABIJSON = ` -[ - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "address" - }, - { - "name": "", - "type": "address" - } - ], - "name": "delegatorsOffset", - "outputs": [ - { - "name": "", - "type": "int256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "uint256" - }, - { - "name": "", - "type": "uint256" - } - ], - "name": "dkgComplaints", - "outputs": [ - { - "name": "", - "type": "bytes" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "notarySetSize", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "dkgSetSize", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "uint256" - } - ], - "name": "nodes", - "outputs": [ - { - "name": "owner", - "type": "address" - }, - { - "name": "publicKey", - "type": "bytes" - }, - { - "name": "staked", - "type": "uint256" - }, - { - "name": "fined", - "type": "uint256" - }, - { - "name": "name", - "type": "string" - }, - { - "name": "email", - "type": "string" - }, - { - "name": "location", - "type": "string" - }, - { - "name": "url", - "type": "string" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "miningVelocity", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "lambdaBA", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "minStake", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "uint256" - } - ], - "name": "crs", - "outputs": [ - { - "name": "", - "type": "bytes32" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "phiRatio", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "uint256" - } - ], - "name": "dkgMPKReadysCount", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "uint256" - }, - { - "name": "", - "type": "address" - } - ], - "name": "dkgMPKReadys", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "address" - }, - { - "name": "", - "type": "uint256" - } - ], - "name": "delegators", - "outputs": [ - { - "name": "owner", - "type": "address" - }, - { - "name": "value", - "type": "uint256" - }, - { - "name": "undelegated_at", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "blockGasLimit", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "bytes32" - } - ], - "name": "nodesOffsetByID", - "outputs": [ - { - "name": "", - "type": "int256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "totalStaked", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "roundInterval", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "address" - } - ], - "name": "nodesOffsetByAddress", - "outputs": [ - { - "name": "", - "type": "int256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "nextHalvingSupply", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "owner", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "lastHalvedAmount", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "bytes32" - } - ], - "name": "finedRecords", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "lambdaDKG", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "uint256" - } - ], - "name": "fineValues", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "uint256" - } - ], - "name": "roundHeight", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "minBlockInterval", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "k", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "uint256" - }, - { - "name": "", - "type": "uint256" - } - ], - "name": "dkgMasterPublicKeys", - "outputs": [ - { - "name": "", - "type": "bytes" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "uint256" - }, - { - "name": "", - "type": "address" - } - ], - "name": "dkgFinalizeds", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "numChains", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "lockupPeriod", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "uint256" - } - ], - "name": "dkgFinalizedsCount", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "anonymous": false, - "inputs": [], - "name": "ConfigurationChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "Round", - "type": "uint256" - }, - { - "indexed": false, - "name": "CRS", - "type": "bytes32" - } - ], - "name": "CRSProposed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "NodeAddress", - "type": "address" - } - ], - "name": "Staked", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "NodeAddress", - "type": "address" - } - ], - "name": "Unstaked", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "NodeAddress", - "type": "address" - }, - { - "indexed": true, - "name": "DelegatorAddress", - "type": "address" - }, - { - "indexed": false, - "name": "Amount", - "type": "uint256" - } - ], - "name": "Delegated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "NodeAddress", - "type": "address" - }, - { - "indexed": true, - "name": "DelegatorAddress", - "type": "address" - } - ], - "name": "Undelegated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "NodeAddress", - "type": "address" - }, - { - "indexed": false, - "name": "Amount", - "type": "uint256" - } - ], - "name": "Withdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "NodeAddress", - "type": "address" - }, - { - "indexed": false, - "name": "Type", - "type": "uint256" - }, - { - "indexed": false, - "name": "Arg1", - "type": "bytes" - }, - { - "indexed": false, - "name": "Arg2", - "type": "bytes" - } - ], - "name": "ForkReported", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "NodeAddress", - "type": "address" - }, - { - "indexed": false, - "name": "Amount", - "type": "uint256" - } - ], - "name": "Fined", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "NodeAddress", - "type": "address" - }, - { - "indexed": false, - "name": "Amount", - "type": "uint256" - } - ], - "name": "FinePaid", - "type": "event" - }, - { - "constant": false, - "inputs": [ - { - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "MinStake", - "type": "uint256" - }, - { - "name": "LockupPeriod", - "type": "uint256" - }, - { - "name": "MiningVelocity", - "type": "uint256" - }, - { - "name": "NextHalvingSupply", - "type": "uint256" - }, - { - "name": "LastHalvingAmount", - "type": "uint256" - }, - { - "name": "BlockGasLimit", - "type": "uint256" - }, - { - "name": "NumChains", - "type": "uint256" - }, - { - "name": "LambdaBA", - "type": "uint256" - }, - { - "name": "LambdaDKG", - "type": "uint256" - }, - { - "name": "K", - "type": "uint256" - }, - { - "name": "PhiRatio", - "type": "uint256" - }, - { - "name": "NotarySetSize", - "type": "uint256" - }, - { - "name": "DKGSetSize", - "type": "uint256" - }, - { - "name": "RoundInterval", - "type": "uint256" - }, - { - "name": "MinBlockInterval", - "type": "uint256" - }, - { - "name": "FineValues", - "type": "uint256[]" - } - ], - "name": "updateConfiguration", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "nodesLength", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "NodeAddress", - "type": "address" - } - ], - "name": "delegatorsLength", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "Round", - "type": "uint256" - }, - { - "name": "Height", - "type": "uint256" - } - ], - "name": "snapshotRound", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "Round", - "type": "uint256" - }, - { - "name": "SignedCRS", - "type": "bytes" - } - ], - "name": "proposeCRS", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "Round", - "type": "uint256" - }, - { - "name": "Complaint", - "type": "bytes" - } - ], - "name": "addDKGComplaint", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "Round", - "type": "uint256" - }, - { - "name": "PublicKey", - "type": "bytes" - } - ], - "name": "addDKGMasterPublicKey", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "Round", - "type": "uint256" - }, - { - "name": "MPKReady", - "type": "bytes" - } - ], - "name": "addDKGMPKReady", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "Round", - "type": "uint256" - }, - { - "name": "Finalize", - "type": "bytes" - } - ], - "name": "addDKGFinalize", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "PublicKey", - "type": "bytes" - }, - { - "name": "Name", - "type": "string" - }, - { - "name": "Email", - "type": "string" - }, - { - "name": "Location", - "type": "string" - }, - { - "name": "Url", - "type": "string" - } - ], - "name": "stake", - "outputs": [], - "payable": true, - "stateMutability": "payable", - "type": "function" - }, - { - "constant": false, - "inputs": [], - "name": "unstake", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "NodeAddress", - "type": "address" - } - ], - "name": "delegate", - "outputs": [], - "payable": true, - "stateMutability": "payable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "NodeAddress", - "type": "address" - } - ], - "name": "undelegate", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "NodeAddress", - "type": "address" - } - ], - "name": "withdraw", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "NodeAddress", - "type": "address" - } - ], - "name": "payFine", - "outputs": [], - "payable": true, - "stateMutability": "payable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "Type", - "type": "uint256" - }, - { - "name": "Arg1", - "type": "bytes" - }, - { - "name": "Arg2", - "type": "bytes" - } - ], - "name": "report", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - } -] -` diff --git a/core/vm/evm/governance_test.go b/core/vm/evm/governance_test.go deleted file mode 100644 index 5a82c7f1a..000000000 --- a/core/vm/evm/governance_test.go +++ /dev/null @@ -1,1061 +0,0 @@ -// Copyright 2018 The dexon-consensus Authors -// This file is part of the dexon-consensus library. -// -// The dexon-consensus library is free software: you can redistribute it -// and/or modify it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of the License, -// or (at your option) any later version. -// -// The dexon-consensus library is distributed in the hope that it will be -// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the dexon-consensus library. If not, see -// . - -package evm - -import ( - "bytes" - "crypto/ecdsa" - "math/big" - "math/rand" - "sort" - "testing" - "time" - - coreCommon "github.com/dexon-foundation/dexon-consensus/common" - coreCrypto "github.com/dexon-foundation/dexon-consensus/core/crypto" - coreEcdsa "github.com/dexon-foundation/dexon-consensus/core/crypto/ecdsa" - coreTypes "github.com/dexon-foundation/dexon-consensus/core/types" - coreUtils "github.com/dexon-foundation/dexon-consensus/core/utils" - - "github.com/dexon-foundation/dexon/common" - "github.com/dexon-foundation/dexon/core/state" - "github.com/dexon-foundation/dexon/core/vm" - "github.com/dexon-foundation/dexon/crypto" - "github.com/dexon-foundation/dexon/ethdb" - "github.com/dexon-foundation/dexon/params" - "github.com/dexon-foundation/dexon/rlp" - "github.com/stretchr/testify/suite" -) - -func init() { - rand.Seed(time.Now().UnixNano()) -} - -func randomBytes(minLength, maxLength int32) []byte { - length := rand.Int31()%(maxLength-minLength) + minLength - b := make([]byte, length) - for i := range b { - b[i] = byte(65 + rand.Int31()%60) - } - return b -} - -type GovernanceStateHelperTestSuite struct { - suite.Suite - - s *GovernanceStateHelper -} - -func (g *GovernanceStateHelperTestSuite) SetupTest() { - db := state.NewDatabase(ethdb.NewMemDatabase()) - statedb, err := state.New(common.Hash{}, db) - if err != nil { - panic(err) - } - g.s = &GovernanceStateHelper{statedb} -} - -func (g *GovernanceStateHelperTestSuite) TestReadWriteBytes() { - for i := 0; i < 100; i++ { - // Short bytes. - loc := big.NewInt(rand.Int63()) - data := randomBytes(3, 32) - g.s.writeBytes(loc, data) - read := g.s.readBytes(loc) - g.Require().Equal(0, bytes.Compare(data, read)) - - // long bytes. - loc = big.NewInt(rand.Int63()) - data = randomBytes(33, 2560) - g.s.writeBytes(loc, data) - read = g.s.readBytes(loc) - g.Require().Equal(0, bytes.Compare(data, read)) - } -} - -func TestGovernanceStateHelper(t *testing.T) { - suite.Run(t, new(GovernanceStateHelperTestSuite)) -} - -type GovernanceContractTestSuite struct { - suite.Suite - - config *params.DexconConfig - memDB *ethdb.MemDatabase - stateDB *state.StateDB - s *GovernanceStateHelper -} - -func (g *GovernanceContractTestSuite) SetupTest() { - memDB := ethdb.NewMemDatabase() - stateDB, err := state.New(common.Hash{}, state.NewDatabase(memDB)) - if err != nil { - panic(err) - } - g.memDB = memDB - g.stateDB = stateDB - g.s = &GovernanceStateHelper{stateDB} - - config := params.TestnetChainConfig.Dexcon - config.LockupPeriod = 1000 - config.NextHalvingSupply = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2.5e9)) - config.LastHalvedAmount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1.5e9)) - config.MiningVelocity = 0.1875 - - g.config = config - - // Give governance contract balance so it will not be deleted because of being an empty state object. - stateDB.AddBalance(GovernanceContractAddress, big.NewInt(1)) - - // Genesis CRS. - crs := crypto.Keccak256Hash([]byte(config.GenesisCRSText)) - g.s.PushCRS(crs) - - // Round 0 height. - g.s.PushRoundHeight(big.NewInt(0)) - - // Owner. - g.s.SetOwner(g.config.Owner) - - // Governance configuration. - g.s.UpdateConfiguration(config) - - g.stateDB.Commit(true) -} - -func (g *GovernanceContractTestSuite) newPrefundAccount() (*ecdsa.PrivateKey, common.Address) { - privKey, err := crypto.GenerateKey() - if err != nil { - panic(err) - } - address := crypto.PubkeyToAddress(privKey.PublicKey) - - g.stateDB.AddBalance(address, new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2e6))) - return privKey, address -} - -func (g *GovernanceContractTestSuite) call(caller common.Address, input []byte, value *big.Int) ([]byte, error) { - context := vm.Context{ - CanTransfer: func(db vm.StateDB, addr common.Address, amount *big.Int) bool { - return db.GetBalance(addr).Cmp(amount) >= 0 - }, - Transfer: func(db vm.StateDB, sender common.Address, recipient common.Address, amount *big.Int) { - db.SubBalance(sender, amount) - db.AddBalance(recipient, amount) - }, - GetRoundHeight: func(round uint64) (uint64, bool) { - switch round { - case 0: - return 0, true - case 1: - return 1000, true - case 2: - return 2000, true - } - return 0, false - }, - Time: big.NewInt(time.Now().UnixNano() / 1000000), - BlockNumber: big.NewInt(0), - } - - evm := NewEVM(context, g.stateDB, params.TestChainConfig, Config{IsBlockProposer: true}) - ret, _, err := evm.Call(vm.AccountRef(caller), GovernanceContractAddress, input, 10000000, value) - return ret, err -} - -func (g *GovernanceContractTestSuite) TestTransferOwnership() { - _, addr := g.newPrefundAccount() - - input, err := abiObject.Pack("transferOwnership", addr) - g.Require().NoError(err) - - // Call with non-owner. - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NotNil(err) - - // Call with owner. - _, err = g.call(g.config.Owner, input, big.NewInt(0)) - g.Require().NoError(err) - g.Require().Equal(addr, g.s.Owner()) -} - -func (g *GovernanceContractTestSuite) TestStakeUnstakeWithoutExtraDelegators() { - privKey, addr := g.newPrefundAccount() - pk := crypto.FromECDSAPub(&privKey.PublicKey) - - // Stake. - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)) - balanceBeforeStake := g.stateDB.GetBalance(addr) - input, err := abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(addr, input, amount) - g.Require().NoError(err) - - g.Require().Equal(1, int(g.s.LenNodes().Uint64())) - g.Require().Equal(1, len(g.s.QualifiedNodes())) - g.Require().Equal("Test1", g.s.Node(big.NewInt(0)).Name) - g.Require().Equal(amount.String(), g.s.TotalStaked().String()) - - // Check balance. - g.Require().Equal(new(big.Int).Sub(balanceBeforeStake, amount), g.stateDB.GetBalance(addr)) - g.Require().Equal(new(big.Int).Add(big.NewInt(1), amount), g.stateDB.GetBalance(GovernanceContractAddress)) - - // Staking again should fail. - _, err = g.call(addr, input, amount) - g.Require().NotNil(err) - - // Unstake. - input, err = abiObject.Pack("unstake") - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - g.Require().Equal(0, len(g.s.QualifiedNodes())) - g.Require().Equal(1, int(g.s.LenDelegators(addr).Uint64())) - g.Require().Equal(1, int(g.s.LenNodes().Uint64())) - - node := g.s.Node(big.NewInt(0)) - g.Require().Equal(big.NewInt(0).String(), node.Staked.String()) - g.Require().Equal(big.NewInt(0).String(), g.s.TotalStaked().String()) - - // Wait for lockup time than withdraw. - time.Sleep(time.Second * 2) - input, err = abiObject.Pack("withdraw", addr) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - g.Require().Equal(0, len(g.s.QualifiedNodes())) - g.Require().Equal(0, int(g.s.LenDelegators(addr).Uint64())) - g.Require().Equal(0, int(g.s.LenNodes().Uint64())) - - // Stake 2 nodes, and unstake the first then the second. - - // 2nd node Stake. - privKey2, addr2 := g.newPrefundAccount() - pk2 := crypto.FromECDSAPub(&privKey2.PublicKey) - input, err = abiObject.Pack("stake", pk2, "Test2", "test2@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(addr2, input, amount) - g.Require().NoError(err) - g.Require().Equal("Test2", g.s.Node(big.NewInt(0)).Name) - g.Require().Equal(0, int(g.s.NodesOffsetByAddress(addr2).Int64())) - - // 1st node Stake. - input, err = abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(addr, input, amount) - g.Require().NoError(err) - - g.Require().Equal(2, len(g.s.QualifiedNodes())) - g.Require().Equal(new(big.Int).Mul(amount, big.NewInt(2)).String(), g.s.TotalStaked().String()) - - // 2nd node Unstake. - input, err = abiObject.Pack("unstake") - g.Require().NoError(err) - _, err = g.call(addr2, input, big.NewInt(0)) - g.Require().NoError(err) - node = g.s.Node(big.NewInt(0)) - g.Require().Equal("Test2", node.Name) - g.Require().Equal(big.NewInt(0).String(), node.Staked.String()) - g.Require().Equal(1, len(g.s.QualifiedNodes())) - g.Require().Equal(amount.String(), g.s.TotalStaked().String()) - - time.Sleep(time.Second * 2) - input, err = abiObject.Pack("withdraw", addr2) - g.Require().NoError(err) - _, err = g.call(addr2, input, big.NewInt(0)) - g.Require().NoError(err) - g.Require().Equal(1, len(g.s.QualifiedNodes())) - - g.Require().Equal(1, int(g.s.LenNodes().Uint64())) - g.Require().Equal("Test1", g.s.Node(big.NewInt(0)).Name) - g.Require().Equal(-1, int(g.s.NodesOffsetByAddress(addr2).Int64())) - - // 1st node Unstake. - input, err = abiObject.Pack("unstake") - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - g.Require().Equal(0, len(g.s.QualifiedNodes())) - g.Require().Equal(big.NewInt(0).String(), g.s.TotalStaked().String()) - - time.Sleep(time.Second * 2) - input, err = abiObject.Pack("withdraw", addr) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - g.Require().Equal(0, int(g.s.LenNodes().Uint64())) - g.Require().Equal(-1, int(g.s.NodesOffsetByAddress(addr).Int64())) - g.Require().Equal(-1, int(g.s.DelegatorsOffset(addr, addr).Int64())) - - // Check balance. - g.Require().Equal(balanceBeforeStake, g.stateDB.GetBalance(addr)) - g.Require().Equal(balanceBeforeStake, g.stateDB.GetBalance(addr2)) - g.Require().Equal(big.NewInt(1), g.stateDB.GetBalance(GovernanceContractAddress)) -} - -func (g *GovernanceContractTestSuite) TestDelegateUndelegate() { - privKey, addr := g.newPrefundAccount() - pk := crypto.FromECDSAPub(&privKey.PublicKey) - - // Stake. - input, err := abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - ownerStaked := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - _, err = g.call(addr, input, ownerStaked) - g.Require().NoError(err) - g.Require().Equal(0, len(g.s.QualifiedNodes())) - g.Require().Equal(addr, g.s.Delegator(addr, big.NewInt(0)).Owner) - g.Require().Equal(ownerStaked, g.s.Node(big.NewInt(0)).Staked) - - // 1st delegator delegate to 1st node. - _, addrDelegator := g.newPrefundAccount() - - balanceBeforeDelegate := g.stateDB.GetBalance(addrDelegator) - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3e5)) - input, err = abiObject.Pack("delegate", addr) - g.Require().NoError(err) - - _, err = g.call(addrDelegator, input, amount) - g.Require().NoError(err) - g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator)) - g.Require().Equal(addrDelegator, g.s.Delegator(addr, big.NewInt(1)).Owner) - g.Require().Equal(new(big.Int).Add(amount, ownerStaked), g.s.Node(big.NewInt(0)).Staked) - g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String()) - g.Require().Equal(1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64())) - - // Same person delegate the 2nd time should fail. - _, err = g.call(addrDelegator, input, big.NewInt(1e18)) - g.Require().NotNil(err) - - // Not yet qualified. - g.Require().Equal(0, len(g.s.QualifiedNodes())) - - // 2nd delegator delegate to 1st node. - _, addrDelegator2 := g.newPrefundAccount() - _, err = g.call(addrDelegator2, input, amount) - g.Require().NoError(err) - g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator2)) - g.Require().Equal(addrDelegator2, g.s.Delegator(addr, big.NewInt(2)).Owner) - g.Require().Equal(new(big.Int).Add(ownerStaked, new(big.Int).Mul(amount, big.NewInt(2))), - g.s.Node(big.NewInt(0)).Staked) - g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String()) - g.Require().Equal(2, int(g.s.DelegatorsOffset(addr, addrDelegator2).Int64())) - - // Qualified. - g.Require().Equal(1, len(g.s.QualifiedNodes())) - - // Undelegate addrDelegator. - balanceBeforeUnDelegate := g.stateDB.GetBalance(addrDelegator) - input, err = abiObject.Pack("undelegate", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator, input, big.NewInt(0)) - g.Require().Equal(new(big.Int).Add(amount, ownerStaked), g.s.Node(big.NewInt(0)).Staked) - g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String()) - g.Require().NoError(err) - - // Undelegate the second time should fail. - _, err = g.call(addrDelegator, input, big.NewInt(0)) - g.Require().Error(err) - - // Withdraw within lockup time should fail. - input, err = abiObject.Pack("withdraw", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator, input, big.NewInt(0)) - g.Require().NotNil(err) - - g.Require().Equal(3, int(g.s.LenDelegators(addr).Uint64())) - g.Require().Equal(balanceBeforeUnDelegate, g.stateDB.GetBalance(addrDelegator)) - g.Require().NotEqual(-1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64())) - - // Wait for lockup time than withdraw. - time.Sleep(time.Second * 2) - input, err = abiObject.Pack("withdraw", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator, input, big.NewInt(0)) - g.Require().NoError(err) - - g.Require().Equal(2, int(g.s.LenDelegators(addr).Uint64())) - g.Require().Equal(new(big.Int).Add(balanceBeforeUnDelegate, amount), g.stateDB.GetBalance(addrDelegator)) - g.Require().Equal(-1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64())) - - // Withdraw when their is no delegation should fail. - time.Sleep(time.Second) - input, err = abiObject.Pack("withdraw", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator, input, big.NewInt(0)) - g.Require().Error(err) - - // Undelegate addrDelegator2. - balanceBeforeUnDelegate = g.stateDB.GetBalance(addrDelegator2) - input, err = abiObject.Pack("undelegate", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator2, input, big.NewInt(0)) - g.Require().NoError(err) - - g.Require().Equal(ownerStaked, g.s.Node(big.NewInt(0)).Staked) - g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String()) - - // Wait for lockup time than withdraw. - time.Sleep(time.Second * 2) - input, err = abiObject.Pack("withdraw", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator2, input, big.NewInt(0)) - g.Require().NoError(err) - - g.Require().Equal(1, int(g.s.LenDelegators(addr).Uint64())) - g.Require().Equal(new(big.Int).Add(balanceBeforeUnDelegate, amount), g.stateDB.GetBalance(addrDelegator2)) - g.Require().Equal(-1, int(g.s.DelegatorsOffset(addr, addrDelegator2).Int64())) - - // Unqualified - g.Require().Equal(0, len(g.s.QualifiedNodes())) - - // Owner undelegate itself. - g.Require().Equal(1, int(g.s.LenNodes().Uint64())) - g.Require().Equal(1, int(g.s.LenDelegators(addr).Uint64())) - - input, err = abiObject.Pack("undelegate", addr) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - g.Require().Equal(big.NewInt(0).String(), g.s.Node(big.NewInt(0)).Staked.String()) - g.Require().Equal(big.NewInt(0).String(), g.s.TotalStaked().String()) - - time.Sleep(time.Second * 2) - input, err = abiObject.Pack("withdraw", addr) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - - g.Require().Equal(0, int(g.s.LenNodes().Uint64())) - g.Require().Equal(0, int(g.s.LenDelegators(addr).Uint64())) -} - -func (g *GovernanceContractTestSuite) TestFine() { - privKey, addr := g.newPrefundAccount() - pk := crypto.FromECDSAPub(&privKey.PublicKey) - - // Stake. - input, err := abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - ownerStaked := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - _, err = g.call(addr, input, ownerStaked) - g.Require().NoError(err) - g.Require().Equal(0, len(g.s.QualifiedNodes())) - g.Require().Equal(addr, g.s.Delegator(addr, big.NewInt(0)).Owner) - g.Require().Equal(ownerStaked, g.s.Node(big.NewInt(0)).Staked) - - // 1st delegator delegate to 1st node. - _, addrDelegator := g.newPrefundAccount() - - balanceBeforeDelegate := g.stateDB.GetBalance(addrDelegator) - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - input, err = abiObject.Pack("delegate", addr) - g.Require().NoError(err) - - _, err = g.call(addrDelegator, input, amount) - g.Require().NoError(err) - g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator)) - g.Require().Equal(addrDelegator, g.s.Delegator(addr, big.NewInt(1)).Owner) - g.Require().Equal(new(big.Int).Add(amount, ownerStaked), g.s.Node(big.NewInt(0)).Staked) - g.Require().Equal(1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64())) - - // Qualified. - g.Require().Equal(1, len(g.s.QualifiedNodes())) - - // Paying to node without fine should fail. - input, err = abiObject.Pack("payFine", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator, input, amount) - g.Require().NotNil(err) - - // Fined. - offset := g.s.NodesOffsetByAddress(addr) - g.Require().True(offset.Cmp(big.NewInt(0)) >= 0) - node := g.s.Node(offset) - node.Fined = new(big.Int).Set(amount) - g.s.UpdateNode(offset, node) - node = g.s.Node(offset) - g.Require().Equal(0, node.Fined.Cmp(amount)) - - // Not qualified after fined. - g.Require().Equal(0, len(g.s.QualifiedNodes())) - - // Cannot undelegate before fines are paied. - input, err = abiObject.Pack("undelegate", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator, input, big.NewInt(0)) - g.Require().NotNil(err) - - // Only delegators can pay fine. - _, addrDelegator2 := g.newPrefundAccount() - input, err = abiObject.Pack("payFine", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator2, input, big.NewInt(5e5)) - g.Require().NotNil(err) - - // Paying more than fine should fail. - payAmount := new(big.Int).Add(amount, amount) - input, err = abiObject.Pack("payFine", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator, input, payAmount) - g.Require().NotNil(err) - - // Pay the fine. - input, err = abiObject.Pack("payFine", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator, input, amount) - g.Require().NoError(err) - - // Qualified. - g.Require().Equal(1, len(g.s.QualifiedNodes())) - - // Can undelegate after all fines are paied. - input, err = abiObject.Pack("undelegate", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator, input, big.NewInt(0)) - g.Require().NoError(err) -} - -func (g *GovernanceContractTestSuite) TestUnstakeWithExtraDelegators() { - privKey, addr := g.newPrefundAccount() - pk := crypto.FromECDSAPub(&privKey.PublicKey) - - // Stake. - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - input, err := abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(addr, input, amount) - g.Require().NoError(err) - - // 1st delegator delegate to 1st node. - _, addrDelegator := g.newPrefundAccount() - - balanceBeforeDelegate := g.stateDB.GetBalance(addrDelegator) - amount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3e5)) - input, err = abiObject.Pack("delegate", addr) - g.Require().NoError(err) - - _, err = g.call(addrDelegator, input, amount) - g.Require().NoError(err) - g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator)) - g.Require().Equal(addrDelegator, g.s.Delegator(addr, big.NewInt(1)).Owner) - g.Require().Equal(0, len(g.s.QualifiedNodes())) - - // 2st delegator delegate to 1st node. - _, addrDelegator2 := g.newPrefundAccount() - - balanceBeforeDelegate = g.stateDB.GetBalance(addrDelegator2) - input, err = abiObject.Pack("delegate", addr) - g.Require().NoError(err) - - _, err = g.call(addrDelegator2, input, amount) - g.Require().NoError(err) - g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator2)) - g.Require().Equal(addrDelegator2, g.s.Delegator(addr, big.NewInt(2)).Owner) - - // Node is now qualified. - g.Require().Equal(1, len(g.s.QualifiedNodes())) - - // Unstake. - input, err = abiObject.Pack("unstake") - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - time.Sleep(time.Second * 2) - input, err = abiObject.Pack("withdraw", addr) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - _, err = g.call(addrDelegator, input, big.NewInt(0)) - g.Require().NoError(err) - _, err = g.call(addrDelegator2, input, big.NewInt(0)) - g.Require().NoError(err) - - g.Require().Equal(0, int(g.s.LenDelegators(addr).Uint64())) - g.Require().Equal(0, int(g.s.LenNodes().Uint64())) - - // Check balance. - g.Require().Equal(balanceBeforeDelegate, g.stateDB.GetBalance(addr)) - g.Require().Equal(balanceBeforeDelegate, g.stateDB.GetBalance(addrDelegator)) - g.Require().Equal(balanceBeforeDelegate, g.stateDB.GetBalance(addrDelegator2)) - g.Require().Equal(big.NewInt(1), g.stateDB.GetBalance(GovernanceContractAddress)) -} - -func (g *GovernanceContractTestSuite) TestUpdateConfiguration() { - _, addr := g.newPrefundAccount() - - input, err := abiObject.Pack("updateConfiguration", - new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)), - big.NewInt(1000), - big.NewInt(0.1875*decimalMultiplier), - big.NewInt(1e18), - big.NewInt(1e18), - big.NewInt(8000000), - big.NewInt(6), - big.NewInt(250), - big.NewInt(2500), - big.NewInt(0), - big.NewInt(667000), - big.NewInt(4), - big.NewInt(4), - big.NewInt(600000), - big.NewInt(900), - []*big.Int{big.NewInt(1), big.NewInt(1), big.NewInt(1)}) - g.Require().NoError(err) - - // Call with non-owner. - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NotNil(err) - - // Call with owner. - _, err = g.call(g.config.Owner, input, big.NewInt(0)) - g.Require().NoError(err) -} - -func (g *GovernanceContractTestSuite) TestSnapshotRound() { - _, addr := g.newPrefundAccount() - - // Wrong height. - input, err := abiObject.Pack("snapshotRound", big.NewInt(1), big.NewInt(666)) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NotNil(err) - - // Invalid round. - input, err = abiObject.Pack("snapshotRound", big.NewInt(2), big.NewInt(2000)) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NotNil(err) - - // Correct. - input, err = abiObject.Pack("snapshotRound", big.NewInt(1), big.NewInt(1000)) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - // Duplicate round. - input, err = abiObject.Pack("snapshotRound", big.NewInt(1), big.NewInt(1000)) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NotNil(err) - - // Invalid round. - input, err = abiObject.Pack("snapshotRound", big.NewInt(3), big.NewInt(3000)) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NotNil(err) - - // Correct. - input, err = abiObject.Pack("snapshotRound", big.NewInt(2), big.NewInt(2000)) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) -} - -func (g *GovernanceContractTestSuite) TestConfigurationReading() { - _, addr := g.newPrefundAccount() - - // CRS. - input, err := abiObject.Pack("crs", big.NewInt(0)) - g.Require().NoError(err) - res, err := g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - var crs0 [32]byte - err = abiObject.Unpack(&crs0, "crs", res) - g.Require().NoError(err) - g.Require().Equal(crypto.Keccak256Hash([]byte(g.config.GenesisCRSText)), common.BytesToHash(crs0[:])) - - // Owner. - input, err = abiObject.Pack("owner") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - var owner common.Address - err = abiObject.Unpack(&owner, "owner", res) - g.Require().NoError(err) - g.Require().Equal(g.config.Owner, owner) - - // MinStake. - input, err = abiObject.Pack("minStake") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - var value *big.Int - err = abiObject.Unpack(&value, "minStake", res) - g.Require().NoError(err) - g.Require().Equal(g.config.MinStake.String(), value.String()) - - // BlockReward. - input, err = abiObject.Pack("miningVelocity") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "miningVelocity", res) - g.Require().NoError(err) - g.Require().Equal(g.config.MiningVelocity, float32(value.Uint64())/decimalMultiplier) - - // BlockGasLimit. - input, err = abiObject.Pack("blockGasLimit") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "blockGasLimit", res) - g.Require().NoError(err) - g.Require().Equal(g.config.BlockGasLimit, value.Uint64()) - - // NumChains. - input, err = abiObject.Pack("numChains") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "numChains", res) - g.Require().NoError(err) - g.Require().Equal(g.config.NumChains, uint32(value.Uint64())) - - // LambdaBA. - input, err = abiObject.Pack("lambdaBA") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "lambdaBA", res) - g.Require().NoError(err) - g.Require().Equal(g.config.LambdaBA, value.Uint64()) - - // LambdaDKG. - input, err = abiObject.Pack("lambdaDKG") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "lambdaDKG", res) - g.Require().NoError(err) - g.Require().Equal(g.config.LambdaDKG, value.Uint64()) - - // K. - input, err = abiObject.Pack("k") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "k", res) - g.Require().NoError(err) - g.Require().Equal(g.config.K, uint32(value.Uint64())) - - // PhiRatio. - input, err = abiObject.Pack("phiRatio") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "phiRatio", res) - g.Require().NoError(err) - g.Require().Equal(g.config.PhiRatio, float32(value.Uint64())/decimalMultiplier) - - // NotarySetSize. - input, err = abiObject.Pack("notarySetSize") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "notarySetSize", res) - g.Require().NoError(err) - g.Require().Equal(g.config.NotarySetSize, uint32(value.Uint64())) - - // DKGSetSize. - input, err = abiObject.Pack("dkgSetSize") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "dkgSetSize", res) - g.Require().NoError(err) - g.Require().Equal(g.config.DKGSetSize, uint32(value.Uint64())) - - // RoundInterval. - input, err = abiObject.Pack("roundInterval") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "roundInterval", res) - g.Require().NoError(err) - g.Require().Equal(g.config.RoundInterval, value.Uint64()) - - // MinBlockInterval. - input, err = abiObject.Pack("minBlockInterval") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "minBlockInterval", res) - g.Require().NoError(err) - g.Require().Equal(g.config.MinBlockInterval, value.Uint64()) -} - -func (g *GovernanceContractTestSuite) TestReportForkVote() { - key, addr := g.newPrefundAccount() - pkBytes := crypto.FromECDSAPub(&key.PublicKey) - - // Stake. - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - input, err := abiObject.Pack("stake", pkBytes, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(addr, input, amount) - g.Require().NoError(err) - - pubKey := coreEcdsa.NewPublicKeyFromECDSA(&key.PublicKey) - privKey := coreEcdsa.NewPrivateKeyFromECDSA(key) - vote1 := coreTypes.NewVote(coreTypes.VoteCom, coreCommon.NewRandomHash(), uint64(0)) - vote1.ProposerID = coreTypes.NewNodeID(pubKey) - - vote2 := vote1.Clone() - for vote2.BlockHash == vote1.BlockHash { - vote2.BlockHash = coreCommon.NewRandomHash() - } - vote1.Signature, err = privKey.Sign(coreUtils.HashVote(vote1)) - g.Require().NoError(err) - vote2.Signature, err = privKey.Sign(coreUtils.HashVote(vote2)) - g.Require().NoError(err) - - vote1Bytes, err := rlp.EncodeToBytes(vote1) - g.Require().NoError(err) - vote2Bytes, err := rlp.EncodeToBytes(vote2) - g.Require().NoError(err) - - // Report wrong type (fork block) - input, err = abiObject.Pack("report", big.NewInt(2), vote1Bytes, vote2Bytes) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().Error(err) - - input, err = abiObject.Pack("report", big.NewInt(1), vote1Bytes, vote2Bytes) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - node := g.s.Node(big.NewInt(0)) - g.Require().Equal(node.Fined, g.s.FineValue(big.NewInt(1))) - - // Duplicate report should fail. - input, err = abiObject.Pack("report", big.NewInt(1), vote1Bytes, vote2Bytes) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().Error(err) - - // Check if finedRecords is set. - payloads := [][]byte{vote1Bytes, vote2Bytes} - sort.Sort(sortBytes(payloads)) - - hash := Bytes32(crypto.Keccak256Hash(payloads...)) - input, err = abiObject.Pack("finedRecords", hash) - g.Require().NoError(err) - res, err := g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - var value bool - err = abiObject.Unpack(&value, "finedRecords", res) - g.Require().NoError(err) - g.Require().True(value) -} - -func (g *GovernanceContractTestSuite) TestReportForkBlock() { - key, addr := g.newPrefundAccount() - pkBytes := crypto.FromECDSAPub(&key.PublicKey) - - // Stake. - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - input, err := abiObject.Pack("stake", pkBytes, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(addr, input, amount) - g.Require().NoError(err) - - privKey := coreEcdsa.NewPrivateKeyFromECDSA(key) - block1 := &coreTypes.Block{ - ProposerID: coreTypes.NewNodeID(privKey.PublicKey()), - ParentHash: coreCommon.NewRandomHash(), - Timestamp: time.Now(), - } - - block2 := block1.Clone() - for block2.ParentHash == block1.ParentHash { - block2.ParentHash = coreCommon.NewRandomHash() - } - - hashBlock := func(block *coreTypes.Block) coreCommon.Hash { - block.PayloadHash = coreCrypto.Keccak256Hash(block.Payload) - var err error - block.Hash, err = coreUtils.HashBlock(block) - g.Require().NoError(err) - return block.Hash - } - - block1.Signature, err = privKey.Sign(hashBlock(block1)) - g.Require().NoError(err) - block2.Signature, err = privKey.Sign(hashBlock(block2)) - g.Require().NoError(err) - - block1Bytes, err := rlp.EncodeToBytes(block1) - g.Require().NoError(err) - block2Bytes, err := rlp.EncodeToBytes(block2) - g.Require().NoError(err) - - // Report wrong type (fork vote) - input, err = abiObject.Pack("report", big.NewInt(1), block1Bytes, block2Bytes) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().Error(err) - - input, err = abiObject.Pack("report", big.NewInt(2), block1Bytes, block2Bytes) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - node := g.s.Node(big.NewInt(0)) - g.Require().Equal(node.Fined, g.s.FineValue(big.NewInt(2))) - - // Duplicate report should fail. - input, err = abiObject.Pack("report", big.NewInt(2), block1Bytes, block2Bytes) - g.Require().NoError(err) - _, err = g.call(addr, input, big.NewInt(0)) - g.Require().Error(err) - - // Check if finedRecords is set. - payloads := [][]byte{block1Bytes, block2Bytes} - sort.Sort(sortBytes(payloads)) - - hash := Bytes32(crypto.Keccak256Hash(payloads...)) - input, err = abiObject.Pack("finedRecords", hash) - g.Require().NoError(err) - res, err := g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - var value bool - err = abiObject.Unpack(&value, "finedRecords", res) - g.Require().NoError(err) - g.Require().True(value) -} - -func (g *GovernanceContractTestSuite) TestMiscVariableReading() { - privKey, addr := g.newPrefundAccount() - pk := crypto.FromECDSAPub(&privKey.PublicKey) - - input, err := abiObject.Pack("totalSupply") - g.Require().NoError(err) - res, err := g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - input, err = abiObject.Pack("totalStaked") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - // Stake. - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - input, err = abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(addr, input, amount) - g.Require().NoError(err) - - // 1st delegator delegate to 1st node. - _, addrDelegator := g.newPrefundAccount() - amount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3e5)) - input, err = abiObject.Pack("delegate", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator, input, amount) - g.Require().NoError(err) - - // 2st delegator delegate to 1st node. - _, addrDelegator2 := g.newPrefundAccount() - input, err = abiObject.Pack("delegate", addr) - g.Require().NoError(err) - _, err = g.call(addrDelegator2, input, amount) - g.Require().NoError(err) - - input, err = abiObject.Pack("nodes", big.NewInt(0)) - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - input, err = abiObject.Pack("nodesLength") - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - var value *big.Int - err = abiObject.Unpack(&value, "nodesLength", res) - g.Require().NoError(err) - g.Require().Equal(1, int(value.Uint64())) - - input, err = abiObject.Pack("nodesOffsetByAddress", addr) - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "nodesOffsetByAddress", res) - g.Require().NoError(err) - g.Require().Equal(0, int(value.Uint64())) - - id, err := publicKeyToNodeID(pk) - g.Require().NoError(err) - input, err = abiObject.Pack("nodesOffsetByID", id) - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "nodesOffsetByID", res) - g.Require().NoError(err) - g.Require().Equal(0, int(value.Uint64())) - - input, err = abiObject.Pack("delegators", addr, big.NewInt(0)) - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - - input, err = abiObject.Pack("delegatorsLength", addr) - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "delegatorsLength", res) - g.Require().NoError(err) - g.Require().Equal(3, int(value.Uint64())) - - input, err = abiObject.Pack("delegatorsOffset", addr, addrDelegator2) - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = abiObject.Unpack(&value, "delegatorsOffset", res) - g.Require().NoError(err) - g.Require().Equal(2, int(value.Uint64())) - - input, err = abiObject.Pack("fineValues", big.NewInt(0)) - g.Require().NoError(err) - res, err = g.call(addr, input, big.NewInt(0)) - g.Require().NoError(err) -} - -func (g *GovernanceContractTestSuite) TestHalvingCondition() { - // TotalSupply 2.5B reached - g.s.MiningHalved() - g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3.25e9)).String(), - g.s.NextHalvingSupply().String()) - g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(0.75e9)).String(), - g.s.LastHalvedAmount().String()) - - // TotalSupply 3.25B reached - g.s.MiningHalved() - g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3.625e9)).String(), - g.s.NextHalvingSupply().String()) - g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(0.375e9)).String(), - g.s.LastHalvedAmount().String()) -} - -func TestGovernanceContract(t *testing.T) { - suite.Run(t, new(GovernanceContractTestSuite)) -} diff --git a/core/vm/evm/oracle.go b/core/vm/evm/oracle.go new file mode 100644 index 000000000..1daba822e --- /dev/null +++ b/core/vm/evm/oracle.go @@ -0,0 +1,89 @@ +// Copyright 2019 The dexon-consensus Authors +// This file is part of the dexon-consensus library. +// +// The dexon-consensus library is free software: you can redistribute it +// and/or modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation, either version 3 of the License, +// or (at your option) any later version. +// +// The dexon-consensus library is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +// General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the dexon-consensus library. If not, see +// . + +package evm + +import ( + "strings" + + "github.com/dexon-foundation/dexon/accounts/abi" + "github.com/dexon-foundation/dexon/common" + "github.com/dexon-foundation/dexon/core/vm" +) + +var GovernanceContractAddress = common.HexToAddress("63751838d6485578b23e8b051d40861ecc416794") + +var GovernanceABI *OracleContractABI + +func init() { + GovernanceABI = NewOracleContractABI(GovernanceABIJSON) +} + +// OracleContract represent special system contracts written in Go. +type OracleContract interface { + Run(evm *EVM, input []byte, contract *vm.Contract) (ret []byte, err error) +} + +// A map representing available system oracle contracts. +var OracleContracts = map[common.Address]func() OracleContract{ + GovernanceContractAddress: func() OracleContract { + return &GovernanceContract{ + coreDKGUtils: &defaultCoreDKGUtils{}, + } + }, +} + +// Run oracle contract. +func RunOracleContract(oracle OracleContract, evm *EVM, input []byte, contract *vm.Contract) (ret []byte, err error) { + return oracle.Run(evm, input, contract) +} + +// OracleContractABI represents ABI information for a given contract. +type OracleContractABI struct { + ABI abi.ABI + Name2Method map[string]abi.Method + Sig2Method map[string]abi.Method + Events map[string]abi.Event +} + +// NewOracleContractABI parse the ABI. +func NewOracleContractABI(abiDefinition string) *OracleContractABI { + abiObject, err := abi.JSON(strings.NewReader(abiDefinition)) + if err != nil { + panic(err) + } + + sig2Method := make(map[string]abi.Method) + name2Method := make(map[string]abi.Method) + + for _, method := range abiObject.Methods { + sig2Method[string(method.Id())] = method + name2Method[method.Name] = method + } + + events := make(map[string]abi.Event) + for _, event := range abiObject.Events { + events[event.Name] = event + } + + return &OracleContractABI{ + ABI: abiObject, + Name2Method: name2Method, + Sig2Method: sig2Method, + Events: events, + } +} diff --git a/core/vm/evm/oracle_contract_abi.go b/core/vm/evm/oracle_contract_abi.go new file mode 100644 index 000000000..3e7fc8784 --- /dev/null +++ b/core/vm/evm/oracle_contract_abi.go @@ -0,0 +1,1221 @@ +// Copyright 2019 The dexon-consensus Authors +// This file is part of the dexon-consensus library. +// +// The dexon-consensus library is free software: you can redistribute it +// and/or modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation, either version 3 of the License, +// or (at your option) any later version. +// +// The dexon-consensus library is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +// General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the dexon-consensus library. If not, see +// . + +package evm + +// The governance ABI is generated from: +// https://github.com/dexon-foundation/governance-abi + +const GovernanceABIJSON = ` +[ + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "dkgSuccesses", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "notarySetSize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "nodes", + "outputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "publicKey", + "type": "bytes" + }, + { + "name": "staked", + "type": "uint256" + }, + { + "name": "fined", + "type": "uint256" + }, + { + "name": "name", + "type": "string" + }, + { + "name": "email", + "type": "string" + }, + { + "name": "location", + "type": "string" + }, + { + "name": "url", + "type": "string" + }, + { + "name": "unstaked", + "type": "uint256" + }, + { + "name": "unstakedAt", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "notaryParamBeta", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "miningVelocity", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "lambdaBA", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "minStake", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "crsRound", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "notaryParamAlpha", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "dkgSuccessesCount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "dkgFinalizeds", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "blockGasLimit", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "dkgRound", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalStaked", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "nodesOffsetByAddress", + "outputs": [ + { + "name": "", + "type": "int256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "crs", + "outputs": [ + { + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "roundLength", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "nextHalvingSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "dkgComplaints", + "outputs": [ + { + "name": "", + "type": "bytes" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "bytes32" + } + ], + "name": "dkgMasterPublicKeyOffset", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "dkgMPKReadys", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "lastHalvedAmount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "bytes32" + } + ], + "name": "finedRecords", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "lambdaDKG", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "fineValues", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "roundHeight", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "dkgMPKReadysCount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "minBlockInterval", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "dkgMasterPublicKeys", + "outputs": [ + { + "name": "", + "type": "bytes" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "lastProposedHeight", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "minGasPrice", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "dkgFinalizedsCount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "bytes32" + } + ], + "name": "dkgComplaintsProposed", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "nodesOffsetByNodeKeyAddress", + "outputs": [ + { + "name": "", + "type": "int256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "lockupPeriod", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "dkgResetCount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [], + "name": "ConfigurationChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "Round", + "type": "uint256" + }, + { + "indexed": false, + "name": "CRS", + "type": "bytes32" + } + ], + "name": "CRSProposed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" + }, + { + "indexed": true, + "name": "NewOwnerAddress", + "type": "address" + } + ], + "name": "NodeOwnershipTransfered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" + }, + { + "indexed": false, + "name": "PublicKey", + "type": "bytes" + } + ], + "name": "NodePublicKeyReplaced", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" + }, + { + "indexed": false, + "name": "Amount", + "type": "uint256" + } + ], + "name": "Staked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" + }, + { + "indexed": false, + "name": "Amount", + "type": "uint256" + } + ], + "name": "Unstaked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" + }, + { + "indexed": false, + "name": "Amount", + "type": "uint256" + } + ], + "name": "Withdrawn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" + } + ], + "name": "NodeAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" + } + ], + "name": "NodeRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" + }, + { + "indexed": false, + "name": "Type", + "type": "uint256" + }, + { + "indexed": false, + "name": "Arg1", + "type": "bytes" + }, + { + "indexed": false, + "name": "Arg2", + "type": "bytes" + } + ], + "name": "Reported", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" + }, + { + "indexed": false, + "name": "Amount", + "type": "uint256" + } + ], + "name": "Fined", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" + }, + { + "indexed": false, + "name": "Amount", + "type": "uint256" + } + ], + "name": "FinePaid", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "Round", + "type": "uint256" + }, + { + "indexed": false, + "name": "BlockHeight", + "type": "uint256" + } + ], + "name": "DKGReset", + "type": "event" + }, + { + "constant": false, + "inputs": [ + { + "name": "NewOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "MinStake", + "type": "uint256" + }, + { + "name": "LockupPeriod", + "type": "uint256" + }, + { + "name": "MinGasPrice", + "type": "uint256" + }, + { + "name": "BlockGasLimit", + "type": "uint256" + }, + { + "name": "LambdaBA", + "type": "uint256" + }, + { + "name": "LambdaDKG", + "type": "uint256" + }, + { + "name": "NotaryParamAlpha", + "type": "uint256" + }, + { + "name": "NotaryParamBeta", + "type": "uint256" + }, + { + "name": "RoundLength", + "type": "uint256" + }, + { + "name": "MinBlockInterval", + "type": "uint256" + }, + { + "name": "FineValues", + "type": "uint256[]" + } + ], + "name": "updateConfiguration", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "NewOwner", + "type": "address" + } + ], + "name": "transferNodeOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "OldOwner", + "type": "address" + }, + { + "name": "NewOwner", + "type": "address" + } + ], + "name": "transferNodeOwnershipByFoundation", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "NewPublicKey", + "type": "bytes" + } + ], + "name": "replaceNodePublicKey", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "nodesLength", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "Round", + "type": "uint256" + }, + { + "name": "SignedCRS", + "type": "bytes" + } + ], + "name": "proposeCRS", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "Complaint", + "type": "bytes" + } + ], + "name": "addDKGComplaint", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "PublicKey", + "type": "bytes" + } + ], + "name": "addDKGMasterPublicKey", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "MPKReady", + "type": "bytes" + } + ], + "name": "addDKGMPKReady", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "Finalize", + "type": "bytes" + } + ], + "name": "addDKGFinalize", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "Success", + "type": "bytes" + } + ], + "name": "addDKGSuccess", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "PublicKey", + "type": "bytes" + }, + { + "name": "Name", + "type": "string" + }, + { + "name": "Email", + "type": "string" + }, + { + "name": "Location", + "type": "string" + }, + { + "name": "Url", + "type": "string" + } + ], + "name": "register", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "stake", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "Amount", + "type": "uint256" + } + ], + "name": "unstake", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "withdraw", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "withdrawable", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "NodeAddress", + "type": "address" + } + ], + "name": "payFine", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "Type", + "type": "uint256" + }, + { + "name": "Arg1", + "type": "bytes" + }, + { + "name": "Arg2", + "type": "bytes" + } + ], + "name": "report", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "NewSignedCRS", + "type": "bytes" + } + ], + "name": "resetDKG", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } +] +` diff --git a/core/vm/evm/oracle_contracts.go b/core/vm/evm/oracle_contracts.go new file mode 100644 index 000000000..4a13198e2 --- /dev/null +++ b/core/vm/evm/oracle_contracts.go @@ -0,0 +1,2885 @@ +// Copyright 2018 The dexon-consensus Authors +// This file is part of the dexon-consensus library. +// +// The dexon-consensus library is free software: you can redistribute it +// and/or modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation, either version 3 of the License, +// or (at your option) any later version. +// +// The dexon-consensus library is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +// General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the dexon-consensus library. If not, see +// . + +package evm + +import ( + "bytes" + "errors" + "fmt" + "math" + "math/big" + "sort" + "sync/atomic" + + "github.com/dexon-foundation/dexon/accounts/abi" + "github.com/dexon-foundation/dexon/common" + "github.com/dexon-foundation/dexon/core/types" + "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/crypto" + "github.com/dexon-foundation/dexon/params" + "github.com/dexon-foundation/dexon/rlp" + + coreCommon "github.com/dexon-foundation/dexon-consensus/common" + dexCore "github.com/dexon-foundation/dexon-consensus/core" + coreCrypto "github.com/dexon-foundation/dexon-consensus/core/crypto" + coreUtils "github.com/dexon-foundation/dexon-consensus/core/utils" + + "github.com/dexon-foundation/dexon-consensus/core/crypto/ecdsa" + coreTypes "github.com/dexon-foundation/dexon-consensus/core/types" + dkgTypes "github.com/dexon-foundation/dexon-consensus/core/types/dkg" +) + +type Bytes32 [32]byte + +type FineType uint64 + +const ( + FineTypeFailStop = iota + FineTypeFailStopDKG + FineTypeInvalidDKG + FineTypeForkVote + FineTypeForkBlock +) + +const GovernanceActionGasCost = 200000 + +// Storage position enums. +const ( + roundHeightLoc = iota + totalSupplyLoc + totalStakedLoc + nodesLoc + nodesOffsetByAddressLoc + nodesOffsetByNodeKeyAddressLoc + lastProposedHeightLoc + crsRoundLoc + crsLoc + dkgRoundLoc + dkgResetCountLoc + dkgMasterPublicKeysLoc + dkgMasterPublicKeyOffsetLoc + dkgComplaintsLoc + dkgComplaintsProposedLoc + dkgReadyLoc + dkgReadysCountLoc + dkgFinalizedLoc + dkgFinalizedsCountLoc + dkgSuccessLoc + dkgSuccessesCountLoc + ownerLoc + minStakeLoc + lockupPeriodLoc + miningVelocityLoc + nextHalvingSupplyLoc + lastHalvedAmountLoc + minGasPriceLoc + blockGasLimitLoc + lambdaBALoc + lambdaDKGLoc + notarySetSizeLoc + notaryParamAlphaLoc + notaryParamBetaLoc + roundLengthLoc + minBlockIntervalLoc + fineValuesLoc + finedRecordsLoc +) + +func publicKeyToNodeKeyAddress(pkBytes []byte) (common.Address, error) { + pk, err := crypto.UnmarshalPubkey(pkBytes) + if err != nil { + return common.Address{}, err + } + return crypto.PubkeyToAddress(*pk), nil +} + +func getDKGMasterPublicKeyID(mpk *dkgTypes.MasterPublicKey) Bytes32 { + return Bytes32(mpk.ProposerID.Hash) +} + +func getDKGComplaintID(comp *dkgTypes.Complaint) Bytes32 { + return Bytes32(crypto.Keccak256Hash( + comp.ProposerID.Hash[:], + comp.PrivateShare.ProposerID.Hash[:], + []byte(fmt.Sprintf("%v", comp.IsNack())))) +} + +func IdToAddress(id coreTypes.NodeID) common.Address { + return common.BytesToAddress(id.Hash[12:]) +} + +// State manipulation helper fro the governance contract. +type GovernanceState struct { + StateDB vm.StateDB +} + +func (s *GovernanceState) getState(loc common.Hash) common.Hash { + return s.StateDB.GetState(GovernanceContractAddress, loc) +} + +func (s *GovernanceState) setState(loc common.Hash, val common.Hash) { + s.StateDB.SetState(GovernanceContractAddress, loc, val) +} + +func (s *GovernanceState) getStateBigInt(loc *big.Int) *big.Int { + res := s.StateDB.GetState(GovernanceContractAddress, common.BigToHash(loc)) + return new(big.Int).SetBytes(res.Bytes()) +} + +func (s *GovernanceState) setStateBigInt(loc *big.Int, val *big.Int) { + s.setState(common.BigToHash(loc), common.BigToHash(val)) +} + +func (s *GovernanceState) getSlotLoc(loc *big.Int) *big.Int { + return new(big.Int).SetBytes(crypto.Keccak256(common.BigToHash(loc).Bytes())) +} + +func (s *GovernanceState) getMapLoc(pos *big.Int, key []byte) *big.Int { + return new(big.Int).SetBytes(crypto.Keccak256(key, common.BigToHash(pos).Bytes())) +} + +func (s *GovernanceState) readBytes(loc *big.Int) []byte { + // Length of the dynamic array (bytes). + rawLength := s.getStateBigInt(loc) + lengthByte := new(big.Int).Mod(rawLength, big.NewInt(256)) + + // Bytes length <= 31, lengthByte % 2 == 0 + // return the high 31 bytes. + if new(big.Int).Mod(lengthByte, big.NewInt(2)).Cmp(big.NewInt(0)) == 0 { + length := new(big.Int).Div(lengthByte, big.NewInt(2)).Uint64() + return rawLength.Bytes()[:length] + } + + // Actual length = (rawLength - 1) / 2 + length := new(big.Int).Div(new(big.Int).Sub(rawLength, big.NewInt(1)), big.NewInt(2)).Uint64() + + // Data address. + dataLoc := s.getSlotLoc(loc) + + // Read continuously for length bytes. + carry := int64(0) + if length%32 > 0 { + carry = 1 + } + chunks := int64(length/32) + carry + var data []byte + for i := int64(0); i < chunks; i++ { + loc = new(big.Int).Add(dataLoc, big.NewInt(i)) + data = append(data, s.getState(common.BigToHash(loc)).Bytes()...) + } + data = data[:length] + return data +} + +func (s *GovernanceState) writeBytes(loc *big.Int, data []byte) { + length := int64(len(data)) + + if length == 0 { + s.setState(common.BigToHash(loc), common.Hash{}) + return + } + + // Short bytes (length <= 31). + if length < 32 { + data2 := append([]byte(nil), data...) + // Right pad with zeros + for len(data2) < 31 { + data2 = append(data2, byte(0)) + } + data2 = append(data2, byte(length*2)) + s.setState(common.BigToHash(loc), common.BytesToHash(data2)) + return + } + + // Write 2 * length + 1. + storedLength := new(big.Int).Add(new(big.Int).Mul( + big.NewInt(length), big.NewInt(2)), big.NewInt(1)) + s.setStateBigInt(loc, storedLength) + // Write data chunck. + dataLoc := s.getSlotLoc(loc) + carry := int64(0) + if length%32 > 0 { + carry = 1 + } + chunks := length/32 + carry + for i := int64(0); i < chunks; i++ { + loc = new(big.Int).Add(dataLoc, big.NewInt(i)) + maxLoc := (i + 1) * 32 + if maxLoc > length { + maxLoc = length + } + data2 := data[i*32 : maxLoc] + // Right pad with zeros. + for len(data2) < 32 { + data2 = append(data2, byte(0)) + } + s.setState(common.BigToHash(loc), common.BytesToHash(data2)) + } +} + +func (s *GovernanceState) eraseBytes(loc *big.Int) { + // Length of the dynamic array (bytes). + rawLength := s.getStateBigInt(loc) + lengthByte := new(big.Int).Mod(rawLength, big.NewInt(256)) + + // Bytes length <= 31, lengthByte % 2 == 0 + // return the high 31 bytes. + if new(big.Int).Mod(lengthByte, big.NewInt(2)).Cmp(big.NewInt(0)) == 0 { + s.setStateBigInt(loc, big.NewInt(0)) + return + } + + // Actual length = (rawLength - 1) / 2 + length := new(big.Int).Div(new(big.Int).Sub( + rawLength, big.NewInt(1)), big.NewInt(2)).Uint64() + + // Fill 0. + s.writeBytes(loc, make([]byte, length)) + + // Clear slot. + s.setStateBigInt(loc, big.NewInt(0)) +} + +func (s *GovernanceState) read1DByteArray(loc *big.Int) [][]byte { + arrayLength := s.getStateBigInt(loc) + dataLoc := s.getSlotLoc(loc) + + data := [][]byte{} + for i := int64(0); i < int64(arrayLength.Uint64()); i++ { + elementLoc := new(big.Int).Add(dataLoc, big.NewInt(i)) + data = append(data, s.readBytes(elementLoc)) + } + return data +} + +func (s *GovernanceState) appendTo1DByteArray(loc *big.Int, data []byte) { + // Increase length by 1. + arrayLength := s.getStateBigInt(loc) + s.setStateBigInt(loc, new(big.Int).Add(arrayLength, big.NewInt(1))) + + // Write element. + dataLoc := s.getSlotLoc(loc) + elementLoc := new(big.Int).Add(dataLoc, arrayLength) + s.writeBytes(elementLoc, data) +} + +func (s *GovernanceState) erase1DByteArray(loc *big.Int) { + arrayLength := s.getStateBigInt(loc) + dataLoc := s.getSlotLoc(loc) + + for i := int64(0); i < int64(arrayLength.Uint64()); i++ { + elementLoc := new(big.Int).Add(dataLoc, big.NewInt(i)) + s.eraseBytes(elementLoc) + } + s.setStateBigInt(loc, big.NewInt(0)) +} + +// uint256[] public roundHeight; +func (s *GovernanceState) RoundHeight(round *big.Int) *big.Int { + baseLoc := s.getSlotLoc(big.NewInt(roundHeightLoc)) + loc := new(big.Int).Add(baseLoc, round) + return s.getStateBigInt(loc) +} +func (s *GovernanceState) PushRoundHeight(height *big.Int) { + // Increase length by 1. + length := s.getStateBigInt(big.NewInt(roundHeightLoc)) + s.setStateBigInt(big.NewInt(roundHeightLoc), new(big.Int).Add(length, big.NewInt(1))) + + baseLoc := s.getSlotLoc(big.NewInt(roundHeightLoc)) + loc := new(big.Int).Add(baseLoc, length) + + s.setStateBigInt(loc, height) +} + +// uint256 public totalSupply; +func (s *GovernanceState) TotalSupply() *big.Int { + return s.getStateBigInt(big.NewInt(totalSupplyLoc)) +} +func (s *GovernanceState) IncTotalSupply(amount *big.Int) { + s.setStateBigInt(big.NewInt(totalSupplyLoc), new(big.Int).Add(s.TotalSupply(), amount)) +} +func (s *GovernanceState) DecTotalSupply(amount *big.Int) { + s.setStateBigInt(big.NewInt(totalSupplyLoc), new(big.Int).Sub(s.TotalSupply(), amount)) +} + +// uint256 public totalStaked; +func (s *GovernanceState) TotalStaked() *big.Int { + return s.getStateBigInt(big.NewInt(totalStakedLoc)) +} +func (s *GovernanceState) IncTotalStaked(amount *big.Int) { + s.setStateBigInt(big.NewInt(totalStakedLoc), new(big.Int).Add(s.TotalStaked(), amount)) +} +func (s *GovernanceState) DecTotalStaked(amount *big.Int) { + s.setStateBigInt(big.NewInt(totalStakedLoc), new(big.Int).Sub(s.TotalStaked(), amount)) +} + +// struct Node { +// address owner; +// bytes publicKey; +// uint256 staked; +// uint256 fined; +// string name; +// string email; +// string location; +// string url; +// uint256 unstaked; +// uint256 unstakedAt; +// uint256 lastProposedHeight; +// } +// +// Node[] nodes; + +type nodeInfo struct { + Owner common.Address + PublicKey []byte + Staked *big.Int + Fined *big.Int + Name string + Email string + Location string + Url string + Unstaked *big.Int + UnstakedAt *big.Int +} + +const nodeStructSize = 10 + +func (s *GovernanceState) LenNodes() *big.Int { + return s.getStateBigInt(big.NewInt(nodesLoc)) +} +func (s *GovernanceState) Node(index *big.Int) *nodeInfo { + node := new(nodeInfo) + + arrayBaseLoc := s.getSlotLoc(big.NewInt(nodesLoc)) + elementBaseLoc := new(big.Int).Add(arrayBaseLoc, + new(big.Int).Mul(index, big.NewInt(nodeStructSize))) + + // Owner. + loc := elementBaseLoc + node.Owner = common.BytesToAddress(s.getState(common.BigToHash(elementBaseLoc)).Bytes()) + + // PublicKey. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(1)) + node.PublicKey = s.readBytes(loc) + + // Staked. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(2)) + node.Staked = s.getStateBigInt(loc) + + // Fined. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(3)) + node.Fined = s.getStateBigInt(loc) + + // Name. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(4)) + node.Name = string(s.readBytes(loc)) + + // Email. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(5)) + node.Email = string(s.readBytes(loc)) + + // Location. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(6)) + node.Location = string(s.readBytes(loc)) + + // Url. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(7)) + node.Url = string(s.readBytes(loc)) + + // Unstaked. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(8)) + node.Unstaked = s.getStateBigInt(loc) + + // UnstakedAt. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(9)) + node.UnstakedAt = s.getStateBigInt(loc) + + return node +} +func (s *GovernanceState) PushNode(n *nodeInfo) { + // Increase length by 1. + arrayLength := s.LenNodes() + s.setStateBigInt(big.NewInt(nodesLoc), new(big.Int).Add(arrayLength, big.NewInt(1))) + + s.UpdateNode(arrayLength, n) +} +func (s *GovernanceState) UpdateNode(index *big.Int, n *nodeInfo) { + arrayBaseLoc := s.getSlotLoc(big.NewInt(nodesLoc)) + elementBaseLoc := new(big.Int).Add(arrayBaseLoc, + new(big.Int).Mul(index, big.NewInt(nodeStructSize))) + + // Owner. + loc := elementBaseLoc + s.setState(common.BigToHash(loc), n.Owner.Hash()) + + // PublicKey. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(1)) + s.writeBytes(loc, n.PublicKey) + + // Staked. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(2)) + s.setStateBigInt(loc, n.Staked) + + // Fined. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(3)) + s.setStateBigInt(loc, n.Fined) + + // Name. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(4)) + s.writeBytes(loc, []byte(n.Name)) + + // Email. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(5)) + s.writeBytes(loc, []byte(n.Email)) + + // Location. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(6)) + s.writeBytes(loc, []byte(n.Location)) + + // Url. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(7)) + s.writeBytes(loc, []byte(n.Url)) + + // Unstaked. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(8)) + s.setStateBigInt(loc, n.Unstaked) + + // UnstakedAt. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(9)) + s.setStateBigInt(loc, n.UnstakedAt) + + // Update set size. + s.CalNotarySetSize() +} +func (s *GovernanceState) PopLastNode() { + // Decrease length by 1. + arrayLength := s.LenNodes() + newArrayLength := new(big.Int).Sub(arrayLength, big.NewInt(1)) + s.setStateBigInt(big.NewInt(nodesLoc), newArrayLength) + + s.UpdateNode(newArrayLength, &nodeInfo{ + Staked: big.NewInt(0), + Fined: big.NewInt(0), + Unstaked: big.NewInt(0), + UnstakedAt: big.NewInt(0), + }) +} +func (s *GovernanceState) Nodes() []*nodeInfo { + var nodes []*nodeInfo + for i := int64(0); i < int64(s.LenNodes().Uint64()); i++ { + nodes = append(nodes, s.Node(big.NewInt(i))) + } + return nodes +} +func (s *GovernanceState) QualifiedNodes() []*nodeInfo { + var nodes []*nodeInfo + for i := int64(0); i < int64(s.LenNodes().Uint64()); i++ { + node := s.Node(big.NewInt(i)) + // Node with unpaid fine is consider unqualified. + if node.Fined.Cmp(big.NewInt(0)) > 0 { + continue + } + if node.Staked.Cmp(s.MinStake()) >= 0 { + nodes = append(nodes, node) + } + } + return nodes +} + +// mapping(address => uint256) public nodesOffsetByAddress; +func (s *GovernanceState) NodesOffsetByAddress(addr common.Address) *big.Int { + loc := s.getMapLoc(big.NewInt(nodesOffsetByAddressLoc), addr.Bytes()) + return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1)) +} +func (s *GovernanceState) PutNodesOffsetByAddress(addr common.Address, offset *big.Int) { + loc := s.getMapLoc(big.NewInt(nodesOffsetByAddressLoc), addr.Bytes()) + s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1))) +} +func (s *GovernanceState) DeleteNodesOffsetByAddress(addr common.Address) { + loc := s.getMapLoc(big.NewInt(nodesOffsetByAddressLoc), addr.Bytes()) + s.setStateBigInt(loc, big.NewInt(0)) +} + +// mapping(address => uint256) public nodesOffsetByNodeKeyAddress; +func (s *GovernanceState) NodesOffsetByNodeKeyAddress(addr common.Address) *big.Int { + loc := s.getMapLoc(big.NewInt(nodesOffsetByNodeKeyAddressLoc), addr.Bytes()) + return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1)) +} +func (s *GovernanceState) PutNodesOffsetByNodeKeyAddress(addr common.Address, offset *big.Int) { + loc := s.getMapLoc(big.NewInt(nodesOffsetByNodeKeyAddressLoc), addr.Bytes()) + s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1))) +} +func (s *GovernanceState) DeleteNodesOffsetByNodeKeyAddress(addr common.Address) { + loc := s.getMapLoc(big.NewInt(nodesOffsetByNodeKeyAddressLoc), addr.Bytes()) + s.setStateBigInt(loc, big.NewInt(0)) +} + +func (s *GovernanceState) PutNodeOffsets(n *nodeInfo, offset *big.Int) { + address, err := publicKeyToNodeKeyAddress(n.PublicKey) + if err != nil { + panic(err) + } + s.PutNodesOffsetByNodeKeyAddress(address, offset) + s.PutNodesOffsetByAddress(n.Owner, offset) +} +func (s *GovernanceState) DeleteNodeOffsets(n *nodeInfo) { + address, err := publicKeyToNodeKeyAddress(n.PublicKey) + if err != nil { + panic(err) + } + s.DeleteNodesOffsetByNodeKeyAddress(address) + s.DeleteNodesOffsetByAddress(n.Owner) +} + +func (s *GovernanceState) GetNodeByID(id coreTypes.NodeID) (*nodeInfo, error) { + offset := s.NodesOffsetByNodeKeyAddress(IdToAddress(id)) + if offset.Cmp(big.NewInt(0)) < 0 { + return nil, errors.New("node not found") + } + node := s.Node(offset) + return node, nil +} + +// mapping(address => uint256) public lastProposedHeight; +func (s *GovernanceState) LastProposedHeight(addr common.Address) *big.Int { + loc := s.getMapLoc(big.NewInt(lastProposedHeightLoc), addr.Bytes()) + return s.getStateBigInt(loc) +} +func (s *GovernanceState) PutLastProposedHeight(addr common.Address, height *big.Int) { + loc := s.getMapLoc(big.NewInt(lastProposedHeightLoc), addr.Bytes()) + s.setStateBigInt(loc, height) +} + +// uint256 public crsRound; +func (s *GovernanceState) CRSRound() *big.Int { + return s.getStateBigInt(big.NewInt(crsRoundLoc)) +} +func (s *GovernanceState) SetCRSRound(round *big.Int) { + s.setStateBigInt(big.NewInt(crsRoundLoc), round) +} + +// bytes32 public crs; +func (s *GovernanceState) CRS() common.Hash { + return s.getState(common.BigToHash(big.NewInt(crsLoc))) +} +func (s *GovernanceState) SetCRS(crs common.Hash) { + s.setState(common.BigToHash(big.NewInt(crsLoc)), crs) +} + +// uint256 public dkgRound; +func (s *GovernanceState) DKGRound() *big.Int { + return s.getStateBigInt(big.NewInt(dkgRoundLoc)) +} +func (s *GovernanceState) SetDKGRound(round *big.Int) { + s.setStateBigInt(big.NewInt(dkgRoundLoc), round) +} + +// uint256[] public dkgResetCount; +func (s *GovernanceState) DKGResetCount(round *big.Int) *big.Int { + arrayBaseLoc := s.getSlotLoc(big.NewInt(dkgResetCountLoc)) + return s.getStateBigInt(new(big.Int).Add(arrayBaseLoc, round)) +} +func (s *GovernanceState) IncDKGResetCount(round *big.Int) { + loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgResetCountLoc)), round) + count := s.getStateBigInt(loc) + s.setStateBigInt(loc, new(big.Int).Add(count, big.NewInt(1))) +} + +// bytes[] public dkgMasterPublicKeys; +func (s *GovernanceState) LenDKGMasterPublicKeys() *big.Int { + return s.getStateBigInt(big.NewInt(dkgMasterPublicKeysLoc)) +} +func (s *GovernanceState) DKGMasterPublicKey(offset *big.Int) []byte { + loc := big.NewInt(dkgMasterPublicKeysLoc) + dataLoc := s.getSlotLoc(loc) + elementLoc := new(big.Int).Add(dataLoc, offset) + return s.readBytes(elementLoc) +} +func (s *GovernanceState) DKGMasterPublicKeyItem(offset *big.Int) *dkgTypes.MasterPublicKey { + element := s.DKGMasterPublicKey(offset) + x := new(dkgTypes.MasterPublicKey) + if err := rlp.DecodeBytes(element, x); err != nil { + panic(err) + } + return x +} +func (s *GovernanceState) DKGMasterPublicKeys() [][]byte { + return s.read1DByteArray(big.NewInt(dkgMasterPublicKeysLoc)) +} +func (s *GovernanceState) PushDKGMasterPublicKey(mpk []byte) { + s.appendTo1DByteArray(big.NewInt(dkgMasterPublicKeysLoc), mpk) +} +func (s *GovernanceState) DKGMasterPublicKeyItems() []*dkgTypes.MasterPublicKey { + // Prepare DKGMasterPublicKeys. + var dkgMasterPKs []*dkgTypes.MasterPublicKey + for _, mpk := range s.DKGMasterPublicKeys() { + x := new(dkgTypes.MasterPublicKey) + if err := rlp.DecodeBytes(mpk, x); err != nil { + panic(err) + } + dkgMasterPKs = append(dkgMasterPKs, x) + } + return dkgMasterPKs +} +func (s *GovernanceState) ClearDKGMasterPublicKeys() { + s.erase1DByteArray(big.NewInt(dkgMasterPublicKeysLoc)) +} + +// mapping(bytes32 => uint256) public dkgMasterPublicKeyOffset; +func (s *GovernanceState) DKGMasterPublicKeyOffset(id Bytes32) *big.Int { + loc := s.getMapLoc(big.NewInt(dkgMasterPublicKeyOffsetLoc), id[:]) + return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1)) +} +func (s *GovernanceState) PutDKGMasterPublicKeyOffset(id Bytes32, offset *big.Int) { + loc := s.getMapLoc(big.NewInt(dkgMasterPublicKeyOffsetLoc), id[:]) + s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1))) +} +func (s *GovernanceState) ClearDKGMasterPublicKeyOffset() { + for _, mpk := range s.DKGMasterPublicKeyItems() { + s.PutDKGMasterPublicKeyOffset(getDKGMasterPublicKeyID(mpk), big.NewInt(-1)) + } +} + +// bytes[] public dkgComplaints; +func (s *GovernanceState) LenDKGComplaints() *big.Int { + return s.getStateBigInt(big.NewInt(dkgComplaintsLoc)) +} +func (s *GovernanceState) DKGComplaint(offset *big.Int) []byte { + loc := big.NewInt(dkgComplaintsLoc) + dataLoc := s.getSlotLoc(loc) + elementLoc := new(big.Int).Add(dataLoc, offset) + return s.readBytes(elementLoc) +} +func (s *GovernanceState) DKGComplaints() [][]byte { + return s.read1DByteArray(big.NewInt(dkgComplaintsLoc)) +} +func (s *GovernanceState) PushDKGComplaint(complaint []byte) { + s.appendTo1DByteArray(big.NewInt(dkgComplaintsLoc), complaint) +} +func (s *GovernanceState) ClearDKGComplaints() { + s.erase1DByteArray(big.NewInt(dkgComplaintsLoc)) +} +func (s *GovernanceState) DKGComplaintItems() []*dkgTypes.Complaint { + var dkgComplaints []*dkgTypes.Complaint + for _, pk := range s.DKGComplaints() { + x := new(dkgTypes.Complaint) + if err := rlp.DecodeBytes(pk, x); err != nil { + panic(err) + } + dkgComplaints = append(dkgComplaints, x) + } + return dkgComplaints +} + +// mapping(bytes32 => bool) public dkgComplaintsProposed; +func (s *GovernanceState) DKGComplaintProposed(id Bytes32) bool { + loc := s.getMapLoc(big.NewInt(dkgComplaintsProposedLoc), id[:]) + return s.getStateBigInt(loc).Cmp(big.NewInt(0)) > 0 +} +func (s *GovernanceState) PutDKGComplaintProposed(id Bytes32, status bool) { + loc := s.getMapLoc(big.NewInt(dkgComplaintsProposedLoc), id[:]) + val := big.NewInt(0) + if status { + val = big.NewInt(1) + } + s.setStateBigInt(loc, val) +} +func (s *GovernanceState) ClearDKGComplaintProposed() { + for _, comp := range s.DKGComplaintItems() { + s.PutDKGComplaintProposed(getDKGComplaintID(comp), false) + } +} + +// mapping(address => bool) public dkgMPKReadys; +func (s *GovernanceState) DKGMPKReady(addr common.Address) bool { + mapLoc := s.getMapLoc(big.NewInt(dkgReadyLoc), addr.Bytes()) + return s.getStateBigInt(mapLoc).Cmp(big.NewInt(0)) != 0 +} +func (s *GovernanceState) PutDKGMPKReady(addr common.Address, ready bool) { + mapLoc := s.getMapLoc(big.NewInt(dkgReadyLoc), addr.Bytes()) + res := big.NewInt(0) + if ready { + res = big.NewInt(1) + } + s.setStateBigInt(mapLoc, res) +} +func (s *GovernanceState) ClearDKGMPKReadys(notarySet map[coreTypes.NodeID]struct{}) { + for id := range notarySet { + s.PutDKGMPKReady(IdToAddress(id), false) + } +} + +// uint256 public dkgMPKReadysCount; +func (s *GovernanceState) DKGMPKReadysCount() *big.Int { + return s.getStateBigInt(big.NewInt(dkgReadysCountLoc)) +} +func (s *GovernanceState) IncDKGMPKReadysCount() { + s.setStateBigInt(big.NewInt(dkgReadysCountLoc), + new(big.Int).Add(s.getStateBigInt(big.NewInt(dkgReadysCountLoc)), big.NewInt(1))) +} +func (s *GovernanceState) ResetDKGMPKReadysCount() { + s.setStateBigInt(big.NewInt(dkgReadysCountLoc), big.NewInt(0)) +} + +// mapping(address => bool) public dkgFinalizeds; +func (s *GovernanceState) DKGFinalized(addr common.Address) bool { + mapLoc := s.getMapLoc(big.NewInt(dkgFinalizedLoc), addr.Bytes()) + return s.getStateBigInt(mapLoc).Cmp(big.NewInt(0)) != 0 +} +func (s *GovernanceState) PutDKGFinalized(addr common.Address, finalized bool) { + mapLoc := s.getMapLoc(big.NewInt(dkgFinalizedLoc), addr.Bytes()) + res := big.NewInt(0) + if finalized { + res = big.NewInt(1) + } + s.setStateBigInt(mapLoc, res) +} +func (s *GovernanceState) ClearDKGFinalizeds(dkgSet map[coreTypes.NodeID]struct{}) { + for id := range dkgSet { + s.PutDKGFinalized(IdToAddress(id), false) + } +} + +// uint256 public dkgFinalizedsCount; +func (s *GovernanceState) DKGFinalizedsCount() *big.Int { + return s.getStateBigInt(big.NewInt(dkgFinalizedsCountLoc)) +} +func (s *GovernanceState) IncDKGFinalizedsCount() { + s.setStateBigInt(big.NewInt(dkgFinalizedsCountLoc), + new(big.Int).Add(s.getStateBigInt(big.NewInt(dkgFinalizedsCountLoc)), big.NewInt(1))) +} +func (s *GovernanceState) ResetDKGFinalizedsCount() { + s.setStateBigInt(big.NewInt(dkgFinalizedsCountLoc), big.NewInt(0)) +} + +// mapping(address => bool) public dkgSuccesses; +func (s *GovernanceState) DKGSuccess(addr common.Address) bool { + mapLoc := s.getMapLoc(big.NewInt(dkgSuccessLoc), addr.Bytes()) + return s.getStateBigInt(mapLoc).Cmp(big.NewInt(0)) != 0 +} +func (s *GovernanceState) PutDKGSuccess(addr common.Address, success bool) { + mapLoc := s.getMapLoc(big.NewInt(dkgSuccessLoc), addr.Bytes()) + res := big.NewInt(0) + if success { + res = big.NewInt(1) + } + s.setStateBigInt(mapLoc, res) +} +func (s *GovernanceState) ClearDKGSuccesses(dkgSet map[coreTypes.NodeID]struct{}) { + for id := range dkgSet { + s.PutDKGSuccess(IdToAddress(id), false) + } +} + +// uint256 public dkgSuccessesCount; +func (s *GovernanceState) DKGSuccessesCount() *big.Int { + return s.getStateBigInt(big.NewInt(dkgSuccessesCountLoc)) +} +func (s *GovernanceState) IncDKGSuccessesCount() { + s.setStateBigInt(big.NewInt(dkgSuccessesCountLoc), + new(big.Int).Add(s.getStateBigInt(big.NewInt(dkgSuccessesCountLoc)), big.NewInt(1))) +} +func (s *GovernanceState) ResetDKGSuccessesCount() { + s.setStateBigInt(big.NewInt(dkgSuccessesCountLoc), big.NewInt(0)) +} + +// address public owner; +func (s *GovernanceState) Owner() common.Address { + val := s.getState(common.BigToHash(big.NewInt(ownerLoc))) + return common.BytesToAddress(val.Bytes()) +} +func (s *GovernanceState) SetOwner(newOwner common.Address) { + s.setState(common.BigToHash(big.NewInt(ownerLoc)), newOwner.Hash()) +} + +// uint256 public minStake; +func (s *GovernanceState) MinStake() *big.Int { + return s.getStateBigInt(big.NewInt(minStakeLoc)) +} + +// uint256 public lockupPeriod; +func (s *GovernanceState) LockupPeriod() *big.Int { + return s.getStateBigInt(big.NewInt(lockupPeriodLoc)) +} + +// uint256 public miningVelocity; +func (s *GovernanceState) MiningVelocity() *big.Int { + return s.getStateBigInt(big.NewInt(miningVelocityLoc)) +} +func (s *GovernanceState) HalfMiningVelocity() { + s.setStateBigInt(big.NewInt(miningVelocityLoc), + new(big.Int).Div(s.MiningVelocity(), big.NewInt(2))) +} + +// uint256 public nextHalvingSupply; +func (s *GovernanceState) NextHalvingSupply() *big.Int { + return s.getStateBigInt(big.NewInt(nextHalvingSupplyLoc)) +} +func (s *GovernanceState) IncNextHalvingSupply(amount *big.Int) { + s.setStateBigInt(big.NewInt(nextHalvingSupplyLoc), + new(big.Int).Add(s.NextHalvingSupply(), amount)) +} + +// uint256 public lastHalvedAmount; +func (s *GovernanceState) LastHalvedAmount() *big.Int { + return s.getStateBigInt(big.NewInt(lastHalvedAmountLoc)) +} +func (s *GovernanceState) HalfLastHalvedAmount() { + s.setStateBigInt(big.NewInt(lastHalvedAmountLoc), + new(big.Int).Div(s.LastHalvedAmount(), big.NewInt(2))) +} +func (s *GovernanceState) MiningHalved() { + s.HalfMiningVelocity() + s.HalfLastHalvedAmount() + s.IncNextHalvingSupply(s.LastHalvedAmount()) +} + +// uint256 public minGasPrice; +func (s *GovernanceState) MinGasPrice() *big.Int { + return s.getStateBigInt(big.NewInt(minGasPriceLoc)) +} + +// uint256 public blockGasLimit; +func (s *GovernanceState) BlockGasLimit() *big.Int { + return s.getStateBigInt(big.NewInt(blockGasLimitLoc)) +} +func (s *GovernanceState) SetBlockGasLimit(reward *big.Int) { + s.setStateBigInt(big.NewInt(blockGasLimitLoc), reward) +} + +// uint256 public lambdaBA; +func (s *GovernanceState) LambdaBA() *big.Int { + return s.getStateBigInt(big.NewInt(lambdaBALoc)) +} + +// uint256 public lambdaDKG; +func (s *GovernanceState) LambdaDKG() *big.Int { + return s.getStateBigInt(big.NewInt(lambdaDKGLoc)) +} + +// uint256 public notarySetSize; +func (s *GovernanceState) NotarySetSize() *big.Int { + return s.getStateBigInt(big.NewInt(notarySetSizeLoc)) +} +func (s *GovernanceState) CalNotarySetSize() { + nodeSetSize := float64(len(s.QualifiedNodes())) + setSize := math.Ceil((nodeSetSize*0.6-1)/3)*3 + 1 + + if nodeSetSize >= 80 { + alpha := float64(s.NotaryParamAlpha().Uint64()) / decimalMultiplier + beta := float64(s.NotaryParamBeta().Uint64()) / decimalMultiplier + setSize = math.Ceil(alpha*math.Log(nodeSetSize) - beta) + } + s.setStateBigInt(big.NewInt(notarySetSizeLoc), big.NewInt(int64(setSize))) +} + +// uint256 public notaryParamAlpha; +func (s *GovernanceState) NotaryParamAlpha() *big.Int { + return s.getStateBigInt(big.NewInt(notaryParamAlphaLoc)) +} + +// uint256 public notaryParamBeta; +func (s *GovernanceState) NotaryParamBeta() *big.Int { + return s.getStateBigInt(big.NewInt(notaryParamBetaLoc)) +} + +// uint256 public roundLength; +func (s *GovernanceState) RoundLength() *big.Int { + return s.getStateBigInt(big.NewInt(roundLengthLoc)) +} + +// uint256 public minBlockInterval; +func (s *GovernanceState) MinBlockInterval() *big.Int { + return s.getStateBigInt(big.NewInt(minBlockIntervalLoc)) +} + +// uint256[] public fineValues; +func (s *GovernanceState) FineValue(index *big.Int) *big.Int { + arrayBaseLoc := s.getSlotLoc(big.NewInt(fineValuesLoc)) + return s.getStateBigInt(new(big.Int).Add(arrayBaseLoc, index)) +} +func (s *GovernanceState) FineValues() []*big.Int { + len := s.getStateBigInt(big.NewInt(fineValuesLoc)) + result := make([]*big.Int, len.Uint64()) + for i := 0; i < int(len.Uint64()); i++ { + result[i] = s.FineValue(big.NewInt(int64(i))) + } + return result +} +func (s *GovernanceState) SetFineValues(values []*big.Int) { + s.setStateBigInt(big.NewInt(fineValuesLoc), big.NewInt(int64(len(values)))) + + arrayBaseLoc := s.getSlotLoc(big.NewInt(fineValuesLoc)) + for i, v := range values { + s.setStateBigInt(new(big.Int).Add(arrayBaseLoc, big.NewInt(int64(i))), v) + } +} + +// mapping(bytes32 => bool) public fineRdecords; +func (s *GovernanceState) FineRecords(recordHash Bytes32) bool { + loc := s.getMapLoc(big.NewInt(finedRecordsLoc), recordHash[:]) + return s.getStateBigInt(loc).Cmp(big.NewInt(0)) > 0 +} +func (s *GovernanceState) SetFineRecords(recordHash Bytes32, status bool) { + loc := s.getMapLoc(big.NewInt(finedRecordsLoc), recordHash[:]) + value := int64(0) + if status { + value = int64(1) + } + s.setStateBigInt(loc, big.NewInt(value)) +} + +// Initialize initializes governance contract state. +func (s *GovernanceState) Initialize(config *params.DexconConfig, totalSupply *big.Int) { + if config.NextHalvingSupply.Cmp(totalSupply) <= 0 { + panic(fmt.Sprintf("invalid genesis found, totalSupply: %s, nextHavlingSupply: %s", + totalSupply, config.NextHalvingSupply)) + } + + // Genesis CRS. + crs := crypto.Keccak256Hash([]byte(config.GenesisCRSText)) + s.SetCRS(crs) + + // Round 0 height. + s.PushRoundHeight(big.NewInt(0)) + + // Owner. + s.SetOwner(config.Owner) + + // Governance configuration. + s.UpdateConfiguration(config) + + // Set totalSupply. + s.IncTotalSupply(totalSupply) + + // Set DKGRound. + s.SetDKGRound(big.NewInt(int64(dexCore.DKGDelayRound))) +} + +// Register is a helper function for creating genesis state. +func (s *GovernanceState) Register( + addr common.Address, publicKey []byte, + name, email, location, url string, staked *big.Int) { + offset := s.LenNodes() + node := &nodeInfo{ + Owner: addr, + PublicKey: publicKey, + Staked: staked, + Fined: big.NewInt(0), + Name: name, + Email: email, + Location: location, + Url: url, + Unstaked: big.NewInt(0), + UnstakedAt: big.NewInt(0), + } + s.PushNode(node) + s.PutNodeOffsets(node, offset) + + if staked.Cmp(big.NewInt(0)) == 0 { + return + } + + // Add to network total staked. + s.IncTotalStaked(staked) +} + +func (s *GovernanceState) Disqualify(n *nodeInfo) error { + nodeAddr, err := publicKeyToNodeKeyAddress(n.PublicKey) + if err != nil { + return err + } + + // Node might already been unstaked in the latest state. + offset := s.NodesOffsetByNodeKeyAddress(nodeAddr) + if offset.Cmp(big.NewInt(0)) < 0 { + return errors.New("node does not exist") + } + + // Set fined value. + node := s.Node(offset) + amount := s.FineValue(big.NewInt(FineTypeFailStop)) + node.Fined = new(big.Int).Add(node.Fined, amount) + s.UpdateNode(offset, node) + + return nil +} + +const decimalMultiplier = 100000000.0 + +// Configuration returns the current configuration. +func (s *GovernanceState) Configuration() *params.DexconConfig { + return ¶ms.DexconConfig{ + MinStake: s.getStateBigInt(big.NewInt(minStakeLoc)), + LockupPeriod: s.getStateBigInt(big.NewInt(lockupPeriodLoc)).Uint64(), + MiningVelocity: float32(s.getStateBigInt(big.NewInt(miningVelocityLoc)).Uint64()) / decimalMultiplier, + NextHalvingSupply: s.getStateBigInt(big.NewInt(nextHalvingSupplyLoc)), + LastHalvedAmount: s.getStateBigInt(big.NewInt(lastHalvedAmountLoc)), + MinGasPrice: s.getStateBigInt(big.NewInt(minGasPriceLoc)), + BlockGasLimit: s.getStateBigInt(big.NewInt(blockGasLimitLoc)).Uint64(), + LambdaBA: s.getStateBigInt(big.NewInt(lambdaBALoc)).Uint64(), + LambdaDKG: s.getStateBigInt(big.NewInt(lambdaDKGLoc)).Uint64(), + NotarySetSize: uint32(s.getStateBigInt(big.NewInt(notarySetSizeLoc)).Uint64()), + NotaryParamAlpha: float32(s.getStateBigInt(big.NewInt(notaryParamAlphaLoc)).Uint64()) / decimalMultiplier, + NotaryParamBeta: float32(s.getStateBigInt(big.NewInt(notaryParamBetaLoc)).Uint64()) / decimalMultiplier, + RoundLength: s.getStateBigInt(big.NewInt(roundLengthLoc)).Uint64(), + MinBlockInterval: s.getStateBigInt(big.NewInt(minBlockIntervalLoc)).Uint64(), + FineValues: s.FineValues(), + } +} + +// UpdateConfiguration updates system configuration. +func (s *GovernanceState) UpdateConfiguration(cfg *params.DexconConfig) { + s.setStateBigInt(big.NewInt(minStakeLoc), cfg.MinStake) + s.setStateBigInt(big.NewInt(lockupPeriodLoc), big.NewInt(int64(cfg.LockupPeriod))) + s.setStateBigInt(big.NewInt(miningVelocityLoc), big.NewInt(int64(cfg.MiningVelocity*decimalMultiplier))) + s.setStateBigInt(big.NewInt(nextHalvingSupplyLoc), cfg.NextHalvingSupply) + s.setStateBigInt(big.NewInt(lastHalvedAmountLoc), cfg.LastHalvedAmount) + s.setStateBigInt(big.NewInt(minGasPriceLoc), cfg.MinGasPrice) + s.setStateBigInt(big.NewInt(blockGasLimitLoc), big.NewInt(int64(cfg.BlockGasLimit))) + s.setStateBigInt(big.NewInt(lambdaBALoc), big.NewInt(int64(cfg.LambdaBA))) + s.setStateBigInt(big.NewInt(lambdaDKGLoc), big.NewInt(int64(cfg.LambdaDKG))) + s.setStateBigInt(big.NewInt(notarySetSizeLoc), big.NewInt(int64(cfg.NotarySetSize))) + s.setStateBigInt(big.NewInt(notaryParamAlphaLoc), big.NewInt(int64(cfg.NotaryParamAlpha*decimalMultiplier))) + s.setStateBigInt(big.NewInt(notaryParamBetaLoc), big.NewInt(int64(cfg.NotaryParamBeta*decimalMultiplier))) + s.setStateBigInt(big.NewInt(roundLengthLoc), big.NewInt(int64(cfg.RoundLength))) + s.setStateBigInt(big.NewInt(minBlockIntervalLoc), big.NewInt(int64(cfg.MinBlockInterval))) + s.SetFineValues(cfg.FineValues) + + // Calculate set size. + s.CalNotarySetSize() +} + +type rawConfigStruct struct { + MinStake *big.Int + LockupPeriod *big.Int + BlockGasLimit *big.Int + MinGasPrice *big.Int + LambdaBA *big.Int + LambdaDKG *big.Int + NotaryParamAlpha *big.Int + NotaryParamBeta *big.Int + RoundLength *big.Int + MinBlockInterval *big.Int + FineValues []*big.Int +} + +// UpdateConfigurationRaw updates system configuration. +func (s *GovernanceState) UpdateConfigurationRaw(cfg *rawConfigStruct) { + s.setStateBigInt(big.NewInt(minStakeLoc), cfg.MinStake) + s.setStateBigInt(big.NewInt(lockupPeriodLoc), cfg.LockupPeriod) + s.setStateBigInt(big.NewInt(minGasPriceLoc), cfg.MinGasPrice) + s.setStateBigInt(big.NewInt(blockGasLimitLoc), cfg.BlockGasLimit) + s.setStateBigInt(big.NewInt(lambdaBALoc), cfg.LambdaBA) + s.setStateBigInt(big.NewInt(lambdaDKGLoc), cfg.LambdaDKG) + s.setStateBigInt(big.NewInt(notaryParamAlphaLoc), cfg.NotaryParamAlpha) + s.setStateBigInt(big.NewInt(notaryParamBetaLoc), cfg.NotaryParamBeta) + s.setStateBigInt(big.NewInt(roundLengthLoc), cfg.RoundLength) + s.setStateBigInt(big.NewInt(minBlockIntervalLoc), cfg.MinBlockInterval) + s.SetFineValues(cfg.FineValues) + + // Calculate set size. + s.CalNotarySetSize() +} + +// event ConfigurationChanged(); +func (s *GovernanceState) emitConfigurationChangedEvent() { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{GovernanceABI.Events["ConfigurationChanged"].Id()}, + Data: []byte{}, + }) +} + +// event CRSProposed(uint256 indexed Round, bytes32 CRS); +func (s *GovernanceState) emitCRSProposed(round *big.Int, crs common.Hash) { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{GovernanceABI.Events["CRSProposed"].Id(), common.BigToHash(round)}, + Data: crs.Bytes(), + }) +} + +// event NodeOwnershipTransfered(address indexed NodeAddress, address indexed NewOwnerAddress); +func (s *GovernanceState) emitNodeOwnershipTransfered(nodeAddr, newNodeAddr common.Address) { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{GovernanceABI.Events["NodeOwnershipTransfered"].Id(), + nodeAddr.Hash(), newNodeAddr.Hash()}, + Data: []byte{}, + }) +} + +// event NodePublicKeyReplaced(address indexed NodeAddress, bytes PublicKey); +func (s *GovernanceState) emitNodePublicKeyReplaced(nodeAddr common.Address, pk []byte) { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{GovernanceABI.Events["NodePublicKeyReplaced"].Id(), nodeAddr.Hash()}, + Data: pk, + }) +} + +// event Staked(address indexed NodeAddress, uint256 Amount); +func (s *GovernanceState) emitStaked(nodeAddr common.Address, amount *big.Int) { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{GovernanceABI.Events["Staked"].Id(), nodeAddr.Hash()}, + Data: common.BigToHash(amount).Bytes(), + }) +} + +// event Unstaked(address indexed NodeAddress, uint256 Amount); +func (s *GovernanceState) emitUnstaked(nodeAddr common.Address, amount *big.Int) { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{GovernanceABI.Events["Unstaked"].Id(), nodeAddr.Hash()}, + Data: common.BigToHash(amount).Bytes(), + }) +} + +// event Withdrawn(address indexed NodeAddress, uint256 Amount); +func (s *GovernanceState) emitWithdrawn(nodeAddr common.Address, amount *big.Int) { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{GovernanceABI.Events["Withdrawn"].Id(), nodeAddr.Hash()}, + Data: common.BigToHash(amount).Bytes(), + }) +} + +// event NodeAdded(address indexed NodeAddress); +func (s *GovernanceState) emitNodeAdded(nodeAddr common.Address) { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{GovernanceABI.Events["NodeAdded"].Id(), nodeAddr.Hash()}, + Data: []byte{}, + }) +} + +// event NodeRemoved(address indexed NodeAddress); +func (s *GovernanceState) emitNodeRemoved(nodeAddr common.Address) { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{GovernanceABI.Events["NodeRemoved"].Id(), nodeAddr.Hash()}, + Data: []byte{}, + }) +} + +// event Reported(address indexed NodeAddress, uint256 Type, bytes Arg1, bytes Arg2); +func (s *GovernanceState) emitReported(nodeAddr common.Address, reportType *big.Int, arg1, arg2 []byte) { + + t1, err := abi.NewType("uint256", nil) + if err != nil { + panic(err) + } + t2, err := abi.NewType("bytes", nil) + if err != nil { + panic(err) + } + + arg := abi.Arguments{ + abi.Argument{ + Name: "ReportType", + Type: t1, + Indexed: false, + }, + abi.Argument{ + Name: "Arg1", + Type: t2, + Indexed: false, + }, + abi.Argument{ + Name: "Arg2", + Type: t2, + Indexed: false, + }, + } + + data, err := arg.Pack(reportType, arg1, arg2) + if err != nil { + panic(err) + } + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{GovernanceABI.Events["Reported"].Id(), nodeAddr.Hash()}, + Data: data, + }) +} + +// event Fined(address indexed NodeAddress, uint256 Amount); +func (s *GovernanceState) emitFined(nodeAddr common.Address, amount *big.Int) { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{GovernanceABI.Events["Fined"].Id(), nodeAddr.Hash()}, + Data: common.BigToHash(amount).Bytes(), + }) +} + +// event FinePaid(address indexed NodeAddress, uint256 Amount); +func (s *GovernanceState) emitFinePaid(nodeAddr common.Address, amount *big.Int) { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{GovernanceABI.Events["FinePaid"].Id(), nodeAddr.Hash()}, + Data: common.BigToHash(amount).Bytes(), + }) +} + +// event DKGReset(uint256 indexed Round, uint256 BlockHeight); +func (s *GovernanceState) emitDKGReset(round *big.Int, blockHeight *big.Int) { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{GovernanceABI.Events["DKGReset"].Id(), common.BigToHash(round)}, + Data: common.BigToHash(blockHeight).Bytes(), + }) +} + +func getRoundState(evm *EVM, round *big.Int) (*GovernanceState, error) { + gs := &GovernanceState{evm.StateDB} + height := gs.RoundHeight(round).Uint64() + if round.Uint64() > dexCore.ConfigRoundShift { + if height == 0 { + return nil, errExecutionReverted + } + } + statedb, err := evm.StateAtNumber(height) + return &GovernanceState{statedb}, err +} + +func getConfigState(evm *EVM, round *big.Int) (*GovernanceState, error) { + configRound := big.NewInt(0) + if round.Uint64() > dexCore.ConfigRoundShift { + configRound = new(big.Int).Sub(round, big.NewInt(int64(dexCore.ConfigRoundShift))) + } + return getRoundState(evm, configRound) +} + +type coreDKGUtils interface { + NewGroupPublicKey(*GovernanceState, *big.Int, int) (tsigVerifierIntf, error) +} +type tsigVerifierIntf interface { + VerifySignature(coreCommon.Hash, coreCrypto.Signature) bool +} + +// GovernanceContract represents the governance contract of DEXCON. +type GovernanceContract struct { + evm *EVM + state GovernanceState + contract *vm.Contract + coreDKGUtils coreDKGUtils +} + +// defaultCoreDKGUtils implements coreDKGUtils. +type defaultCoreDKGUtils struct { + gpk atomic.Value +} + +func (c *defaultCoreDKGUtils) NewGroupPublicKey( + state *GovernanceState, round *big.Int, threshold int) (tsigVerifierIntf, error) { + var gpk *dkgTypes.GroupPublicKey + var err error + + v := c.gpk.Load() + if v != nil { + gpk = v.(*dkgTypes.GroupPublicKey) + if gpk.Round == round.Uint64() { + return gpk, nil + } + } + + mpks := state.DKGMasterPublicKeyItems() + comps := state.DKGComplaintItems() + gpk, err = dkgTypes.NewGroupPublicKey(round.Uint64(), mpks, comps, threshold) + if err != nil { + return nil, err + } + c.gpk.Store(gpk) + return gpk, nil +} + +func (g *GovernanceContract) Address() common.Address { + return GovernanceContractAddress +} + +func (g *GovernanceContract) transfer(from, to common.Address, amount *big.Int) bool { + // TODO(w): add this to debug trace so it shows up as internal transaction. + if g.evm.CanTransfer(g.evm.StateDB, from, amount) { + g.evm.Transfer(g.evm.StateDB, from, to, amount) + return true + } + return false +} + +func (g *GovernanceContract) useGas(gas uint64) ([]byte, error) { + if !g.contract.UseGas(gas) { + return nil, vm.ErrOutOfGas + } + return nil, nil +} + +func (g *GovernanceContract) configNotarySetSize(round *big.Int) *big.Int { + s, err := getConfigState(g.evm, round) + if err != nil { + return big.NewInt(0) + } + return s.NotarySetSize() +} + +func (g *GovernanceContract) getNotarySet(round *big.Int) map[coreTypes.NodeID]struct{} { + crsRound := g.state.CRSRound() + var crs common.Hash + cmp := round.Cmp(crsRound) + if round.Cmp(big.NewInt(int64(dexCore.DKGDelayRound))) <= 0 { + state, err := getRoundState(g.evm, big.NewInt(0)) + if err != nil { + return map[coreTypes.NodeID]struct{}{} + } + crs = state.CRS() + for i := uint64(0); i < round.Uint64(); i++ { + crs = crypto.Keccak256Hash(crs[:]) + } + } else if cmp > 0 { + return map[coreTypes.NodeID]struct{}{} + } else if cmp == 0 { + crs = g.state.CRS() + } else { + state, err := getRoundState(g.evm, round) + if err != nil { + return map[coreTypes.NodeID]struct{}{} + } + crs = state.CRS() + } + + target := coreTypes.NewNotarySetTarget(coreCommon.Hash(crs)) + ns := coreTypes.NewNodeSet() + + state, err := getConfigState(g.evm, round) + if err != nil { + return map[coreTypes.NodeID]struct{}{} + } + for _, x := range state.QualifiedNodes() { + mpk, err := ecdsa.NewPublicKeyFromByteSlice(x.PublicKey) + if err != nil { + panic(err) + } + ns.Add(coreTypes.NewNodeID(mpk)) + } + return ns.GetSubSet(int(g.configNotarySetSize(round).Uint64()), target) +} + +func (g *GovernanceContract) inNotarySet(round *big.Int, nodeID coreTypes.NodeID) bool { + dkgSet := g.getNotarySet(round) + _, ok := dkgSet[nodeID] + return ok +} + +func (g *GovernanceContract) clearDKG() { + dkgSet := g.getNotarySet(g.state.DKGRound()) + g.state.ClearDKGMasterPublicKeyOffset() + g.state.ClearDKGMasterPublicKeys() + g.state.ClearDKGComplaintProposed() + g.state.ClearDKGComplaints() + g.state.ClearDKGMPKReadys(dkgSet) + g.state.ResetDKGMPKReadysCount() + g.state.ClearDKGFinalizeds(dkgSet) + g.state.ResetDKGFinalizedsCount() + g.state.ClearDKGSuccesses(dkgSet) + g.state.ResetDKGSuccessesCount() +} + +func (g *GovernanceContract) fineFailStopDKG(threshold int) { + fineNode := make(map[coreTypes.NodeID]struct{}) + dkgSet := g.getNotarySet(g.state.DKGRound()) + for id := range dkgSet { + offset := g.state.DKGMasterPublicKeyOffset(Bytes32(id.Hash)) + if offset.Cmp(big.NewInt(0)) >= 0 { + continue + } + fineNode[id] = struct{}{} + } + complaintsByID := map[coreTypes.NodeID]map[coreTypes.NodeID]struct{}{} + for _, complaint := range g.state.DKGComplaints() { + comp := new(dkgTypes.Complaint) + if err := rlp.DecodeBytes(complaint, comp); err != nil { + panic(err) + } + + if comp.IsNack() { + if _, exist := complaintsByID[comp.PrivateShare.ProposerID]; !exist { + complaintsByID[comp.PrivateShare.ProposerID] = + make(map[coreTypes.NodeID]struct{}) + } + complaintsByID[comp.PrivateShare.ProposerID][comp.ProposerID] = struct{}{} + } + } + for id, complaints := range complaintsByID { + if len(complaints) >= threshold { + fineNode[id] = struct{}{} + } + } + nodes := make(coreTypes.NodeIDs, 0, len(fineNode)) + for id := range fineNode { + nodes = append(nodes, id) + } + sort.Sort(nodes) + for _, id := range nodes { + offset := g.state.NodesOffsetByNodeKeyAddress(IdToAddress(id)) + // Node might have been unstaked. + if offset.Cmp(big.NewInt(0)) < 0 { + continue + } + + node := g.state.Node(offset) + amount := g.state.FineValue(big.NewInt(FineTypeFailStopDKG)) + node.Fined = new(big.Int).Add(node.Fined, amount) + g.state.UpdateNode(offset, node) + g.state.emitFined(node.Owner, amount) + } +} + +func (g *GovernanceContract) addDKGComplaint(comp []byte) ([]byte, error) { + caller := g.contract.Caller() + offset := g.state.NodesOffsetByNodeKeyAddress(caller) + + // Can not add complaint if caller does not exists. + if offset.Cmp(big.NewInt(0)) < 0 { + return nil, errExecutionReverted + } + + // Finalized caller is not allowed to propose complaint. + if g.state.DKGFinalized(caller) { + return nil, errExecutionReverted + } + + // Calculate 2f + 1 + threshold := 2*g.configNotarySetSize(g.evm.Round).Uint64()/3 + 1 + + // If 2f + 1 of DKG set is finalized, one can not propose complaint anymore. + if g.state.DKGFinalizedsCount().Uint64() >= threshold { + return nil, errExecutionReverted + } + + var dkgComplaint dkgTypes.Complaint + if err := rlp.DecodeBytes(comp, &dkgComplaint); err != nil { + return nil, errExecutionReverted + } + + if g.state.DKGComplaintProposed(getDKGComplaintID(&dkgComplaint)) { + return nil, errExecutionReverted + } + round := big.NewInt(int64(dkgComplaint.Round)) + if round.Uint64() != g.evm.Round.Uint64()+1 { + return nil, errExecutionReverted + } + + if dkgComplaint.Reset != g.state.DKGResetCount(round).Uint64() { + return nil, errExecutionReverted + } + + // DKGComplaint must belongs to someone in DKG set. + if !g.inNotarySet(round, dkgComplaint.ProposerID) { + return nil, errExecutionReverted + } + + verified, _ := coreUtils.VerifyDKGComplaintSignature(&dkgComplaint) + if !verified { + return nil, errExecutionReverted + } + + mpkOffset := g.state.DKGMasterPublicKeyOffset(Bytes32(dkgComplaint.PrivateShare.ProposerID.Hash)) + mpk := g.state.DKGMasterPublicKeyItem(mpkOffset) + + // Verify DKG complaint is correct. + ok, err := coreUtils.VerifyDKGComplaint(&dkgComplaint, mpk) + if !ok || err != nil { + return nil, errExecutionReverted + } + + // Fine the attacker. + need, err := coreUtils.NeedPenaltyDKGPrivateShare(&dkgComplaint, mpk) + if err != nil { + return nil, errExecutionReverted + } + if need { + node, err := g.state.GetNodeByID(dkgComplaint.PrivateShare.ProposerID) + if err != nil { + return nil, errExecutionReverted + } + fineValue := g.state.FineValue(big.NewInt(FineTypeInvalidDKG)) + if err := g.fine(node.Owner, fineValue, comp, nil); err != nil { + return nil, errExecutionReverted + } + } + + g.state.PushDKGComplaint(comp) + g.state.PutDKGComplaintProposed(getDKGComplaintID(&dkgComplaint), true) + + return g.useGas(GovernanceActionGasCost) +} + +func (g *GovernanceContract) addDKGMasterPublicKey(mpk []byte) ([]byte, error) { + var dkgMasterPK dkgTypes.MasterPublicKey + if err := rlp.DecodeBytes(mpk, &dkgMasterPK); err != nil { + return nil, errExecutionReverted + } + round := big.NewInt(int64(dkgMasterPK.Round)) + if round.Uint64() != g.evm.Round.Uint64()+1 { + return nil, errExecutionReverted + } + + if g.state.DKGRound().Cmp(g.evm.Round) == 0 { + // Clear DKG states for next round. + g.clearDKG() + g.state.SetDKGRound(round) + } + + mpkOffset := g.state.DKGMasterPublicKeyOffset(getDKGMasterPublicKeyID(&dkgMasterPK)) + if mpkOffset.Cmp(big.NewInt(0)) >= 0 { + return nil, errExecutionReverted + } + + caller := g.contract.Caller() + offset := g.state.NodesOffsetByNodeKeyAddress(caller) + + // Can not add dkg mpk if not staked. + if offset.Cmp(big.NewInt(0)) < 0 { + return nil, errExecutionReverted + } + + // MPKReady caller is not allowed to propose mpk. + if g.state.DKGMPKReady(caller) { + return nil, errExecutionReverted + } + + // Calculate 2f + 1 + threshold := 2*g.configNotarySetSize(g.evm.Round).Uint64()/3 + 1 + + // If 2f + 1 of DKG set is mpk ready, one can not propose mpk anymore. + if g.state.DKGMPKReadysCount().Uint64() >= threshold { + return nil, errExecutionReverted + } + + if dkgMasterPK.Reset != g.state.DKGResetCount(round).Uint64() { + return nil, errExecutionReverted + } + + // DKGMasterPublicKey must belongs to someone in DKG set. + if !g.inNotarySet(round, dkgMasterPK.ProposerID) { + return nil, errExecutionReverted + } + + verified, _ := coreUtils.VerifyDKGMasterPublicKeySignature(&dkgMasterPK) + if !verified { + return nil, errExecutionReverted + } + + mpkOffset = g.state.LenDKGMasterPublicKeys() + g.state.PushDKGMasterPublicKey(mpk) + g.state.PutDKGMasterPublicKeyOffset(getDKGMasterPublicKeyID(&dkgMasterPK), mpkOffset) + + return g.useGas(GovernanceActionGasCost) +} + +func (g *GovernanceContract) addDKGMPKReady(ready []byte) ([]byte, error) { + caller := g.contract.Caller() + + var dkgReady dkgTypes.MPKReady + if err := rlp.DecodeBytes(ready, &dkgReady); err != nil { + return nil, errExecutionReverted + } + round := big.NewInt(int64(dkgReady.Round)) + if round.Uint64() != g.evm.Round.Uint64()+1 { + return nil, errExecutionReverted + } + + if dkgReady.Reset != g.state.DKGResetCount(round).Uint64() { + return nil, errExecutionReverted + } + + // DKGFInalize must belongs to someone in DKG set. + if !g.inNotarySet(round, dkgReady.ProposerID) { + return nil, errExecutionReverted + } + + verified, _ := coreUtils.VerifyDKGMPKReadySignature(&dkgReady) + if !verified { + return nil, errExecutionReverted + } + + if !g.state.DKGMPKReady(caller) { + g.state.PutDKGMPKReady(caller, true) + g.state.IncDKGMPKReadysCount() + } + + return g.useGas(GovernanceActionGasCost) +} + +func (g *GovernanceContract) addDKGFinalize(finalize []byte) ([]byte, error) { + caller := g.contract.Caller() + + var dkgFinalize dkgTypes.Finalize + if err := rlp.DecodeBytes(finalize, &dkgFinalize); err != nil { + return nil, errExecutionReverted + } + round := big.NewInt(int64(dkgFinalize.Round)) + if round.Uint64() != g.evm.Round.Uint64()+1 { + return nil, errExecutionReverted + } + + if dkgFinalize.Reset != g.state.DKGResetCount(round).Uint64() { + return nil, errExecutionReverted + } + + // DKGFInalize must belongs to someone in DKG set. + if !g.inNotarySet(round, dkgFinalize.ProposerID) { + return nil, errExecutionReverted + } + + verified, _ := coreUtils.VerifyDKGFinalizeSignature(&dkgFinalize) + if !verified { + return nil, errExecutionReverted + } + + if !g.state.DKGFinalized(caller) { + g.state.PutDKGFinalized(caller, true) + g.state.IncDKGFinalizedsCount() + } + + threshold := 2*g.configNotarySetSize(g.evm.Round).Uint64()/3 + 1 + + if g.state.DKGFinalizedsCount().Uint64() == threshold { + tsigThreshold := coreUtils.GetDKGThreshold(&coreTypes.Config{ + NotarySetSize: uint32(g.configNotarySetSize(g.evm.Round).Uint64())}) + g.fineFailStopDKG(tsigThreshold) + } + + return g.useGas(GovernanceActionGasCost) +} + +func (g *GovernanceContract) addDKGSuccess(success []byte) ([]byte, error) { + caller := g.contract.Caller() + + var dkgSuccess dkgTypes.Success + if err := rlp.DecodeBytes(success, &dkgSuccess); err != nil { + return nil, errExecutionReverted + } + round := big.NewInt(int64(dkgSuccess.Round)) + if round.Uint64() != g.evm.Round.Uint64()+1 { + return nil, errExecutionReverted + } + + if dkgSuccess.Reset != g.state.DKGResetCount(round).Uint64() { + return nil, errExecutionReverted + } + + // DKGFInalize must belongs to someone in DKG set. + if !g.inNotarySet(round, dkgSuccess.ProposerID) { + return nil, errExecutionReverted + } + + verified, _ := coreUtils.VerifyDKGSuccessSignature(&dkgSuccess) + if !verified { + return nil, errExecutionReverted + } + + if !g.state.DKGSuccess(caller) { + g.state.PutDKGSuccess(caller, true) + g.state.IncDKGSuccessesCount() + } + + return g.useGas(GovernanceActionGasCost) +} + +func (g *GovernanceContract) updateConfiguration(cfg *rawConfigStruct) ([]byte, error) { + // Only owner can update configuration. + if g.contract.Caller() != g.state.Owner() { + return nil, errExecutionReverted + } + + // Sanity checks. + if cfg.MinStake.Cmp(big.NewInt(0)) <= 0 || + cfg.LockupPeriod.Cmp(big.NewInt(0)) <= 0 || + cfg.BlockGasLimit.Cmp(big.NewInt(0)) <= 0 || + cfg.MinGasPrice.Cmp(big.NewInt(0)) <= 0 || + cfg.LambdaBA.Cmp(big.NewInt(0)) <= 0 || + cfg.LambdaDKG.Cmp(big.NewInt(0)) <= 0 || + cfg.RoundLength.Cmp(big.NewInt(0)) <= 0 || + cfg.MinBlockInterval.Cmp(big.NewInt(0)) <= 0 { + return nil, errExecutionReverted + } + + g.state.UpdateConfigurationRaw(cfg) + g.state.emitConfigurationChangedEvent() + + return nil, nil +} + +func (g *GovernanceContract) register( + publicKey []byte, name, email, location, url string) ([]byte, error) { + + // Reject invalid inputs. + if len(name) >= 32 || len(email) >= 32 || len(location) >= 32 || len(url) >= 128 { + return nil, errExecutionReverted + } + + caller := g.contract.Caller() + value := g.contract.Value() + offset := g.state.NodesOffsetByAddress(caller) + + // Can not register if already registered. + if offset.Cmp(big.NewInt(0)) >= 0 { + return nil, errExecutionReverted + } + + nodeKeyAddr, err := publicKeyToNodeKeyAddress(publicKey) + if err != nil { + return nil, errExecutionReverted + } + + offset = g.state.NodesOffsetByNodeKeyAddress(nodeKeyAddr) + + // Can not register if node key is duplicate. + if offset.Cmp(big.NewInt(0)) >= 0 { + return nil, errExecutionReverted + } + + offset = g.state.LenNodes() + node := &nodeInfo{ + Owner: caller, + PublicKey: publicKey, + Staked: value, + Fined: big.NewInt(0), + Name: name, + Email: email, + Location: location, + Url: url, + Unstaked: big.NewInt(0), + UnstakedAt: big.NewInt(0), + } + g.state.PushNode(node) + g.state.PutNodeOffsets(node, offset) + g.state.emitNodeAdded(caller) + + if value.Cmp(big.NewInt(0)) > 0 { + g.state.IncTotalStaked(value) + g.state.emitStaked(caller, value) + } + return g.useGas(GovernanceActionGasCost) +} + +func (g *GovernanceContract) stake() ([]byte, error) { + caller := g.contract.Caller() + value := g.contract.Value() + + if big.NewInt(0).Cmp(value) == 0 { + return nil, errExecutionReverted + } + + offset := g.state.NodesOffsetByAddress(caller) + if offset.Cmp(big.NewInt(0)) < 0 { + return nil, errExecutionReverted + } + + node := g.state.Node(offset) + if node.Fined.Cmp(big.NewInt(0)) > 0 { + return nil, errExecutionReverted + } + + node.Staked = new(big.Int).Add(node.Staked, value) + g.state.UpdateNode(offset, node) + + g.state.IncTotalStaked(value) + g.state.emitStaked(caller, value) + + return g.useGas(GovernanceActionGasCost) +} + +func (g *GovernanceContract) unstake(amount *big.Int) ([]byte, error) { + caller := g.contract.Caller() + + offset := g.state.NodesOffsetByAddress(caller) + if offset.Cmp(big.NewInt(0)) < 0 { + return nil, errExecutionReverted + } + + node := g.state.Node(offset) + + // Can not unstake if there are unpaied fine. + if node.Fined.Cmp(big.NewInt(0)) > 0 { + return nil, errExecutionReverted + } + + // Can not unstake if there are unwithdrawn stake. + if node.Unstaked.Cmp(big.NewInt(0)) > 0 { + return nil, errExecutionReverted + } + if node.Staked.Cmp(amount) < 0 { + return nil, errExecutionReverted + } + + node.Staked = new(big.Int).Sub(node.Staked, amount) + node.Unstaked = amount + node.UnstakedAt = g.evm.Time + g.state.UpdateNode(offset, node) + + g.state.DecTotalStaked(amount) + g.state.emitUnstaked(caller, amount) + + return g.useGas(GovernanceActionGasCost) +} + +func (g *GovernanceContract) withdraw() ([]byte, error) { + if !g.withdrawable() { + return nil, errExecutionReverted + } + caller := g.contract.Caller() + + offset := g.state.NodesOffsetByAddress(caller) + if offset.Cmp(big.NewInt(0)) < 0 { + return nil, errExecutionReverted + } + + node := g.state.Node(offset) + + amount := node.Unstaked + node.Unstaked = big.NewInt(0) + node.UnstakedAt = big.NewInt(0) + g.state.UpdateNode(offset, node) + + if node.Staked.Cmp(big.NewInt(0)) == 0 { + length := g.state.LenNodes() + lastIndex := new(big.Int).Sub(length, big.NewInt(1)) + + // Delete the node. + if offset.Cmp(lastIndex) != 0 { + lastNode := g.state.Node(lastIndex) + g.state.UpdateNode(offset, lastNode) + g.state.PutNodeOffsets(lastNode, offset) + } + g.state.DeleteNodeOffsets(node) + g.state.PopLastNode() + g.state.emitNodeRemoved(caller) + } + + // Return the staked fund. + if !g.transfer(GovernanceContractAddress, node.Owner, amount) { + return nil, errExecutionReverted + } + g.state.emitWithdrawn(caller, amount) + + return g.useGas(GovernanceActionGasCost) +} + +func (g *GovernanceContract) withdrawable() bool { + caller := g.contract.Caller() + + offset := g.state.NodesOffsetByAddress(caller) + if offset.Cmp(big.NewInt(0)) < 0 { + return false + } + + node := g.state.Node(offset) + + // Can not withdraw if there are unpaied fine. + if node.Fined.Cmp(big.NewInt(0)) > 0 { + return false + } + + // Can not withdraw if there are no pending withdrawal. + if node.Unstaked.Cmp(big.NewInt(0)) == 0 { + return false + } + + unlockTime := new(big.Int).Add(node.UnstakedAt, g.state.LockupPeriod()) + return g.evm.Time.Cmp(unlockTime) > 0 +} + +func (g *GovernanceContract) payFine(nodeAddr common.Address) ([]byte, error) { + nodeOffset := g.state.NodesOffsetByAddress(nodeAddr) + if nodeOffset.Cmp(big.NewInt(0)) < 0 { + return nil, errExecutionReverted + } + + node := g.state.Node(nodeOffset) + if node.Fined.Cmp(big.NewInt(0)) <= 0 || node.Fined.Cmp(g.contract.Value) < 0 { + return nil, errExecutionReverted + } + + node.Fined = new(big.Int).Sub(node.Fined, g.contract.Value) + g.state.UpdateNode(nodeOffset, node) + + // Pay the fine to governance owner. + g.evm.StateDB.AddBalance(g.state.Owner(), g.contract.Value) + + g.state.emitFinePaid(nodeAddr, g.contract.Value) + + return g.useGas(GovernanceActionGasCost) +} + +func (g *GovernanceContract) proposeCRS(nextRound *big.Int, signedCRS []byte) ([]byte, error) { + if nextRound.Uint64() != g.evm.Round.Uint64()+1 || + g.state.CRSRound().Uint64() == nextRound.Uint64() { + return nil, errExecutionReverted + } + + prevCRS := g.state.CRS() + + // CRS(n) = hash(CRS(n-1)) if n <= core.DKGRoundDelay + if g.evm.Round.Uint64() == dexCore.DKGDelayRound { + for i := uint64(0); i < dexCore.DKGDelayRound; i++ { + prevCRS = crypto.Keccak256Hash(prevCRS[:]) + } + } + + threshold := coreUtils.GetDKGThreshold(&coreTypes.Config{ + NotarySetSize: uint32(g.state.NotarySetSize().Uint64())}) + dkgGPK, err := g.coreDKGUtils.NewGroupPublicKey(&g.state, nextRound, threshold) + if err != nil { + return nil, errExecutionReverted + } + signature := coreCrypto.Signature{ + Type: "bls", + Signature: signedCRS, + } + if !dkgGPK.VerifySignature(coreCommon.Hash(prevCRS), signature) { + return nil, errExecutionReverted + } + + // Save new CRS into state and increase round. + crs := crypto.Keccak256Hash(signedCRS) + + g.state.SetCRS(crs) + g.state.SetCRSRound(nextRound) + g.state.emitCRSProposed(nextRound, crs) + + return g.useGas(GovernanceActionGasCost) +} + +type sortBytes [][]byte + +func (s sortBytes) Less(i, j int) bool { + return bytes.Compare(s[i], s[j]) < 0 +} + +func (s sortBytes) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +func (s sortBytes) Len() int { + return len(s) +} + +func (g *GovernanceContract) fine(nodeAddr common.Address, amount *big.Int, payloads ...[]byte) error { + sort.Sort(sortBytes(payloads)) + + hash := Bytes32(crypto.Keccak256Hash(payloads...)) + if g.state.FineRecords(hash) { + return errors.New("already fined") + } + g.state.SetFineRecords(hash, true) + + nodeOffset := g.state.NodesOffsetByAddress(nodeAddr) + if nodeOffset.Cmp(big.NewInt(0)) < 0 { + return errExecutionReverted + } + + // Set fined value. + node := g.state.Node(nodeOffset) + node.Fined = new(big.Int).Add(node.Fined, amount) + g.state.UpdateNode(nodeOffset, node) + + g.state.emitFined(nodeAddr, amount) + + return nil +} + +func (g *GovernanceContract) report(reportType *big.Int, arg1, arg2 []byte) ([]byte, error) { + typeEnum := FineType(reportType.Uint64()) + var reportedNodeID coreTypes.NodeID + + switch typeEnum { + case FineTypeForkVote: + vote1 := new(coreTypes.Vote) + if err := rlp.DecodeBytes(arg1, vote1); err != nil { + return nil, errExecutionReverted + } + vote2 := new(coreTypes.Vote) + if err := rlp.DecodeBytes(arg2, vote2); err != nil { + return nil, errExecutionReverted + } + need, err := coreUtils.NeedPenaltyForkVote(vote1, vote2) + if !need || err != nil { + return nil, errExecutionReverted + } + reportedNodeID = vote1.ProposerID + case FineTypeForkBlock: + block1 := new(coreTypes.Block) + if err := rlp.DecodeBytes(arg1, block1); err != nil { + return nil, errExecutionReverted + } + block2 := new(coreTypes.Block) + if err := rlp.DecodeBytes(arg2, block2); err != nil { + return nil, errExecutionReverted + } + need, err := coreUtils.NeedPenaltyForkBlock(block1, block2) + if !need || err != nil { + return nil, errExecutionReverted + } + reportedNodeID = block1.ProposerID + default: + return nil, errExecutionReverted + } + + node, err := g.state.GetNodeByID(reportedNodeID) + if err != nil { + return nil, errExecutionReverted + } + + g.state.emitReported(node.Owner, reportType, arg1, arg2) + + fineValue := g.state.FineValue(reportType) + if err := g.fine(node.Owner, fineValue, arg1, arg2); err != nil { + return nil, errExecutionReverted + } + return nil, nil +} + +func (g *GovernanceContract) resetDKG(newSignedCRS []byte) ([]byte, error) { + round := g.evm.Round + nextRound := new(big.Int).Add(round, big.NewInt(1)) + + // If no one call addDKGMasterPublicKey, DKG of previous round will not be + // cleared. + if g.state.DKGRound().Cmp(round) == 0 { + // Clear DKG states for next round. + g.clearDKG() + g.state.SetDKGRound(nextRound) + } + + resetCount := g.state.DKGResetCount(nextRound) + + // Just restart DEXON if failed at round 0. + if round.Cmp(big.NewInt(0)) == 0 { + return nil, errExecutionReverted + } + + // Extend the the current round. + // target = (85 + 100 * DKGResetCount)% + target := new(big.Int).Add( + big.NewInt(85), + new(big.Int).Mul(big.NewInt(100), resetCount)) + + roundHeight := g.state.RoundHeight(round) + gs, err := getConfigState(g.evm, round) + if err != nil { + return nil, err + } + config := gs.Configuration() + + targetBlockNum := new(big.Int).SetUint64(config.RoundLength) + targetBlockNum.Mul(targetBlockNum, target) + targetBlockNum.Quo(targetBlockNum, big.NewInt(100)) + targetBlockNum.Add(targetBlockNum, roundHeight) + + // Check if current block over 85%of current round. + blockHeight := g.evm.Context.BlockNumber + if blockHeight.Cmp(targetBlockNum) < 0 { + return nil, errExecutionReverted + } + + tsigThreshold := coreUtils.GetDKGThreshold(&coreTypes.Config{ + NotarySetSize: uint32(g.configNotarySetSize(nextRound).Uint64())}) + // Check if next DKG has not enough of success. + if g.state.DKGSuccessesCount().Uint64() >= + uint64(coreUtils.GetDKGValidThreshold(&coreTypes.Config{ + NotarySetSize: uint32(g.configNotarySetSize(nextRound).Uint64()), + })) { + // Check if next DKG did not success. + // Calculate 2f + 1 + threshold := 2*g.configNotarySetSize(nextRound).Uint64()/3 + 1 + + // If 2f + 1 of DKG set is finalized, check if DKG succeeded. + if g.state.DKGFinalizedsCount().Uint64() >= threshold { + gpk, err := g.coreDKGUtils.NewGroupPublicKey(&g.state, nextRound, tsigThreshold) + if gpk, ok := gpk.(*dkgTypes.GroupPublicKey); ok { + if len(gpk.QualifyNodeIDs) < coreUtils.GetDKGValidThreshold(&coreTypes.Config{ + NotarySetSize: uint32(g.configNotarySetSize(nextRound).Uint64())}) { + err = dkgTypes.ErrNotReachThreshold + } + } + + // DKG success. + if err == nil { + return nil, errExecutionReverted + } + switch err { + case dkgTypes.ErrNotReachThreshold, dkgTypes.ErrInvalidThreshold: + default: + return nil, errExecutionReverted + } + } + } + + // Fine fail stop DKGs. + g.fineFailStopDKG(tsigThreshold) + + // Update CRS. + state, err := getRoundState(g.evm, round) + if err != nil { + return nil, errExecutionReverted + } + prevCRS := state.CRS() + + // CRS(n) = hash(CRS(n-1)) if n <= core.DKGRoundDelay + if round.Uint64() == dexCore.DKGDelayRound { + for i := uint64(0); i < dexCore.DKGDelayRound; i++ { + prevCRS = crypto.Keccak256Hash(prevCRS[:]) + } + } + + for i := uint64(0); i < resetCount.Uint64()+1; i++ { + prevCRS = crypto.Keccak256Hash(prevCRS[:]) + } + + dkgGPK, err := g.coreDKGUtils.NewGroupPublicKey(state, round, + coreUtils.GetDKGThreshold(&coreTypes.Config{ + NotarySetSize: uint32(g.configNotarySetSize(round).Uint64())})) + if err != nil { + return nil, errExecutionReverted + } + signature := coreCrypto.Signature{ + Type: "bls", + Signature: newSignedCRS, + } + if !dkgGPK.VerifySignature(coreCommon.Hash(prevCRS), signature) { + return nil, errExecutionReverted + } + + // Clear DKG states for next round. + g.clearDKG() + g.state.SetDKGRound(nextRound) + + // Save new CRS into state and increase round. + newCRS := crypto.Keccak256(newSignedCRS) + crs := common.BytesToHash(newCRS) + + g.state.SetCRS(crs) + g.state.SetCRSRound(nextRound) + g.state.emitCRSProposed(nextRound, crs) + + // Increase reset count. + g.state.IncDKGResetCount(nextRound) + g.state.emitDKGReset(round, blockHeight) + + return nil, nil +} + +// Run executes governance contract. +func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *vm.Contract) (ret []byte, err error) { + if len(input) < 4 { + return nil, errExecutionReverted + } + + // Initialize contract state. + g.evm = evm + g.state = GovernanceState{evm.StateDB} + g.contract = contract + + // Parse input. + method, exists := GovernanceABI.Sig2Method[string(input[:4])] + if !exists { + return nil, errExecutionReverted + } + + arguments := input[4:] + + // Dispatch method call. + switch method.Name { + case "addDKGComplaint": + var Complaint []byte + if err := method.Inputs.Unpack(&Complaint, arguments); err != nil { + return nil, errExecutionReverted + } + return g.addDKGComplaint(Complaint) + case "addDKGMasterPublicKey": + var PublicKey []byte + if err := method.Inputs.Unpack(&PublicKey, arguments); err != nil { + return nil, errExecutionReverted + } + return g.addDKGMasterPublicKey(PublicKey) + case "addDKGMPKReady": + var MPKReady []byte + if err := method.Inputs.Unpack(&MPKReady, arguments); err != nil { + return nil, errExecutionReverted + } + return g.addDKGMPKReady(MPKReady) + case "addDKGFinalize": + var Finalize []byte + if err := method.Inputs.Unpack(&Finalize, arguments); err != nil { + return nil, errExecutionReverted + } + return g.addDKGFinalize(Finalize) + case "addDKGSuccess": + var Success []byte + if err := method.Inputs.Unpack(&Success, arguments); err != nil { + return nil, errExecutionReverted + } + return g.addDKGSuccess(Success) + case "nodesLength": + res, err := method.Outputs.Pack(g.state.LenNodes()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "payFine": + address := common.Address{} + if err := method.Inputs.Unpack(&address, arguments); err != nil { + return nil, errExecutionReverted + } + return g.payFine(address) + case "proposeCRS": + args := struct { + Round *big.Int + SignedCRS []byte + }{} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + return g.proposeCRS(args.Round, args.SignedCRS) + case "report": + args := struct { + Type *big.Int + Arg1 []byte + Arg2 []byte + }{} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + return g.report(args.Type, args.Arg1, args.Arg2) + case "resetDKG": + args := struct { + NewSignedCRS []byte + }{} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + return g.resetDKG(args.NewSignedCRS) + case "register": + args := struct { + PublicKey []byte + Name string + Email string + Location string + Url string + }{} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + return g.register(args.PublicKey, args.Name, args.Email, args.Location, args.Url) + case "stake": + return g.stake() + case "transferOwnership": + var newOwner common.Address + if err := method.Inputs.Unpack(&newOwner, arguments); err != nil { + return nil, errExecutionReverted + } + return g.transferOwnership(newOwner) + case "transferNodeOwnership": + var newOwner common.Address + if err := method.Inputs.Unpack(&newOwner, arguments); err != nil { + return nil, errExecutionReverted + } + return g.transferNodeOwnership(newOwner) + case "transferNodeOwnershipByFoundation": + args := struct { + OldOwner common.Address + NewOwner common.Address + }{} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + return g.transferNodeOwnershipByFoundation(args.OldOwner, args.NewOwner) + case "unstake": + amount := new(big.Int) + if err := method.Inputs.Unpack(&amount, arguments); err != nil { + return nil, errExecutionReverted + } + return g.unstake(amount) + case "updateConfiguration": + var cfg rawConfigStruct + if err := method.Inputs.Unpack(&cfg, arguments); err != nil { + return nil, errExecutionReverted + } + return g.updateConfiguration(&cfg) + case "withdraw": + return g.withdraw() + case "withdrawable": + res, err := method.Outputs.Pack(g.withdrawable()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + + // -------------------------------- + // Solidity auto generated methods. + // -------------------------------- + + case "blockGasLimit": + res, err := method.Outputs.Pack(g.state.BlockGasLimit()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "crs": + res, err := method.Outputs.Pack(g.state.CRS()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "crsRound": + res, err := method.Outputs.Pack(g.state.CRSRound()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "dkgComplaints": + offset := new(big.Int) + if err := method.Inputs.Unpack(&offset, arguments); err != nil { + return nil, errExecutionReverted + } + complaint := g.state.DKGComplaint(offset) + res, err := method.Outputs.Pack(complaint) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "dkgComplaintsProposed": + id := Bytes32{} + if err := method.Inputs.Unpack(&id, arguments); err != nil { + return nil, errExecutionReverted + } + proposed := g.state.DKGComplaintProposed(id) + res, err := method.Outputs.Pack(proposed) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "dkgFinalizeds": + addr := common.Address{} + if err := method.Inputs.Unpack(&addr, arguments); err != nil { + return nil, errExecutionReverted + } + finalized := g.state.DKGFinalized(addr) + res, err := method.Outputs.Pack(finalized) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "dkgFinalizedsCount": + count := g.state.DKGFinalizedsCount() + res, err := method.Outputs.Pack(count) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "dkgSuccesses": + addr := common.Address{} + if err := method.Inputs.Unpack(&addr, arguments); err != nil { + return nil, errExecutionReverted + } + finalized := g.state.DKGSuccess(addr) + res, err := method.Outputs.Pack(finalized) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "dkgSuccessesCount": + count := g.state.DKGSuccessesCount() + res, err := method.Outputs.Pack(count) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "dkgMasterPublicKeys": + offset := new(big.Int) + if err := method.Inputs.Unpack(&offset, arguments); err != nil { + return nil, errExecutionReverted + } + mpk := g.state.DKGMasterPublicKey(offset) + res, err := method.Outputs.Pack(mpk) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "dkgMasterPublicKeyOffset": + id := Bytes32{} + if err := method.Inputs.Unpack(&id, arguments); err != nil { + return nil, errExecutionReverted + } + offset := g.state.DKGMasterPublicKeyOffset(id) + res, err := method.Outputs.Pack(offset) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "dkgMPKReadys": + addr := common.Address{} + if err := method.Inputs.Unpack(&addr, arguments); err != nil { + return nil, errExecutionReverted + } + ready := g.state.DKGMPKReady(addr) + res, err := method.Outputs.Pack(ready) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "dkgMPKReadysCount": + count := g.state.DKGMPKReadysCount() + res, err := method.Outputs.Pack(count) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "dkgResetCount": + round := new(big.Int) + if err := method.Inputs.Unpack(&round, arguments); err != nil { + return nil, errExecutionReverted + } + res, err := method.Outputs.Pack(g.state.DKGResetCount(round)) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "dkgRound": + res, err := method.Outputs.Pack(g.state.DKGRound()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "finedRecords": + record := Bytes32{} + if err := method.Inputs.Unpack(&record, arguments); err != nil { + return nil, errExecutionReverted + } + value := g.state.FineRecords(record) + res, err := method.Outputs.Pack(value) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "fineValues": + index := new(big.Int) + if err := method.Inputs.Unpack(&index, arguments); err != nil { + return nil, errExecutionReverted + } + value := g.state.FineValue(index) + res, err := method.Outputs.Pack(value) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "lambdaBA": + res, err := method.Outputs.Pack(g.state.LambdaBA()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "lambdaDKG": + res, err := method.Outputs.Pack(g.state.LambdaDKG()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "lastHalvedAmount": + res, err := method.Outputs.Pack(g.state.LastHalvedAmount()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "lastProposedHeight": + address := common.Address{} + if err := method.Inputs.Unpack(&address, arguments); err != nil { + return nil, errExecutionReverted + } + res, err := method.Outputs.Pack(g.state.LastProposedHeight(address)) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "lockupPeriod": + res, err := method.Outputs.Pack(g.state.LockupPeriod()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "minBlockInterval": + res, err := method.Outputs.Pack(g.state.MinBlockInterval()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "minGasPrice": + res, err := method.Outputs.Pack(g.state.MinGasPrice()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "miningVelocity": + res, err := method.Outputs.Pack(g.state.MiningVelocity()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "minStake": + res, err := method.Outputs.Pack(g.state.MinStake()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "nextHalvingSupply": + res, err := method.Outputs.Pack(g.state.NextHalvingSupply()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "nodes": + index := new(big.Int) + if err := method.Inputs.Unpack(&index, arguments); err != nil { + return nil, errExecutionReverted + } + info := g.state.Node(index) + res, err := method.Outputs.Pack( + info.Owner, info.PublicKey, info.Staked, info.Fined, + info.Name, info.Email, info.Location, info.Url, + info.Unstaked, info.UnstakedAt) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "nodesOffsetByAddress": + address := common.Address{} + if err := method.Inputs.Unpack(&address, arguments); err != nil { + return nil, errExecutionReverted + } + res, err := method.Outputs.Pack(g.state.NodesOffsetByAddress(address)) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "nodesOffsetByNodeKeyAddress": + address := common.Address{} + if err := method.Inputs.Unpack(&address, arguments); err != nil { + return nil, errExecutionReverted + } + res, err := method.Outputs.Pack(g.state.NodesOffsetByNodeKeyAddress(address)) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "notarySetSize": + res, err := method.Outputs.Pack(g.state.NotarySetSize()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "notaryParamAlpha": + res, err := method.Outputs.Pack(g.state.NotaryParamAlpha()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "notaryParamBeta": + res, err := method.Outputs.Pack(g.state.NotaryParamBeta()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "owner": + res, err := method.Outputs.Pack(g.state.Owner()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "replaceNodePublicKey": + var pk []byte + if err := method.Inputs.Unpack(&pk, arguments); err != nil { + return nil, errExecutionReverted + } + return g.replaceNodePublicKey(pk) + case "roundHeight": + round := new(big.Int) + if err := method.Inputs.Unpack(&round, arguments); err != nil { + return nil, errExecutionReverted + } + res, err := method.Outputs.Pack(g.state.RoundHeight(round)) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "roundLength": + res, err := method.Outputs.Pack(g.state.RoundLength()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "totalStaked": + res, err := method.Outputs.Pack(g.state.TotalStaked()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "totalSupply": + res, err := method.Outputs.Pack(g.state.TotalSupply()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + } + return nil, errExecutionReverted +} + +func (g *GovernanceContract) transferOwnership(newOwner common.Address) ([]byte, error) { + // Only owner can update configuration. + if g.contract.Caller() != g.state.Owner() { + return nil, errExecutionReverted + } + if newOwner == (common.Address{}) { + return nil, errExecutionReverted + } + g.state.SetOwner(newOwner) + return nil, nil +} + +func (g *GovernanceContract) transferNodeOwnership(newOwner common.Address) ([]byte, error) { + if newOwner == (common.Address{}) { + return nil, errExecutionReverted + } + caller := g.contract.Caller() + + offset := g.state.NodesOffsetByAddress(caller) + if offset.Cmp(big.NewInt(0)) < 0 { + return nil, errExecutionReverted + } + + newOffset := g.state.NodesOffsetByAddress(newOwner) + if newOffset.Cmp(big.NewInt(0)) >= 0 { + return nil, errExecutionReverted + } + + node := g.state.Node(offset) + g.state.DeleteNodeOffsets(node) + + node.Owner = newOwner + g.state.PutNodeOffsets(node, offset) + g.state.UpdateNode(offset, node) + + g.state.emitNodeOwnershipTransfered(caller, newOwner) + + return nil, nil +} + +func (g *GovernanceContract) transferNodeOwnershipByFoundation(oldOwner, newOwner common.Address) ([]byte, error) { + // Only owner can update configuration. + if g.contract.Caller() != g.state.Owner() { + return nil, errExecutionReverted + } + + if newOwner == (common.Address{}) { + return nil, errExecutionReverted + } + + offset := g.state.NodesOffsetByAddress(oldOwner) + if offset.Cmp(big.NewInt(0)) < 0 { + return nil, errExecutionReverted + } + + newOffset := g.state.NodesOffsetByAddress(newOwner) + if newOffset.Cmp(big.NewInt(0)) >= 0 { + return nil, errExecutionReverted + } + + node := g.state.Node(offset) + g.state.DeleteNodeOffsets(node) + + node.Owner = newOwner + g.state.PutNodeOffsets(node, offset) + g.state.UpdateNode(offset, node) + + g.state.emitNodeOwnershipTransfered(oldOwner, newOwner) + + return nil, nil +} + +func (g *GovernanceContract) replaceNodePublicKey(newPublicKey []byte) ([]byte, error) { + caller := g.contract.Caller() + + offset := g.state.NodesOffsetByAddress(caller) + if offset.Cmp(big.NewInt(0)) < 0 { + return nil, errExecutionReverted + } + + node := g.state.Node(offset) + + _, err := publicKeyToNodeKeyAddress(newPublicKey) + if err != nil { + return nil, errExecutionReverted + } + + g.state.DeleteNodeOffsets(node) + + node.PublicKey = newPublicKey + g.state.PutNodeOffsets(node, offset) + g.state.UpdateNode(offset, node) + + g.state.emitNodePublicKeyReplaced(caller, newPublicKey) + + return nil, nil +} + +func PackProposeCRS(round uint64, signedCRS []byte) ([]byte, error) { + method := GovernanceABI.Name2Method["proposeCRS"] + res, err := method.Inputs.Pack(big.NewInt(int64(round)), signedCRS) + if err != nil { + return nil, err + } + data := append(method.Id(), res...) + return data, nil +} + +func PackAddDKGMasterPublicKey(mpk *dkgTypes.MasterPublicKey) ([]byte, error) { + method := GovernanceABI.Name2Method["addDKGMasterPublicKey"] + encoded, err := rlp.EncodeToBytes(mpk) + if err != nil { + return nil, err + } + res, err := method.Inputs.Pack(encoded) + if err != nil { + return nil, err + } + data := append(method.Id(), res...) + return data, nil +} + +func PackAddDKGMPKReady(ready *dkgTypes.MPKReady) ([]byte, error) { + method := GovernanceABI.Name2Method["addDKGMPKReady"] + encoded, err := rlp.EncodeToBytes(ready) + if err != nil { + return nil, err + } + res, err := method.Inputs.Pack(encoded) + if err != nil { + return nil, err + } + data := append(method.Id(), res...) + return data, nil +} + +func PackAddDKGComplaint(complaint *dkgTypes.Complaint) ([]byte, error) { + method := GovernanceABI.Name2Method["addDKGComplaint"] + encoded, err := rlp.EncodeToBytes(complaint) + if err != nil { + return nil, err + } + + res, err := method.Inputs.Pack(encoded) + if err != nil { + return nil, err + } + data := append(method.Id(), res...) + return data, nil +} + +func PackAddDKGFinalize(final *dkgTypes.Finalize) ([]byte, error) { + method := GovernanceABI.Name2Method["addDKGFinalize"] + encoded, err := rlp.EncodeToBytes(final) + if err != nil { + return nil, err + } + + res, err := method.Inputs.Pack(encoded) + if err != nil { + return nil, err + } + data := append(method.Id(), res...) + return data, nil +} + +func PackAddDKGSuccess(final *dkgTypes.Success) ([]byte, error) { + method := GovernanceABI.Name2Method["addDKGSuccess"] + encoded, err := rlp.EncodeToBytes(final) + if err != nil { + return nil, err + } + + res, err := method.Inputs.Pack(encoded) + if err != nil { + return nil, err + } + data := append(method.Id(), res...) + return data, nil +} + +func PackReportForkVote(vote1, vote2 *coreTypes.Vote) ([]byte, error) { + method := GovernanceABI.Name2Method["report"] + + vote1Bytes, err := rlp.EncodeToBytes(vote1) + if err != nil { + return nil, err + } + + vote2Bytes, err := rlp.EncodeToBytes(vote2) + if err != nil { + return nil, err + } + + res, err := method.Inputs.Pack(big.NewInt(FineTypeForkVote), vote1Bytes, vote2Bytes) + if err != nil { + return nil, err + } + data := append(method.Id(), res...) + return data, nil +} + +func PackReportForkBlock(block1, block2 *coreTypes.Block) ([]byte, error) { + method := GovernanceABI.Name2Method["report"] + + block1Bytes, err := rlp.EncodeToBytes(block1) + if err != nil { + return nil, err + } + + block2Bytes, err := rlp.EncodeToBytes(block2) + if err != nil { + return nil, err + } + + res, err := method.Inputs.Pack(big.NewInt(FineTypeForkBlock), block1Bytes, block2Bytes) + if err != nil { + return nil, err + } + data := append(method.Id(), res...) + return data, nil +} + +func PackResetDKG(newSignedCRS []byte) ([]byte, error) { + method := GovernanceABI.Name2Method["resetDKG"] + res, err := method.Inputs.Pack(newSignedCRS) + if err != nil { + return nil, err + } + data := append(method.Id(), res...) + return data, nil +} diff --git a/core/vm/evm/oracle_contracts_test.go b/core/vm/evm/oracle_contracts_test.go new file mode 100644 index 000000000..41bf0fb58 --- /dev/null +++ b/core/vm/evm/oracle_contracts_test.go @@ -0,0 +1,1203 @@ +// Copyright 2018 The dexon-consensus Authors +// This file is part of the dexon-consensus library. +// +// The dexon-consensus library is free software: you can redistribute it +// and/or modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation, either version 3 of the License, +// or (at your option) any later version. +// +// The dexon-consensus library is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +// General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the dexon-consensus library. If not, see +// . + +package evm + +import ( + "bytes" + "crypto/ecdsa" + "math/big" + "math/rand" + "sort" + "testing" + "time" + + coreCommon "github.com/dexon-foundation/dexon-consensus/common" + dexCore "github.com/dexon-foundation/dexon-consensus/core" + coreCrypto "github.com/dexon-foundation/dexon-consensus/core/crypto" + coreEcdsa "github.com/dexon-foundation/dexon-consensus/core/crypto/ecdsa" + coreTypes "github.com/dexon-foundation/dexon-consensus/core/types" + dkgTypes "github.com/dexon-foundation/dexon-consensus/core/types/dkg" + coreUtils "github.com/dexon-foundation/dexon-consensus/core/utils" + + "github.com/dexon-foundation/dexon/common" + "github.com/dexon-foundation/dexon/core/state" + "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/crypto" + "github.com/dexon-foundation/dexon/ethdb" + "github.com/dexon-foundation/dexon/params" + "github.com/dexon-foundation/dexon/rlp" + "github.com/stretchr/testify/suite" +) + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +func randomBytes(minLength, maxLength int32) []byte { + length := minLength + if maxLength != minLength { + length += rand.Int31() % (maxLength - minLength) + } + b := make([]byte, length) + for i := range b { + b[i] = byte(65 + rand.Int31()%60) + } + return b +} + +func newPrefundAccount(s *state.StateDB) (*ecdsa.PrivateKey, common.Address) { + privKey, err := crypto.GenerateKey() + if err != nil { + panic(err) + } + address := crypto.PubkeyToAddress(privKey.PublicKey) + + s.AddBalance(address, new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2e6))) + return privKey, address +} + +type GovernanceStateTestSuite struct { + suite.Suite + + stateDB *state.StateDB + s *GovernanceState +} + +func (g *GovernanceStateTestSuite) SetupTest() { + db := state.NewDatabase(ethdb.NewMemDatabase()) + statedb, err := state.New(common.Hash{}, db) + if err != nil { + panic(err) + } + g.stateDB = statedb + g.s = &GovernanceState{statedb} + + config := params.TestnetChainConfig.Dexcon + g.s.Initialize(config, new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e7))) + + statedb.AddBalance(GovernanceContractAddress, big.NewInt(1)) + statedb.Commit(true) +} + +func (g *GovernanceStateTestSuite) TestReadWriteEraseBytes() { + for i := 0; i < 100; i++ { + // Short bytes. + loc := big.NewInt(rand.Int63()) + data := randomBytes(3, 32) + g.s.writeBytes(loc, data) + read := g.s.readBytes(loc) + g.Require().Equal(0, bytes.Compare(data, read)) + g.s.eraseBytes(loc) + read = g.s.readBytes(loc) + g.Require().Len(read, 0) + + // long bytes. + loc = big.NewInt(rand.Int63()) + data = randomBytes(33, 2560) + g.s.writeBytes(loc, data) + read = g.s.readBytes(loc) + g.Require().Equal(0, bytes.Compare(data, read)) + g.s.eraseBytes(loc) + read = g.s.readBytes(loc) + g.Require().Len(read, 0) + } +} + +func (g *GovernanceStateTestSuite) TestReadWriteErase1DArray() { + emptyOffset := 100 + for j := 0; j < 50; j++ { + idx := big.NewInt(int64(j + emptyOffset)) + data := make([][]byte, 30) + for key := range data { + data[key] = randomBytes(3, 32) + g.s.appendTo1DByteArray(idx, data[key]) + } + read := g.s.read1DByteArray(idx) + g.Require().Len(read, len(data)) + for key := range data { + g.Require().Equal(0, bytes.Compare(data[key], read[key])) + } + g.s.erase1DByteArray(idx) + read = g.s.read1DByteArray(idx) + g.Require().Len(read, 0) + } +} + +func (g *GovernanceStateTestSuite) TestDisqualify() { + privKey, addr := newPrefundAccount(g.stateDB) + pk := crypto.FromECDSAPub(&privKey.PublicKey) + + g.s.Register(addr, pk, "Test", "test@dexon.org", "Taipei", "https://test.com", g.s.MinStake()) + + node := g.s.Node(big.NewInt(0)) + g.Require().Equal(uint64(0), node.Fined.Uint64()) + + // Disqualify + g.s.Disqualify(node) + node = g.s.Node(big.NewInt(0)) + g.Require().Equal(uint64(0xd78ebc5ac6200000), node.Fined.Uint64()) + + // Disqualify none exist node should return error. + privKey2, _ := newPrefundAccount(g.stateDB) + node.PublicKey = crypto.FromECDSAPub(&privKey2.PublicKey) + g.Require().Error(g.s.Disqualify(node)) +} + +func TestGovernanceState(t *testing.T) { + suite.Run(t, new(GovernanceStateTestSuite)) +} + +type OracleContractsTestSuite struct { + suite.Suite + + context vm.Context + config *params.DexconConfig + memDB *ethdb.MemDatabase + stateDB *state.StateDB + s *GovernanceState +} + +func (g *OracleContractsTestSuite) SetupTest() { + memDB := ethdb.NewMemDatabase() + stateDB, err := state.New(common.Hash{}, state.NewDatabase(memDB)) + if err != nil { + panic(err) + } + g.memDB = memDB + g.stateDB = stateDB + g.s = &GovernanceState{stateDB} + + config := params.TestnetChainConfig.Dexcon + config.LockupPeriod = 1000 + config.NextHalvingSupply = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2.5e9)) + config.LastHalvedAmount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1.5e9)) + config.MiningVelocity = 0.1875 + config.NotarySetSize = 7 + + g.config = config + + // Give governance contract balance so it will not be deleted because of being an empty state object. + stateDB.AddBalance(GovernanceContractAddress, big.NewInt(1)) + + // Genesis CRS. + crs := crypto.Keccak256Hash([]byte(config.GenesisCRSText)) + g.s.SetCRS(crs) + + // Round 0 height. + g.s.PushRoundHeight(big.NewInt(0)) + + // Owner. + g.s.SetOwner(g.config.Owner) + + // Governance configuration. + g.s.UpdateConfiguration(config) + + g.stateDB.Commit(true) + + g.context = vm.Context{ + CanTransfer: func(db vm.StateDB, addr common.Address, amount *big.Int) bool { + return db.GetBalance(addr).Cmp(amount) >= 0 + }, + Transfer: func(db vm.StateDB, sender common.Address, recipient common.Address, amount *big.Int) { + db.SubBalance(sender, amount) + db.AddBalance(recipient, amount) + }, + GetRoundHeight: func(round uint64) (uint64, bool) { + switch round { + case 0: + return 0, true + case 1: + return 1000, true + case 2: + return 2000, true + } + return 0, false + }, + StateAtNumber: func(n uint64) (*state.StateDB, error) { + return g.stateDB, nil + }, + BlockNumber: big.NewInt(0), + } + +} + +func (g *OracleContractsTestSuite) TearDownTest() { + OracleContracts[GovernanceContractAddress] = func() OracleContract { + return &GovernanceContract{ + coreDKGUtils: &defaultCoreDKGUtils{}, + } + } +} + +func (g *OracleContractsTestSuite) call( + contractAddr common.Address, caller common.Address, input []byte, value *big.Int) ([]byte, error) { + + g.context.Time = big.NewInt(time.Now().UnixNano() / 1000000) + + evm := NewEVM(g.context, g.stateDB, params.TestChainConfig, Config{IsBlockProposer: true}) + ret, _, err := evm.Call(vm.AccountRef(caller), contractAddr, input, 10000000, value) + return ret, err +} + +func (g *OracleContractsTestSuite) TestTransferOwnership() { + input, err := GovernanceABI.ABI.Pack("transferOwnership", common.Address{}) + g.Require().NoError(err) + // Call with owner but invalid new owner. + _, err = g.call(GovernanceContractAddress, g.config.Owner, input, big.NewInt(0)) + g.Require().NotNil(err) + + _, addr := newPrefundAccount(g.stateDB) + + input, err = GovernanceABI.ABI.Pack("transferOwnership", addr) + g.Require().NoError(err) + + // Call with non-owner. + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NotNil(err) + + // Call with owner. + _, err = g.call(GovernanceContractAddress, g.config.Owner, input, big.NewInt(0)) + g.Require().NoError(err) + g.Require().Equal(addr, g.s.Owner()) +} + +func (g *OracleContractsTestSuite) TestTransferNodeOwnership() { + privKey, addr := newPrefundAccount(g.stateDB) + pk := crypto.FromECDSAPub(&privKey.PublicKey) + + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)) + input, err := GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, amount) + g.Require().NoError(err) + + // Call with not valid new owner. + input, err = GovernanceABI.ABI.Pack("transferNodeOwnership", common.Address{}) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NotNil(err) + + _, newAddr := newPrefundAccount(g.stateDB) + + input, err = GovernanceABI.ABI.Pack("transferNodeOwnership", newAddr) + g.Require().NoError(err) + + // Call with non-owner. + _, noneOwner := newPrefundAccount(g.stateDB) + _, err = g.call(GovernanceContractAddress, noneOwner, input, big.NewInt(0)) + g.Require().Error(err) + + // Call with owner. + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + g.Require().Equal(-1, int(g.s.NodesOffsetByAddress(addr).Int64())) + g.Require().Equal(0, int(g.s.NodesOffsetByNodeKeyAddress(addr).Int64())) + g.Require().Equal(0, int(g.s.NodesOffsetByAddress(newAddr).Int64())) + + // New node for duplication test. + privKey2, addr2 := newPrefundAccount(g.stateDB) + pk2 := crypto.FromECDSAPub(&privKey2.PublicKey) + input, err = GovernanceABI.ABI.Pack("register", pk2, "Test2", "test1@dexon.org", "Taipei", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr2, input, amount) + g.Require().NoError(err) + + // Transfer to duplicate owner address. + input, err = GovernanceABI.ABI.Pack("transferNodeOwnership", addr2) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, newAddr, input, amount) + g.Require().Error(err) +} + +func (g *OracleContractsTestSuite) TestTransferNodeOwnershipByFoundation() { + privKey, addr := newPrefundAccount(g.stateDB) + pk := crypto.FromECDSAPub(&privKey.PublicKey) + + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)) + input, err := GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, amount) + g.Require().NoError(err) + + _, newAddr := newPrefundAccount(g.stateDB) + + // Call with not valid new owner. + input, err = GovernanceABI.ABI.Pack("transferNodeOwnershipByFoundation", common.Address{}, newAddr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NotNil(err) + + input, err = GovernanceABI.ABI.Pack("transferNodeOwnershipByFoundation", addr, newAddr) + g.Require().NoError(err) + + // Call with gov owner. + _, noneOwner := newPrefundAccount(g.stateDB) + _, err = g.call(GovernanceContractAddress, noneOwner, input, big.NewInt(0)) + g.Require().Error(err) + + // Call with gov owner. + _, err = g.call(GovernanceContractAddress, g.config.Owner, input, big.NewInt(0)) + g.Require().NoError(err) + g.Require().Equal(-1, int(g.s.NodesOffsetByAddress(addr).Int64())) + g.Require().Equal(0, int(g.s.NodesOffsetByNodeKeyAddress(addr).Int64())) + g.Require().Equal(0, int(g.s.NodesOffsetByAddress(newAddr).Int64())) +} + +func (g *OracleContractsTestSuite) TestReplaceNodePublicKey() { + privKey, addr := newPrefundAccount(g.stateDB) + pk := crypto.FromECDSAPub(&privKey.PublicKey) + + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)) + input, err := GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, amount) + g.Require().NoError(err) + + privKey2, addr2 := newPrefundAccount(g.stateDB) + pk2 := crypto.FromECDSAPub(&privKey2.PublicKey) + + input, err = GovernanceABI.ABI.Pack("replaceNodePublicKey", pk2) + g.Require().NoError(err) + + // Call with non-owner. + _, noneOwner := newPrefundAccount(g.stateDB) + _, err = g.call(GovernanceContractAddress, noneOwner, input, big.NewInt(0)) + g.Require().Error(err) + + // Call with owner. + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + g.Require().Equal(-1, int(g.s.NodesOffsetByNodeKeyAddress(addr).Int64())) + g.Require().Equal(0, int(g.s.NodesOffsetByAddress(addr).Int64())) + g.Require().Equal(0, int(g.s.NodesOffsetByNodeKeyAddress(addr2).Int64())) +} + +func (g *OracleContractsTestSuite) TestStakingMechanism() { + privKey, addr := newPrefundAccount(g.stateDB) + pk := crypto.FromECDSAPub(&privKey.PublicKey) + + // Register with some stake. + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) + balanceBeforeStake := g.stateDB.GetBalance(addr) + input, err := GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, amount) + g.Require().NoError(err) + + g.Require().Equal(1, int(g.s.LenNodes().Uint64())) + g.Require().Equal(0, len(g.s.QualifiedNodes())) + g.Require().Equal("Test1", g.s.Node(big.NewInt(0)).Name) + g.Require().Equal(amount.String(), g.s.TotalStaked().String()) + + // Check balance. + g.Require().Equal(new(big.Int).Sub(balanceBeforeStake, amount), g.stateDB.GetBalance(addr)) + g.Require().Equal(new(big.Int).Add(big.NewInt(1), amount), g.stateDB.GetBalance(GovernanceContractAddress)) + + // Registering again should fail. + _, err = g.call(GovernanceContractAddress, addr, input, amount) + g.Require().Error(err) + + // Duplicate public key should fail + _, addrDup := newPrefundAccount(g.stateDB) + input, err = GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addrDup, input, amount) + g.Require().Error(err) + + // Stake more to qualify. + input, err = GovernanceABI.ABI.Pack("stake") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, amount) + g.Require().NoError(err) + g.Require().Equal(1, len(g.s.QualifiedNodes())) + g.Require().Equal(new(big.Int).Add(amount, amount).String(), g.s.TotalStaked().String()) + + // Unstake more then staked should fail. + unstakeAmount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e6)) + input, err = GovernanceABI.ABI.Pack("unstake", unstakeAmount) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().Error(err) + + // Unstake. + input, err = GovernanceABI.ABI.Pack("unstake", amount) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + g.Require().Equal(0, len(g.s.QualifiedNodes())) + g.Require().Equal(amount.String(), g.s.TotalStaked().String()) + + var ok bool + // Withdraw immediately should fail. + input, err = GovernanceABI.ABI.Pack("withdrawable") + g.Require().NoError(err) + output, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + GovernanceABI.ABI.Unpack(&ok, "withdrawable", output) + g.Require().False(ok) + input, err = GovernanceABI.ABI.Pack("withdraw") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().Error(err) + + // Wait for lockup time than withdraw. + input, err = GovernanceABI.ABI.Pack("withdrawable") + g.Require().NoError(err) + output, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + GovernanceABI.ABI.Unpack(&ok, "withdrawable", output) + g.Require().False(ok) + time.Sleep(time.Second * 2) + input, err = GovernanceABI.ABI.Pack("withdraw") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + g.Require().Equal(0, len(g.s.QualifiedNodes())) + g.Require().Equal(1, int(g.s.LenNodes().Uint64())) + + // Unstake all to remove node. + input, err = GovernanceABI.ABI.Pack("unstake", amount) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + time.Sleep(time.Second * 2) + input, err = GovernanceABI.ABI.Pack("withdrawable") + g.Require().NoError(err) + output, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + GovernanceABI.ABI.Unpack(&ok, "withdrawable", output) + g.Require().True(ok) + input, err = GovernanceABI.ABI.Pack("withdraw") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + g.Require().Equal(0, len(g.s.QualifiedNodes())) + g.Require().Equal(0, int(g.s.LenNodes().Uint64())) + + node := g.s.Node(big.NewInt(0)) + g.Require().Equal(big.NewInt(0).String(), node.Staked.String()) + g.Require().Equal(big.NewInt(0).String(), g.s.TotalStaked().String()) + + // Stake 2 nodes, and unstake the first then the second. + amount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)) + + // 2nd node Stake. + privKey2, addr2 := newPrefundAccount(g.stateDB) + pk2 := crypto.FromECDSAPub(&privKey2.PublicKey) + input, err = GovernanceABI.ABI.Pack("register", pk2, "Test2", "test2@dexon.org", "Taipei", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr2, input, amount) + g.Require().NoError(err) + g.Require().Equal("Test2", g.s.Node(big.NewInt(0)).Name) + g.Require().Equal(0, int(g.s.NodesOffsetByAddress(addr2).Int64())) + + // 1st node Stake. + input, err = GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, amount) + g.Require().NoError(err) + + g.Require().Equal(2, int(g.s.LenNodes().Uint64())) + g.Require().Equal(2, len(g.s.QualifiedNodes())) + g.Require().Equal(new(big.Int).Mul(amount, big.NewInt(2)).String(), g.s.TotalStaked().String()) + + // 2nd node Unstake. + input, err = GovernanceABI.ABI.Pack("unstake", amount) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr2, input, big.NewInt(0)) + g.Require().NoError(err) + + node = g.s.Node(big.NewInt(0)) + g.Require().Equal("Test2", node.Name) + g.Require().Equal(big.NewInt(0).String(), node.Staked.String()) + g.Require().Equal(1, len(g.s.QualifiedNodes())) + g.Require().Equal(amount.String(), g.s.TotalStaked().String()) + + time.Sleep(time.Second * 2) + input, err = GovernanceABI.ABI.Pack("withdraw") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr2, input, big.NewInt(0)) + g.Require().NoError(err) + + g.Require().Equal(1, len(g.s.QualifiedNodes())) + g.Require().Equal(1, int(g.s.LenNodes().Uint64())) + g.Require().Equal("Test1", g.s.Node(big.NewInt(0)).Name) + g.Require().Equal(-1, int(g.s.NodesOffsetByAddress(addr2).Int64())) + + // 1st node Unstake. + input, err = GovernanceABI.ABI.Pack("unstake", amount) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + g.Require().Equal(0, len(g.s.QualifiedNodes())) + g.Require().Equal(big.NewInt(0).String(), g.s.TotalStaked().String()) + + time.Sleep(time.Second * 2) + input, err = GovernanceABI.ABI.Pack("withdraw") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + g.Require().Equal(0, int(g.s.LenNodes().Uint64())) + g.Require().Equal(-1, int(g.s.NodesOffsetByAddress(addr).Int64())) + + // Check balance. + g.Require().Equal(balanceBeforeStake, g.stateDB.GetBalance(addr)) + g.Require().Equal(balanceBeforeStake, g.stateDB.GetBalance(addr2)) + g.Require().Equal(big.NewInt(1), g.stateDB.GetBalance(GovernanceContractAddress)) +} + +func (g *OracleContractsTestSuite) TestFine() { + privKey, addr := newPrefundAccount(g.stateDB) + pk := crypto.FromECDSAPub(&privKey.PublicKey) + + // Stake. + input, err := GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org") + g.Require().NoError(err) + ownerStaked := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)) + _, err = g.call(GovernanceContractAddress, addr, input, ownerStaked) + g.Require().NoError(err) + g.Require().Equal(1, len(g.s.QualifiedNodes())) + g.Require().Equal(ownerStaked, g.s.Node(big.NewInt(0)).Staked) + + _, finePayer := newPrefundAccount(g.stateDB) + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) + + // Paying to node without fine should fail. + input, err = GovernanceABI.ABI.Pack("payFine", addr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, finePayer, input, amount) + g.Require().NotNil(err) + + // Fined. + offset := g.s.NodesOffsetByAddress(addr) + g.Require().True(offset.Cmp(big.NewInt(0)) >= 0) + node := g.s.Node(offset) + node.Fined = new(big.Int).Set(amount) + g.s.UpdateNode(offset, node) + node = g.s.Node(offset) + g.Require().Equal(0, node.Fined.Cmp(amount)) + + // Not qualified after fined. + g.Require().Equal(0, len(g.s.QualifiedNodes())) + + // Cannot unstake before fines are paied. + input, err = GovernanceABI.ABI.Pack("unstake", big.NewInt(10)) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, finePayer, input, big.NewInt(0)) + g.Require().NotNil(err) + + // Paying more than fine should fail. + payAmount := new(big.Int).Add(amount, amount) + input, err = GovernanceABI.ABI.Pack("payFine", addr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, finePayer, input, payAmount) + g.Require().NotNil(err) + + // Pay the fine. + input, err = GovernanceABI.ABI.Pack("payFine", addr) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, finePayer, input, amount) + g.Require().NoError(err) + + // Qualified. + g.Require().Equal(1, len(g.s.QualifiedNodes())) +} + +func (g *OracleContractsTestSuite) TestUpdateConfiguration() { + _, addr := newPrefundAccount(g.stateDB) + + input, err := GovernanceABI.ABI.Pack("updateConfiguration", + new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)), + big.NewInt(1000), + big.NewInt(2e9), + big.NewInt(8000000), + big.NewInt(250), + big.NewInt(2500), + big.NewInt(int64(70.5*decimalMultiplier)), + big.NewInt(264*decimalMultiplier), + big.NewInt(600), + big.NewInt(900), + []*big.Int{big.NewInt(1), big.NewInt(1), big.NewInt(1), big.NewInt(1), big.NewInt(1)}) + g.Require().NoError(err) + + // Call with non-owner. + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NotNil(err) + + // Call with owner. + _, err = g.call(GovernanceContractAddress, g.config.Owner, input, big.NewInt(0)) + g.Require().NoError(err) +} + +func (g *OracleContractsTestSuite) TestConfigurationReading() { + _, addr := newPrefundAccount(g.stateDB) + + // CRS. + input, err := GovernanceABI.ABI.Pack("crs") + g.Require().NoError(err) + res, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + var crs0 [32]byte + err = GovernanceABI.ABI.Unpack(&crs0, "crs", res) + g.Require().NoError(err) + g.Require().Equal(crypto.Keccak256Hash([]byte(g.config.GenesisCRSText)), + common.BytesToHash(crs0[:])) + + // CRSRound. + input, err = GovernanceABI.ABI.Pack("crsRound") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + // Owner. + input, err = GovernanceABI.ABI.Pack("owner") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + var owner common.Address + err = GovernanceABI.ABI.Unpack(&owner, "owner", res) + g.Require().NoError(err) + g.Require().Equal(g.config.Owner, owner) + + // MinStake. + input, err = GovernanceABI.ABI.Pack("minStake") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + var value *big.Int + err = GovernanceABI.ABI.Unpack(&value, "minStake", res) + g.Require().NoError(err) + g.Require().Equal(g.config.MinStake.String(), value.String()) + + // BlockReward. + input, err = GovernanceABI.ABI.Pack("miningVelocity") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "miningVelocity", res) + g.Require().NoError(err) + g.Require().Equal(g.config.MiningVelocity, float32(value.Uint64())/decimalMultiplier) + + // BlockGasLimit. + input, err = GovernanceABI.ABI.Pack("blockGasLimit") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "blockGasLimit", res) + g.Require().NoError(err) + g.Require().Equal(g.config.BlockGasLimit, value.Uint64()) + + // LambdaBA. + input, err = GovernanceABI.ABI.Pack("lambdaBA") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "lambdaBA", res) + g.Require().NoError(err) + g.Require().Equal(g.config.LambdaBA, value.Uint64()) + + // LambdaDKG. + input, err = GovernanceABI.ABI.Pack("lambdaDKG") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "lambdaDKG", res) + g.Require().NoError(err) + g.Require().Equal(g.config.LambdaDKG, value.Uint64()) + + // NotarySetSize. + input, err = GovernanceABI.ABI.Pack("notarySetSize") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "notarySetSize", res) + g.Require().NoError(err) + g.Require().True(uint32(value.Uint64()) > 0) + + // DKGRound. + input, err = GovernanceABI.ABI.Pack("dkgRound") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + // DKGResetCount. + input, err = GovernanceABI.ABI.Pack("dkgResetCount", big.NewInt(3)) + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + // RoundLength. + input, err = GovernanceABI.ABI.Pack("roundLength") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "roundLength", res) + g.Require().NoError(err) + g.Require().Equal(g.config.RoundLength, value.Uint64()) + + // MinBlockInterval. + input, err = GovernanceABI.ABI.Pack("minBlockInterval") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "minBlockInterval", res) + g.Require().NoError(err) + g.Require().Equal(g.config.MinBlockInterval, value.Uint64()) + + // MinGasPrice. + input, err = GovernanceABI.ABI.Pack("minGasPrice") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "minGasPrice", res) + g.Require().NoError(err) + g.Require().Equal(g.config.MinGasPrice, value) +} + +func (g *OracleContractsTestSuite) TestReportForkVote() { + key, addr := newPrefundAccount(g.stateDB) + pkBytes := crypto.FromECDSAPub(&key.PublicKey) + + // Stake. + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) + input, err := GovernanceABI.ABI.Pack("register", pkBytes, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, amount) + g.Require().NoError(err) + + pubKey := coreEcdsa.NewPublicKeyFromECDSA(&key.PublicKey) + privKey := coreEcdsa.NewPrivateKeyFromECDSA(key) + vote1 := coreTypes.NewVote(coreTypes.VoteCom, coreCommon.NewRandomHash(), uint64(0)) + vote1.ProposerID = coreTypes.NewNodeID(pubKey) + + vote2 := vote1.Clone() + for vote2.BlockHash == vote1.BlockHash { + vote2.BlockHash = coreCommon.NewRandomHash() + } + vote1.Signature, err = privKey.Sign(coreUtils.HashVote(vote1)) + g.Require().NoError(err) + vote2.Signature, err = privKey.Sign(coreUtils.HashVote(vote2)) + g.Require().NoError(err) + + vote1Bytes, err := rlp.EncodeToBytes(vote1) + g.Require().NoError(err) + vote2Bytes, err := rlp.EncodeToBytes(vote2) + g.Require().NoError(err) + + // Report wrong type (fork block) + input, err = GovernanceABI.ABI.Pack("report", big.NewInt(FineTypeForkBlock), vote1Bytes, vote2Bytes) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().Error(err) + + input, err = GovernanceABI.ABI.Pack("report", big.NewInt(FineTypeForkVote), vote1Bytes, vote2Bytes) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + node := g.s.Node(big.NewInt(0)) + g.Require().Equal(node.Fined, g.s.FineValue(big.NewInt(FineTypeForkVote))) + + // Duplicate report should fail. + input, err = GovernanceABI.ABI.Pack("report", big.NewInt(FineTypeForkVote), vote1Bytes, vote2Bytes) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().Error(err) + + // Check if finedRecords is set. + payloads := [][]byte{vote1Bytes, vote2Bytes} + sort.Sort(sortBytes(payloads)) + + hash := Bytes32(crypto.Keccak256Hash(payloads...)) + input, err = GovernanceABI.ABI.Pack("finedRecords", hash) + g.Require().NoError(err) + res, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + var value bool + err = GovernanceABI.ABI.Unpack(&value, "finedRecords", res) + g.Require().NoError(err) + g.Require().True(value) +} + +func (g *OracleContractsTestSuite) TestReportForkBlock() { + key, addr := newPrefundAccount(g.stateDB) + pkBytes := crypto.FromECDSAPub(&key.PublicKey) + + // Stake. + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) + input, err := GovernanceABI.ABI.Pack("register", pkBytes, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, amount) + g.Require().NoError(err) + + privKey := coreEcdsa.NewPrivateKeyFromECDSA(key) + block1 := &coreTypes.Block{ + ProposerID: coreTypes.NewNodeID(privKey.PublicKey()), + ParentHash: coreCommon.NewRandomHash(), + Timestamp: time.Now(), + } + + block2 := block1.Clone() + for block2.ParentHash == block1.ParentHash { + block2.ParentHash = coreCommon.NewRandomHash() + } + + hashBlock := func(block *coreTypes.Block) coreCommon.Hash { + block.PayloadHash = coreCrypto.Keccak256Hash(block.Payload) + var err error + block.Hash, err = coreUtils.HashBlock(block) + g.Require().NoError(err) + return block.Hash + } + + block1.Signature, err = privKey.Sign(hashBlock(block1)) + g.Require().NoError(err) + block2.Signature, err = privKey.Sign(hashBlock(block2)) + g.Require().NoError(err) + + block1Bytes, err := rlp.EncodeToBytes(block1) + g.Require().NoError(err) + block2Bytes, err := rlp.EncodeToBytes(block2) + g.Require().NoError(err) + + // Report wrong type (fork vote) + input, err = GovernanceABI.ABI.Pack("report", big.NewInt(FineTypeForkVote), block1Bytes, block2Bytes) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().Error(err) + + input, err = GovernanceABI.ABI.Pack("report", big.NewInt(FineTypeForkBlock), block1Bytes, block2Bytes) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + node := g.s.Node(big.NewInt(0)) + g.Require().Equal(node.Fined, g.s.FineValue(big.NewInt(FineTypeForkBlock))) + + // Duplicate report should fail. + input, err = GovernanceABI.ABI.Pack("report", big.NewInt(FineTypeForkBlock), block1Bytes, block2Bytes) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().Error(err) + + // Check if finedRecords is set. + payloads := [][]byte{block1Bytes, block2Bytes} + sort.Sort(sortBytes(payloads)) + + hash := Bytes32(crypto.Keccak256Hash(payloads...)) + input, err = GovernanceABI.ABI.Pack("finedRecords", hash) + g.Require().NoError(err) + res, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + var value bool + err = GovernanceABI.ABI.Unpack(&value, "finedRecords", res) + g.Require().NoError(err) + g.Require().True(value) +} + +func (g *OracleContractsTestSuite) TestMiscVariableReading() { + privKey, addr := newPrefundAccount(g.stateDB) + pk := crypto.FromECDSAPub(&privKey.PublicKey) + + input, err := GovernanceABI.ABI.Pack("totalSupply") + g.Require().NoError(err) + res, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + input, err = GovernanceABI.ABI.Pack("totalStaked") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + // Stake. + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) + input, err = GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, amount) + g.Require().NoError(err) + + input, err = GovernanceABI.ABI.Pack("nodes", big.NewInt(0)) + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + input, err = GovernanceABI.ABI.Pack("nodesLength") + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + var value *big.Int + err = GovernanceABI.ABI.Unpack(&value, "nodesLength", res) + g.Require().NoError(err) + g.Require().Equal(1, int(value.Uint64())) + + input, err = GovernanceABI.ABI.Pack("nodesOffsetByAddress", addr) + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "nodesOffsetByAddress", res) + g.Require().NoError(err) + g.Require().Equal(0, int(value.Uint64())) + + addr, err = publicKeyToNodeKeyAddress(pk) + g.Require().NoError(err) + input, err = GovernanceABI.ABI.Pack("nodesOffsetByNodeKeyAddress", addr) + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&value, "nodesOffsetByNodeKeyAddress", res) + g.Require().NoError(err) + g.Require().Equal(0, int(value.Uint64())) + + input, err = GovernanceABI.ABI.Pack("fineValues", big.NewInt(0)) + g.Require().NoError(err) + res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) +} + +func (g *OracleContractsTestSuite) TestHalvingCondition() { + // TotalSupply 2.5B reached + g.s.MiningHalved() + g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3.25e9)).String(), + g.s.NextHalvingSupply().String()) + g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(0.75e9)).String(), + g.s.LastHalvedAmount().String()) + + // TotalSupply 3.25B reached + g.s.MiningHalved() + g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3.625e9)).String(), + g.s.NextHalvingSupply().String()) + g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(0.375e9)).String(), + g.s.LastHalvedAmount().String()) +} + +type testCoreMock struct { + newDKGGPKError error + tsigReturn bool +} + +func (m *testCoreMock) NewGroupPublicKey(*GovernanceState, *big.Int, int) (tsigVerifierIntf, error) { + if m.newDKGGPKError != nil { + return nil, m.newDKGGPKError + } + return &testTSigVerifierMock{m.tsigReturn}, nil +} + +type testTSigVerifierMock struct { + ret bool +} + +func (v *testTSigVerifierMock) VerifySignature(coreCommon.Hash, coreCrypto.Signature) bool { + return v.ret +} + +func (g *OracleContractsTestSuite) TestResetDKG() { + for i := uint32(0); i < g.config.NotarySetSize; i++ { + privKey, addr := newPrefundAccount(g.stateDB) + pk := crypto.FromECDSAPub(&privKey.PublicKey) + + // Stake. + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)) + input, err := GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, amount) + g.Require().NoError(err) + } + g.Require().Len(g.s.QualifiedNodes(), int(g.config.NotarySetSize)) + + addrs := make(map[int][]common.Address) + dkgSets := make(map[int]map[coreTypes.NodeID]struct{}) + addDKG := func(round int, final, proposeCRS bool) { + if proposeCRS && uint64(round) > dexCore.DKGDelayRound { + // ProposeCRS and clear DKG state. + input, err := GovernanceABI.ABI.Pack( + "proposeCRS", big.NewInt(int64(round)), randomBytes(32, 32)) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addrs[round-1][0], input, big.NewInt(0)) + g.Require().NoError(err) + + // Clear DKG states for next round. + dkgSet := dkgSets[round-1] + g.s.ClearDKGMasterPublicKeyOffset() + g.s.ClearDKGMasterPublicKeys() + g.s.ClearDKGComplaintProposed() + g.s.ClearDKGComplaints() + g.s.ClearDKGMPKReadys(dkgSet) + g.s.ResetDKGMPKReadysCount() + g.s.ClearDKGFinalizeds(dkgSet) + g.s.ResetDKGFinalizedsCount() + g.s.ClearDKGSuccesses(dkgSet) + g.s.ResetDKGSuccessesCount() + g.s.SetDKGRound(big.NewInt(int64(round))) + } + + addrs[round] = []common.Address{} + target := coreTypes.NewNotarySetTarget(coreCommon.Hash(g.s.CRS())) + ns := coreTypes.NewNodeSet() + + for _, x := range g.s.QualifiedNodes() { + mpk, err := coreEcdsa.NewPublicKeyFromByteSlice(x.PublicKey) + if err != nil { + panic(err) + } + ns.Add(coreTypes.NewNodeID(mpk)) + } + dkgSet := ns.GetSubSet(int(g.s.NotarySetSize().Uint64()), target) + g.Require().Len(dkgSet, int(g.config.NotarySetSize)) + dkgSets[round] = dkgSet + + i := 0 + for id := range dkgSet { + offset := g.s.NodesOffsetByNodeKeyAddress(IdToAddress(id)) + if offset.Cmp(big.NewInt(0)) < 0 { + panic("DKG node does not exist") + } + node := g.s.Node(offset) + // Prepare MPK. + x := dkgTypes.MasterPublicKey{} + b, err := rlp.EncodeToBytes(&x) + if err != nil { + panic(err) + } + g.s.PushDKGMasterPublicKey(b) + g.s.PutDKGMasterPublicKeyOffset(Bytes32(id.Hash), big.NewInt(int64(i))) + // Prepare Complaint. + y := dkgTypes.Complaint{} + b, err = rlp.EncodeToBytes(&y) + if err != nil { + panic(err) + } + g.s.PushDKGComplaint(b) + addr := node.Owner + addrs[round] = append(addrs[round], addr) + // Prepare MPK Ready. + g.s.PutDKGMPKReady(addr, true) + g.s.IncDKGMPKReadysCount() + if final { + // Prepare Finalized. + g.s.PutDKGFinalized(addr, true) + g.s.IncDKGFinalizedsCount() + // Prepare Success. + g.s.PutDKGSuccess(addr, true) + g.s.IncDKGSuccessesCount() + } + i += 1 + } + dkgSetSize := len(dkgSet) + g.Require().Len(g.s.DKGMasterPublicKeys(), dkgSetSize) + g.Require().Len(g.s.DKGComplaints(), dkgSetSize) + g.Require().Equal(int64(dkgSetSize), g.s.DKGMPKReadysCount().Int64()) + for _, addr := range addrs[round] { + g.Require().True(g.s.DKGMPKReady(addr)) + } + + if final { + g.Require().Equal(int64(dkgSetSize), g.s.DKGFinalizedsCount().Int64()) + for _, addr := range addrs[round] { + g.Require().True(g.s.DKGFinalized(addr)) + } + g.Require().Equal(int64(dkgSetSize), g.s.DKGSuccessesCount().Int64()) + for _, addr := range addrs[round] { + g.Require().True(g.s.DKGSuccess(addr)) + } + } + + } + + mock := &testCoreMock{ + tsigReturn: true, + } + OracleContracts[GovernanceContractAddress] = func() OracleContract { + return &GovernanceContract{ + coreDKGUtils: mock, + } + } + + // Fill data for previous rounds. + roundHeight := int64(g.config.RoundLength) + round := int(dexCore.DKGDelayRound) + 3 + for i := 0; i <= round; i++ { + g.context.Round = big.NewInt(int64(i)) + + // Prepare Round Height + if i != 0 { + g.s.PushRoundHeight(big.NewInt(int64(i) * roundHeight)) + } + + addDKG(i+1, true, true) + } + + round++ + g.s.PushRoundHeight(big.NewInt(int64(round) * roundHeight)) + g.context.Round = big.NewInt(int64(round)) + addDKG(round+1, false, true) + repeat := 3 + for r := 0; r < repeat; r++ { + // Add one finalized for test. + roundPlusOne := big.NewInt(int64(round + 1)) + g.s.PutDKGFinalized(addrs[round+1][0], true) + g.s.IncDKGFinalizedsCount() + + g.context.BlockNumber = big.NewInt( + roundHeight*int64(round) + roundHeight*int64(r) + roundHeight*85/100) + _, addr := newPrefundAccount(g.stateDB) + newCRS := randomBytes(common.HashLength, common.HashLength) + input, err := GovernanceABI.ABI.Pack("resetDKG", newCRS) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + + // Test if CRS is reset. + newCRSHash := crypto.Keccak256Hash(newCRS) + g.Require().Equal(newCRSHash, g.s.CRS()) + + // Test if MPK is purged. + g.Require().Len(g.s.DKGMasterPublicKeys(), 0) + // Test if MPKReady is purged. + g.Require().Equal(int64(0), g.s.DKGMPKReadysCount().Int64()) + for _, addr := range addrs[round+1] { + g.Require().False(g.s.DKGMPKReady(addr)) + } + // Test if Complaint is purged. + g.Require().Len(g.s.DKGComplaints(), 0) + // Test if Finalized is purged. + g.Require().Equal(int64(0), g.s.DKGFinalizedsCount().Int64()) + for _, addr := range addrs[round+1] { + g.Require().False(g.s.DKGFinalized(addr)) + } + // Test if Success is purged. + g.Require().Equal(int64(0), g.s.DKGSuccessesCount().Int64()) + for _, addr := range addrs[round+1] { + g.Require().False(g.s.DKGSuccess(addr)) + } + + g.Require().Equal(int64(r+1), g.s.DKGResetCount(roundPlusOne).Int64()) + + addDKG(round+1, false, false) + } +} + +func TestOracleContracts(t *testing.T) { + suite.Run(t, new(OracleContractsTestSuite)) +} diff --git a/core/vm/oracle.go b/core/vm/oracle.go deleted file mode 100644 index 0d4c10d9e..000000000 --- a/core/vm/oracle.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2019 The dexon-consensus Authors -// This file is part of the dexon-consensus library. -// -// The dexon-consensus library is free software: you can redistribute it -// and/or modify it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of the License, -// or (at your option) any later version. -// -// The dexon-consensus library is distributed in the hope that it will be -// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the dexon-consensus library. If not, see -// . - -package vm - -import ( - "strings" - - "github.com/dexon-foundation/dexon/accounts/abi" - "github.com/dexon-foundation/dexon/common" -) - -var GovernanceContractAddress = common.HexToAddress("63751838d6485578b23e8b051d40861ecc416794") - -var GovernanceABI *OracleContractABI - -func init() { - GovernanceABI = NewOracleContractABI(GovernanceABIJSON) -} - -// OracleContract represent special system contracts written in Go. -type OracleContract interface { - Run(evm *EVM, input []byte, contract *Contract) (ret []byte, err error) -} - -// A map representing available system oracle contracts. -var OracleContracts = map[common.Address]func() OracleContract{ - GovernanceContractAddress: func() OracleContract { - return &GovernanceContract{ - coreDKGUtils: &defaultCoreDKGUtils{}, - } - }, -} - -// Run oracle contract. -func RunOracleContract(oracle OracleContract, evm *EVM, input []byte, contract *Contract) (ret []byte, err error) { - return oracle.Run(evm, input, contract) -} - -// OracleContractABI represents ABI information for a given contract. -type OracleContractABI struct { - ABI abi.ABI - Name2Method map[string]abi.Method - Sig2Method map[string]abi.Method - Events map[string]abi.Event -} - -// NewOracleContractABI parse the ABI. -func NewOracleContractABI(abiDefinition string) *OracleContractABI { - abiObject, err := abi.JSON(strings.NewReader(abiDefinition)) - if err != nil { - panic(err) - } - - sig2Method := make(map[string]abi.Method) - name2Method := make(map[string]abi.Method) - - for _, method := range abiObject.Methods { - sig2Method[string(method.Id())] = method - name2Method[method.Name] = method - } - - events := make(map[string]abi.Event) - for _, event := range abiObject.Events { - events[event.Name] = event - } - - return &OracleContractABI{ - ABI: abiObject, - Name2Method: name2Method, - Sig2Method: sig2Method, - Events: events, - } -} diff --git a/core/vm/oracle_contract_abi.go b/core/vm/oracle_contract_abi.go deleted file mode 100644 index 0516f3891..000000000 --- a/core/vm/oracle_contract_abi.go +++ /dev/null @@ -1,1221 +0,0 @@ -// Copyright 2019 The dexon-consensus Authors -// This file is part of the dexon-consensus library. -// -// The dexon-consensus library is free software: you can redistribute it -// and/or modify it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of the License, -// or (at your option) any later version. -// -// The dexon-consensus library is distributed in the hope that it will be -// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the dexon-consensus library. If not, see -// . - -package vm - -// The governance ABI is generated from: -// https://github.com/dexon-foundation/governance-abi - -const GovernanceABIJSON = ` -[ - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "address" - } - ], - "name": "dkgSuccesses", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "notarySetSize", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "uint256" - } - ], - "name": "nodes", - "outputs": [ - { - "name": "owner", - "type": "address" - }, - { - "name": "publicKey", - "type": "bytes" - }, - { - "name": "staked", - "type": "uint256" - }, - { - "name": "fined", - "type": "uint256" - }, - { - "name": "name", - "type": "string" - }, - { - "name": "email", - "type": "string" - }, - { - "name": "location", - "type": "string" - }, - { - "name": "url", - "type": "string" - }, - { - "name": "unstaked", - "type": "uint256" - }, - { - "name": "unstakedAt", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "notaryParamBeta", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "miningVelocity", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "lambdaBA", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "minStake", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "crsRound", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "notaryParamAlpha", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "dkgSuccessesCount", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "address" - } - ], - "name": "dkgFinalizeds", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "blockGasLimit", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "dkgRound", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "totalStaked", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "address" - } - ], - "name": "nodesOffsetByAddress", - "outputs": [ - { - "name": "", - "type": "int256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "crs", - "outputs": [ - { - "name": "", - "type": "bytes32" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "roundLength", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "nextHalvingSupply", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "uint256" - } - ], - "name": "dkgComplaints", - "outputs": [ - { - "name": "", - "type": "bytes" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "owner", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "bytes32" - } - ], - "name": "dkgMasterPublicKeyOffset", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "address" - } - ], - "name": "dkgMPKReadys", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "lastHalvedAmount", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "bytes32" - } - ], - "name": "finedRecords", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "lambdaDKG", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "uint256" - } - ], - "name": "fineValues", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "uint256" - } - ], - "name": "roundHeight", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "dkgMPKReadysCount", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "minBlockInterval", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "uint256" - } - ], - "name": "dkgMasterPublicKeys", - "outputs": [ - { - "name": "", - "type": "bytes" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "address" - } - ], - "name": "lastProposedHeight", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "minGasPrice", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "dkgFinalizedsCount", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "bytes32" - } - ], - "name": "dkgComplaintsProposed", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "address" - } - ], - "name": "nodesOffsetByNodeKeyAddress", - "outputs": [ - { - "name": "", - "type": "int256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "lockupPeriod", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "uint256" - } - ], - "name": "dkgResetCount", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "anonymous": false, - "inputs": [], - "name": "ConfigurationChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "Round", - "type": "uint256" - }, - { - "indexed": false, - "name": "CRS", - "type": "bytes32" - } - ], - "name": "CRSProposed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "NodeAddress", - "type": "address" - }, - { - "indexed": true, - "name": "NewOwnerAddress", - "type": "address" - } - ], - "name": "NodeOwnershipTransfered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "NodeAddress", - "type": "address" - }, - { - "indexed": false, - "name": "PublicKey", - "type": "bytes" - } - ], - "name": "NodePublicKeyReplaced", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "NodeAddress", - "type": "address" - }, - { - "indexed": false, - "name": "Amount", - "type": "uint256" - } - ], - "name": "Staked", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "NodeAddress", - "type": "address" - }, - { - "indexed": false, - "name": "Amount", - "type": "uint256" - } - ], - "name": "Unstaked", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "NodeAddress", - "type": "address" - }, - { - "indexed": false, - "name": "Amount", - "type": "uint256" - } - ], - "name": "Withdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "NodeAddress", - "type": "address" - } - ], - "name": "NodeAdded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "NodeAddress", - "type": "address" - } - ], - "name": "NodeRemoved", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "NodeAddress", - "type": "address" - }, - { - "indexed": false, - "name": "Type", - "type": "uint256" - }, - { - "indexed": false, - "name": "Arg1", - "type": "bytes" - }, - { - "indexed": false, - "name": "Arg2", - "type": "bytes" - } - ], - "name": "Reported", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "NodeAddress", - "type": "address" - }, - { - "indexed": false, - "name": "Amount", - "type": "uint256" - } - ], - "name": "Fined", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "NodeAddress", - "type": "address" - }, - { - "indexed": false, - "name": "Amount", - "type": "uint256" - } - ], - "name": "FinePaid", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "Round", - "type": "uint256" - }, - { - "indexed": false, - "name": "BlockHeight", - "type": "uint256" - } - ], - "name": "DKGReset", - "type": "event" - }, - { - "constant": false, - "inputs": [ - { - "name": "NewOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "MinStake", - "type": "uint256" - }, - { - "name": "LockupPeriod", - "type": "uint256" - }, - { - "name": "MinGasPrice", - "type": "uint256" - }, - { - "name": "BlockGasLimit", - "type": "uint256" - }, - { - "name": "LambdaBA", - "type": "uint256" - }, - { - "name": "LambdaDKG", - "type": "uint256" - }, - { - "name": "NotaryParamAlpha", - "type": "uint256" - }, - { - "name": "NotaryParamBeta", - "type": "uint256" - }, - { - "name": "RoundLength", - "type": "uint256" - }, - { - "name": "MinBlockInterval", - "type": "uint256" - }, - { - "name": "FineValues", - "type": "uint256[]" - } - ], - "name": "updateConfiguration", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "NewOwner", - "type": "address" - } - ], - "name": "transferNodeOwnership", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "OldOwner", - "type": "address" - }, - { - "name": "NewOwner", - "type": "address" - } - ], - "name": "transferNodeOwnershipByFoundation", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "NewPublicKey", - "type": "bytes" - } - ], - "name": "replaceNodePublicKey", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "nodesLength", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "Round", - "type": "uint256" - }, - { - "name": "SignedCRS", - "type": "bytes" - } - ], - "name": "proposeCRS", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "Complaint", - "type": "bytes" - } - ], - "name": "addDKGComplaint", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "PublicKey", - "type": "bytes" - } - ], - "name": "addDKGMasterPublicKey", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "MPKReady", - "type": "bytes" - } - ], - "name": "addDKGMPKReady", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "Finalize", - "type": "bytes" - } - ], - "name": "addDKGFinalize", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "Success", - "type": "bytes" - } - ], - "name": "addDKGSuccess", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "PublicKey", - "type": "bytes" - }, - { - "name": "Name", - "type": "string" - }, - { - "name": "Email", - "type": "string" - }, - { - "name": "Location", - "type": "string" - }, - { - "name": "Url", - "type": "string" - } - ], - "name": "register", - "outputs": [], - "payable": true, - "stateMutability": "payable", - "type": "function" - }, - { - "constant": false, - "inputs": [], - "name": "stake", - "outputs": [], - "payable": true, - "stateMutability": "payable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "Amount", - "type": "uint256" - } - ], - "name": "unstake", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [], - "name": "withdraw", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "withdrawable", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "NodeAddress", - "type": "address" - } - ], - "name": "payFine", - "outputs": [], - "payable": true, - "stateMutability": "payable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "Type", - "type": "uint256" - }, - { - "name": "Arg1", - "type": "bytes" - }, - { - "name": "Arg2", - "type": "bytes" - } - ], - "name": "report", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "NewSignedCRS", - "type": "bytes" - } - ], - "name": "resetDKG", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - } -] -` diff --git a/core/vm/oracle_contracts.go b/core/vm/oracle_contracts.go deleted file mode 100644 index 4a3c05ccf..000000000 --- a/core/vm/oracle_contracts.go +++ /dev/null @@ -1,2884 +0,0 @@ -// Copyright 2018 The dexon-consensus Authors -// This file is part of the dexon-consensus library. -// -// The dexon-consensus library is free software: you can redistribute it -// and/or modify it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of the License, -// or (at your option) any later version. -// -// The dexon-consensus library is distributed in the hope that it will be -// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the dexon-consensus library. If not, see -// . - -package vm - -import ( - "bytes" - "errors" - "fmt" - "math" - "math/big" - "sort" - "sync/atomic" - - "github.com/dexon-foundation/dexon/accounts/abi" - "github.com/dexon-foundation/dexon/common" - "github.com/dexon-foundation/dexon/core/types" - "github.com/dexon-foundation/dexon/crypto" - "github.com/dexon-foundation/dexon/params" - "github.com/dexon-foundation/dexon/rlp" - - coreCommon "github.com/dexon-foundation/dexon-consensus/common" - dexCore "github.com/dexon-foundation/dexon-consensus/core" - coreCrypto "github.com/dexon-foundation/dexon-consensus/core/crypto" - coreUtils "github.com/dexon-foundation/dexon-consensus/core/utils" - - "github.com/dexon-foundation/dexon-consensus/core/crypto/ecdsa" - coreTypes "github.com/dexon-foundation/dexon-consensus/core/types" - dkgTypes "github.com/dexon-foundation/dexon-consensus/core/types/dkg" -) - -type Bytes32 [32]byte - -type FineType uint64 - -const ( - FineTypeFailStop = iota - FineTypeFailStopDKG - FineTypeInvalidDKG - FineTypeForkVote - FineTypeForkBlock -) - -const GovernanceActionGasCost = 200000 - -// Storage position enums. -const ( - roundHeightLoc = iota - totalSupplyLoc - totalStakedLoc - nodesLoc - nodesOffsetByAddressLoc - nodesOffsetByNodeKeyAddressLoc - lastProposedHeightLoc - crsRoundLoc - crsLoc - dkgRoundLoc - dkgResetCountLoc - dkgMasterPublicKeysLoc - dkgMasterPublicKeyOffsetLoc - dkgComplaintsLoc - dkgComplaintsProposedLoc - dkgReadyLoc - dkgReadysCountLoc - dkgFinalizedLoc - dkgFinalizedsCountLoc - dkgSuccessLoc - dkgSuccessesCountLoc - ownerLoc - minStakeLoc - lockupPeriodLoc - miningVelocityLoc - nextHalvingSupplyLoc - lastHalvedAmountLoc - minGasPriceLoc - blockGasLimitLoc - lambdaBALoc - lambdaDKGLoc - notarySetSizeLoc - notaryParamAlphaLoc - notaryParamBetaLoc - roundLengthLoc - minBlockIntervalLoc - fineValuesLoc - finedRecordsLoc -) - -func publicKeyToNodeKeyAddress(pkBytes []byte) (common.Address, error) { - pk, err := crypto.UnmarshalPubkey(pkBytes) - if err != nil { - return common.Address{}, err - } - return crypto.PubkeyToAddress(*pk), nil -} - -func getDKGMasterPublicKeyID(mpk *dkgTypes.MasterPublicKey) Bytes32 { - return Bytes32(mpk.ProposerID.Hash) -} - -func getDKGComplaintID(comp *dkgTypes.Complaint) Bytes32 { - return Bytes32(crypto.Keccak256Hash( - comp.ProposerID.Hash[:], - comp.PrivateShare.ProposerID.Hash[:], - []byte(fmt.Sprintf("%v", comp.IsNack())))) -} - -func IdToAddress(id coreTypes.NodeID) common.Address { - return common.BytesToAddress(id.Hash[12:]) -} - -// State manipulation helper fro the governance contract. -type GovernanceState struct { - StateDB StateDB -} - -func (s *GovernanceState) getState(loc common.Hash) common.Hash { - return s.StateDB.GetState(GovernanceContractAddress, loc) -} - -func (s *GovernanceState) setState(loc common.Hash, val common.Hash) { - s.StateDB.SetState(GovernanceContractAddress, loc, val) -} - -func (s *GovernanceState) getStateBigInt(loc *big.Int) *big.Int { - res := s.StateDB.GetState(GovernanceContractAddress, common.BigToHash(loc)) - return new(big.Int).SetBytes(res.Bytes()) -} - -func (s *GovernanceState) setStateBigInt(loc *big.Int, val *big.Int) { - s.setState(common.BigToHash(loc), common.BigToHash(val)) -} - -func (s *GovernanceState) getSlotLoc(loc *big.Int) *big.Int { - return new(big.Int).SetBytes(crypto.Keccak256(common.BigToHash(loc).Bytes())) -} - -func (s *GovernanceState) getMapLoc(pos *big.Int, key []byte) *big.Int { - return new(big.Int).SetBytes(crypto.Keccak256(key, common.BigToHash(pos).Bytes())) -} - -func (s *GovernanceState) readBytes(loc *big.Int) []byte { - // Length of the dynamic array (bytes). - rawLength := s.getStateBigInt(loc) - lengthByte := new(big.Int).Mod(rawLength, big.NewInt(256)) - - // Bytes length <= 31, lengthByte % 2 == 0 - // return the high 31 bytes. - if new(big.Int).Mod(lengthByte, big.NewInt(2)).Cmp(big.NewInt(0)) == 0 { - length := new(big.Int).Div(lengthByte, big.NewInt(2)).Uint64() - return rawLength.Bytes()[:length] - } - - // Actual length = (rawLength - 1) / 2 - length := new(big.Int).Div(new(big.Int).Sub(rawLength, big.NewInt(1)), big.NewInt(2)).Uint64() - - // Data address. - dataLoc := s.getSlotLoc(loc) - - // Read continuously for length bytes. - carry := int64(0) - if length%32 > 0 { - carry = 1 - } - chunks := int64(length/32) + carry - var data []byte - for i := int64(0); i < chunks; i++ { - loc = new(big.Int).Add(dataLoc, big.NewInt(i)) - data = append(data, s.getState(common.BigToHash(loc)).Bytes()...) - } - data = data[:length] - return data -} - -func (s *GovernanceState) writeBytes(loc *big.Int, data []byte) { - length := int64(len(data)) - - if length == 0 { - s.setState(common.BigToHash(loc), common.Hash{}) - return - } - - // Short bytes (length <= 31). - if length < 32 { - data2 := append([]byte(nil), data...) - // Right pad with zeros - for len(data2) < 31 { - data2 = append(data2, byte(0)) - } - data2 = append(data2, byte(length*2)) - s.setState(common.BigToHash(loc), common.BytesToHash(data2)) - return - } - - // Write 2 * length + 1. - storedLength := new(big.Int).Add(new(big.Int).Mul( - big.NewInt(length), big.NewInt(2)), big.NewInt(1)) - s.setStateBigInt(loc, storedLength) - // Write data chunck. - dataLoc := s.getSlotLoc(loc) - carry := int64(0) - if length%32 > 0 { - carry = 1 - } - chunks := length/32 + carry - for i := int64(0); i < chunks; i++ { - loc = new(big.Int).Add(dataLoc, big.NewInt(i)) - maxLoc := (i + 1) * 32 - if maxLoc > length { - maxLoc = length - } - data2 := data[i*32 : maxLoc] - // Right pad with zeros. - for len(data2) < 32 { - data2 = append(data2, byte(0)) - } - s.setState(common.BigToHash(loc), common.BytesToHash(data2)) - } -} - -func (s *GovernanceState) eraseBytes(loc *big.Int) { - // Length of the dynamic array (bytes). - rawLength := s.getStateBigInt(loc) - lengthByte := new(big.Int).Mod(rawLength, big.NewInt(256)) - - // Bytes length <= 31, lengthByte % 2 == 0 - // return the high 31 bytes. - if new(big.Int).Mod(lengthByte, big.NewInt(2)).Cmp(big.NewInt(0)) == 0 { - s.setStateBigInt(loc, big.NewInt(0)) - return - } - - // Actual length = (rawLength - 1) / 2 - length := new(big.Int).Div(new(big.Int).Sub( - rawLength, big.NewInt(1)), big.NewInt(2)).Uint64() - - // Fill 0. - s.writeBytes(loc, make([]byte, length)) - - // Clear slot. - s.setStateBigInt(loc, big.NewInt(0)) -} - -func (s *GovernanceState) read1DByteArray(loc *big.Int) [][]byte { - arrayLength := s.getStateBigInt(loc) - dataLoc := s.getSlotLoc(loc) - - data := [][]byte{} - for i := int64(0); i < int64(arrayLength.Uint64()); i++ { - elementLoc := new(big.Int).Add(dataLoc, big.NewInt(i)) - data = append(data, s.readBytes(elementLoc)) - } - return data -} - -func (s *GovernanceState) appendTo1DByteArray(loc *big.Int, data []byte) { - // Increase length by 1. - arrayLength := s.getStateBigInt(loc) - s.setStateBigInt(loc, new(big.Int).Add(arrayLength, big.NewInt(1))) - - // Write element. - dataLoc := s.getSlotLoc(loc) - elementLoc := new(big.Int).Add(dataLoc, arrayLength) - s.writeBytes(elementLoc, data) -} - -func (s *GovernanceState) erase1DByteArray(loc *big.Int) { - arrayLength := s.getStateBigInt(loc) - dataLoc := s.getSlotLoc(loc) - - for i := int64(0); i < int64(arrayLength.Uint64()); i++ { - elementLoc := new(big.Int).Add(dataLoc, big.NewInt(i)) - s.eraseBytes(elementLoc) - } - s.setStateBigInt(loc, big.NewInt(0)) -} - -// uint256[] public roundHeight; -func (s *GovernanceState) RoundHeight(round *big.Int) *big.Int { - baseLoc := s.getSlotLoc(big.NewInt(roundHeightLoc)) - loc := new(big.Int).Add(baseLoc, round) - return s.getStateBigInt(loc) -} -func (s *GovernanceState) PushRoundHeight(height *big.Int) { - // Increase length by 1. - length := s.getStateBigInt(big.NewInt(roundHeightLoc)) - s.setStateBigInt(big.NewInt(roundHeightLoc), new(big.Int).Add(length, big.NewInt(1))) - - baseLoc := s.getSlotLoc(big.NewInt(roundHeightLoc)) - loc := new(big.Int).Add(baseLoc, length) - - s.setStateBigInt(loc, height) -} - -// uint256 public totalSupply; -func (s *GovernanceState) TotalSupply() *big.Int { - return s.getStateBigInt(big.NewInt(totalSupplyLoc)) -} -func (s *GovernanceState) IncTotalSupply(amount *big.Int) { - s.setStateBigInt(big.NewInt(totalSupplyLoc), new(big.Int).Add(s.TotalSupply(), amount)) -} -func (s *GovernanceState) DecTotalSupply(amount *big.Int) { - s.setStateBigInt(big.NewInt(totalSupplyLoc), new(big.Int).Sub(s.TotalSupply(), amount)) -} - -// uint256 public totalStaked; -func (s *GovernanceState) TotalStaked() *big.Int { - return s.getStateBigInt(big.NewInt(totalStakedLoc)) -} -func (s *GovernanceState) IncTotalStaked(amount *big.Int) { - s.setStateBigInt(big.NewInt(totalStakedLoc), new(big.Int).Add(s.TotalStaked(), amount)) -} -func (s *GovernanceState) DecTotalStaked(amount *big.Int) { - s.setStateBigInt(big.NewInt(totalStakedLoc), new(big.Int).Sub(s.TotalStaked(), amount)) -} - -// struct Node { -// address owner; -// bytes publicKey; -// uint256 staked; -// uint256 fined; -// string name; -// string email; -// string location; -// string url; -// uint256 unstaked; -// uint256 unstakedAt; -// uint256 lastProposedHeight; -// } -// -// Node[] nodes; - -type nodeInfo struct { - Owner common.Address - PublicKey []byte - Staked *big.Int - Fined *big.Int - Name string - Email string - Location string - Url string - Unstaked *big.Int - UnstakedAt *big.Int -} - -const nodeStructSize = 10 - -func (s *GovernanceState) LenNodes() *big.Int { - return s.getStateBigInt(big.NewInt(nodesLoc)) -} -func (s *GovernanceState) Node(index *big.Int) *nodeInfo { - node := new(nodeInfo) - - arrayBaseLoc := s.getSlotLoc(big.NewInt(nodesLoc)) - elementBaseLoc := new(big.Int).Add(arrayBaseLoc, - new(big.Int).Mul(index, big.NewInt(nodeStructSize))) - - // Owner. - loc := elementBaseLoc - node.Owner = common.BytesToAddress(s.getState(common.BigToHash(elementBaseLoc)).Bytes()) - - // PublicKey. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(1)) - node.PublicKey = s.readBytes(loc) - - // Staked. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(2)) - node.Staked = s.getStateBigInt(loc) - - // Fined. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(3)) - node.Fined = s.getStateBigInt(loc) - - // Name. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(4)) - node.Name = string(s.readBytes(loc)) - - // Email. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(5)) - node.Email = string(s.readBytes(loc)) - - // Location. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(6)) - node.Location = string(s.readBytes(loc)) - - // Url. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(7)) - node.Url = string(s.readBytes(loc)) - - // Unstaked. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(8)) - node.Unstaked = s.getStateBigInt(loc) - - // UnstakedAt. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(9)) - node.UnstakedAt = s.getStateBigInt(loc) - - return node -} -func (s *GovernanceState) PushNode(n *nodeInfo) { - // Increase length by 1. - arrayLength := s.LenNodes() - s.setStateBigInt(big.NewInt(nodesLoc), new(big.Int).Add(arrayLength, big.NewInt(1))) - - s.UpdateNode(arrayLength, n) -} -func (s *GovernanceState) UpdateNode(index *big.Int, n *nodeInfo) { - arrayBaseLoc := s.getSlotLoc(big.NewInt(nodesLoc)) - elementBaseLoc := new(big.Int).Add(arrayBaseLoc, - new(big.Int).Mul(index, big.NewInt(nodeStructSize))) - - // Owner. - loc := elementBaseLoc - s.setState(common.BigToHash(loc), n.Owner.Hash()) - - // PublicKey. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(1)) - s.writeBytes(loc, n.PublicKey) - - // Staked. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(2)) - s.setStateBigInt(loc, n.Staked) - - // Fined. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(3)) - s.setStateBigInt(loc, n.Fined) - - // Name. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(4)) - s.writeBytes(loc, []byte(n.Name)) - - // Email. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(5)) - s.writeBytes(loc, []byte(n.Email)) - - // Location. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(6)) - s.writeBytes(loc, []byte(n.Location)) - - // Url. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(7)) - s.writeBytes(loc, []byte(n.Url)) - - // Unstaked. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(8)) - s.setStateBigInt(loc, n.Unstaked) - - // UnstakedAt. - loc = new(big.Int).Add(elementBaseLoc, big.NewInt(9)) - s.setStateBigInt(loc, n.UnstakedAt) - - // Update set size. - s.CalNotarySetSize() -} -func (s *GovernanceState) PopLastNode() { - // Decrease length by 1. - arrayLength := s.LenNodes() - newArrayLength := new(big.Int).Sub(arrayLength, big.NewInt(1)) - s.setStateBigInt(big.NewInt(nodesLoc), newArrayLength) - - s.UpdateNode(newArrayLength, &nodeInfo{ - Staked: big.NewInt(0), - Fined: big.NewInt(0), - Unstaked: big.NewInt(0), - UnstakedAt: big.NewInt(0), - }) -} -func (s *GovernanceState) Nodes() []*nodeInfo { - var nodes []*nodeInfo - for i := int64(0); i < int64(s.LenNodes().Uint64()); i++ { - nodes = append(nodes, s.Node(big.NewInt(i))) - } - return nodes -} -func (s *GovernanceState) QualifiedNodes() []*nodeInfo { - var nodes []*nodeInfo - for i := int64(0); i < int64(s.LenNodes().Uint64()); i++ { - node := s.Node(big.NewInt(i)) - // Node with unpaid fine is consider unqualified. - if node.Fined.Cmp(big.NewInt(0)) > 0 { - continue - } - if node.Staked.Cmp(s.MinStake()) >= 0 { - nodes = append(nodes, node) - } - } - return nodes -} - -// mapping(address => uint256) public nodesOffsetByAddress; -func (s *GovernanceState) NodesOffsetByAddress(addr common.Address) *big.Int { - loc := s.getMapLoc(big.NewInt(nodesOffsetByAddressLoc), addr.Bytes()) - return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1)) -} -func (s *GovernanceState) PutNodesOffsetByAddress(addr common.Address, offset *big.Int) { - loc := s.getMapLoc(big.NewInt(nodesOffsetByAddressLoc), addr.Bytes()) - s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1))) -} -func (s *GovernanceState) DeleteNodesOffsetByAddress(addr common.Address) { - loc := s.getMapLoc(big.NewInt(nodesOffsetByAddressLoc), addr.Bytes()) - s.setStateBigInt(loc, big.NewInt(0)) -} - -// mapping(address => uint256) public nodesOffsetByNodeKeyAddress; -func (s *GovernanceState) NodesOffsetByNodeKeyAddress(addr common.Address) *big.Int { - loc := s.getMapLoc(big.NewInt(nodesOffsetByNodeKeyAddressLoc), addr.Bytes()) - return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1)) -} -func (s *GovernanceState) PutNodesOffsetByNodeKeyAddress(addr common.Address, offset *big.Int) { - loc := s.getMapLoc(big.NewInt(nodesOffsetByNodeKeyAddressLoc), addr.Bytes()) - s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1))) -} -func (s *GovernanceState) DeleteNodesOffsetByNodeKeyAddress(addr common.Address) { - loc := s.getMapLoc(big.NewInt(nodesOffsetByNodeKeyAddressLoc), addr.Bytes()) - s.setStateBigInt(loc, big.NewInt(0)) -} - -func (s *GovernanceState) PutNodeOffsets(n *nodeInfo, offset *big.Int) { - address, err := publicKeyToNodeKeyAddress(n.PublicKey) - if err != nil { - panic(err) - } - s.PutNodesOffsetByNodeKeyAddress(address, offset) - s.PutNodesOffsetByAddress(n.Owner, offset) -} -func (s *GovernanceState) DeleteNodeOffsets(n *nodeInfo) { - address, err := publicKeyToNodeKeyAddress(n.PublicKey) - if err != nil { - panic(err) - } - s.DeleteNodesOffsetByNodeKeyAddress(address) - s.DeleteNodesOffsetByAddress(n.Owner) -} - -func (s *GovernanceState) GetNodeByID(id coreTypes.NodeID) (*nodeInfo, error) { - offset := s.NodesOffsetByNodeKeyAddress(IdToAddress(id)) - if offset.Cmp(big.NewInt(0)) < 0 { - return nil, errors.New("node not found") - } - node := s.Node(offset) - return node, nil -} - -// mapping(address => uint256) public lastProposedHeight; -func (s *GovernanceState) LastProposedHeight(addr common.Address) *big.Int { - loc := s.getMapLoc(big.NewInt(lastProposedHeightLoc), addr.Bytes()) - return s.getStateBigInt(loc) -} -func (s *GovernanceState) PutLastProposedHeight(addr common.Address, height *big.Int) { - loc := s.getMapLoc(big.NewInt(lastProposedHeightLoc), addr.Bytes()) - s.setStateBigInt(loc, height) -} - -// uint256 public crsRound; -func (s *GovernanceState) CRSRound() *big.Int { - return s.getStateBigInt(big.NewInt(crsRoundLoc)) -} -func (s *GovernanceState) SetCRSRound(round *big.Int) { - s.setStateBigInt(big.NewInt(crsRoundLoc), round) -} - -// bytes32 public crs; -func (s *GovernanceState) CRS() common.Hash { - return s.getState(common.BigToHash(big.NewInt(crsLoc))) -} -func (s *GovernanceState) SetCRS(crs common.Hash) { - s.setState(common.BigToHash(big.NewInt(crsLoc)), crs) -} - -// uint256 public dkgRound; -func (s *GovernanceState) DKGRound() *big.Int { - return s.getStateBigInt(big.NewInt(dkgRoundLoc)) -} -func (s *GovernanceState) SetDKGRound(round *big.Int) { - s.setStateBigInt(big.NewInt(dkgRoundLoc), round) -} - -// uint256[] public dkgResetCount; -func (s *GovernanceState) DKGResetCount(round *big.Int) *big.Int { - arrayBaseLoc := s.getSlotLoc(big.NewInt(dkgResetCountLoc)) - return s.getStateBigInt(new(big.Int).Add(arrayBaseLoc, round)) -} -func (s *GovernanceState) IncDKGResetCount(round *big.Int) { - loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgResetCountLoc)), round) - count := s.getStateBigInt(loc) - s.setStateBigInt(loc, new(big.Int).Add(count, big.NewInt(1))) -} - -// bytes[] public dkgMasterPublicKeys; -func (s *GovernanceState) LenDKGMasterPublicKeys() *big.Int { - return s.getStateBigInt(big.NewInt(dkgMasterPublicKeysLoc)) -} -func (s *GovernanceState) DKGMasterPublicKey(offset *big.Int) []byte { - loc := big.NewInt(dkgMasterPublicKeysLoc) - dataLoc := s.getSlotLoc(loc) - elementLoc := new(big.Int).Add(dataLoc, offset) - return s.readBytes(elementLoc) -} -func (s *GovernanceState) DKGMasterPublicKeyItem(offset *big.Int) *dkgTypes.MasterPublicKey { - element := s.DKGMasterPublicKey(offset) - x := new(dkgTypes.MasterPublicKey) - if err := rlp.DecodeBytes(element, x); err != nil { - panic(err) - } - return x -} -func (s *GovernanceState) DKGMasterPublicKeys() [][]byte { - return s.read1DByteArray(big.NewInt(dkgMasterPublicKeysLoc)) -} -func (s *GovernanceState) PushDKGMasterPublicKey(mpk []byte) { - s.appendTo1DByteArray(big.NewInt(dkgMasterPublicKeysLoc), mpk) -} -func (s *GovernanceState) DKGMasterPublicKeyItems() []*dkgTypes.MasterPublicKey { - // Prepare DKGMasterPublicKeys. - var dkgMasterPKs []*dkgTypes.MasterPublicKey - for _, mpk := range s.DKGMasterPublicKeys() { - x := new(dkgTypes.MasterPublicKey) - if err := rlp.DecodeBytes(mpk, x); err != nil { - panic(err) - } - dkgMasterPKs = append(dkgMasterPKs, x) - } - return dkgMasterPKs -} -func (s *GovernanceState) ClearDKGMasterPublicKeys() { - s.erase1DByteArray(big.NewInt(dkgMasterPublicKeysLoc)) -} - -// mapping(bytes32 => uint256) public dkgMasterPublicKeyOffset; -func (s *GovernanceState) DKGMasterPublicKeyOffset(id Bytes32) *big.Int { - loc := s.getMapLoc(big.NewInt(dkgMasterPublicKeyOffsetLoc), id[:]) - return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1)) -} -func (s *GovernanceState) PutDKGMasterPublicKeyOffset(id Bytes32, offset *big.Int) { - loc := s.getMapLoc(big.NewInt(dkgMasterPublicKeyOffsetLoc), id[:]) - s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1))) -} -func (s *GovernanceState) ClearDKGMasterPublicKeyOffset() { - for _, mpk := range s.DKGMasterPublicKeyItems() { - s.PutDKGMasterPublicKeyOffset(getDKGMasterPublicKeyID(mpk), big.NewInt(-1)) - } -} - -// bytes[] public dkgComplaints; -func (s *GovernanceState) LenDKGComplaints() *big.Int { - return s.getStateBigInt(big.NewInt(dkgComplaintsLoc)) -} -func (s *GovernanceState) DKGComplaint(offset *big.Int) []byte { - loc := big.NewInt(dkgComplaintsLoc) - dataLoc := s.getSlotLoc(loc) - elementLoc := new(big.Int).Add(dataLoc, offset) - return s.readBytes(elementLoc) -} -func (s *GovernanceState) DKGComplaints() [][]byte { - return s.read1DByteArray(big.NewInt(dkgComplaintsLoc)) -} -func (s *GovernanceState) PushDKGComplaint(complaint []byte) { - s.appendTo1DByteArray(big.NewInt(dkgComplaintsLoc), complaint) -} -func (s *GovernanceState) ClearDKGComplaints() { - s.erase1DByteArray(big.NewInt(dkgComplaintsLoc)) -} -func (s *GovernanceState) DKGComplaintItems() []*dkgTypes.Complaint { - var dkgComplaints []*dkgTypes.Complaint - for _, pk := range s.DKGComplaints() { - x := new(dkgTypes.Complaint) - if err := rlp.DecodeBytes(pk, x); err != nil { - panic(err) - } - dkgComplaints = append(dkgComplaints, x) - } - return dkgComplaints -} - -// mapping(bytes32 => bool) public dkgComplaintsProposed; -func (s *GovernanceState) DKGComplaintProposed(id Bytes32) bool { - loc := s.getMapLoc(big.NewInt(dkgComplaintsProposedLoc), id[:]) - return s.getStateBigInt(loc).Cmp(big.NewInt(0)) > 0 -} -func (s *GovernanceState) PutDKGComplaintProposed(id Bytes32, status bool) { - loc := s.getMapLoc(big.NewInt(dkgComplaintsProposedLoc), id[:]) - val := big.NewInt(0) - if status { - val = big.NewInt(1) - } - s.setStateBigInt(loc, val) -} -func (s *GovernanceState) ClearDKGComplaintProposed() { - for _, comp := range s.DKGComplaintItems() { - s.PutDKGComplaintProposed(getDKGComplaintID(comp), false) - } -} - -// mapping(address => bool) public dkgMPKReadys; -func (s *GovernanceState) DKGMPKReady(addr common.Address) bool { - mapLoc := s.getMapLoc(big.NewInt(dkgReadyLoc), addr.Bytes()) - return s.getStateBigInt(mapLoc).Cmp(big.NewInt(0)) != 0 -} -func (s *GovernanceState) PutDKGMPKReady(addr common.Address, ready bool) { - mapLoc := s.getMapLoc(big.NewInt(dkgReadyLoc), addr.Bytes()) - res := big.NewInt(0) - if ready { - res = big.NewInt(1) - } - s.setStateBigInt(mapLoc, res) -} -func (s *GovernanceState) ClearDKGMPKReadys(notarySet map[coreTypes.NodeID]struct{}) { - for id := range notarySet { - s.PutDKGMPKReady(IdToAddress(id), false) - } -} - -// uint256 public dkgMPKReadysCount; -func (s *GovernanceState) DKGMPKReadysCount() *big.Int { - return s.getStateBigInt(big.NewInt(dkgReadysCountLoc)) -} -func (s *GovernanceState) IncDKGMPKReadysCount() { - s.setStateBigInt(big.NewInt(dkgReadysCountLoc), - new(big.Int).Add(s.getStateBigInt(big.NewInt(dkgReadysCountLoc)), big.NewInt(1))) -} -func (s *GovernanceState) ResetDKGMPKReadysCount() { - s.setStateBigInt(big.NewInt(dkgReadysCountLoc), big.NewInt(0)) -} - -// mapping(address => bool) public dkgFinalizeds; -func (s *GovernanceState) DKGFinalized(addr common.Address) bool { - mapLoc := s.getMapLoc(big.NewInt(dkgFinalizedLoc), addr.Bytes()) - return s.getStateBigInt(mapLoc).Cmp(big.NewInt(0)) != 0 -} -func (s *GovernanceState) PutDKGFinalized(addr common.Address, finalized bool) { - mapLoc := s.getMapLoc(big.NewInt(dkgFinalizedLoc), addr.Bytes()) - res := big.NewInt(0) - if finalized { - res = big.NewInt(1) - } - s.setStateBigInt(mapLoc, res) -} -func (s *GovernanceState) ClearDKGFinalizeds(dkgSet map[coreTypes.NodeID]struct{}) { - for id := range dkgSet { - s.PutDKGFinalized(IdToAddress(id), false) - } -} - -// uint256 public dkgFinalizedsCount; -func (s *GovernanceState) DKGFinalizedsCount() *big.Int { - return s.getStateBigInt(big.NewInt(dkgFinalizedsCountLoc)) -} -func (s *GovernanceState) IncDKGFinalizedsCount() { - s.setStateBigInt(big.NewInt(dkgFinalizedsCountLoc), - new(big.Int).Add(s.getStateBigInt(big.NewInt(dkgFinalizedsCountLoc)), big.NewInt(1))) -} -func (s *GovernanceState) ResetDKGFinalizedsCount() { - s.setStateBigInt(big.NewInt(dkgFinalizedsCountLoc), big.NewInt(0)) -} - -// mapping(address => bool) public dkgSuccesses; -func (s *GovernanceState) DKGSuccess(addr common.Address) bool { - mapLoc := s.getMapLoc(big.NewInt(dkgSuccessLoc), addr.Bytes()) - return s.getStateBigInt(mapLoc).Cmp(big.NewInt(0)) != 0 -} -func (s *GovernanceState) PutDKGSuccess(addr common.Address, success bool) { - mapLoc := s.getMapLoc(big.NewInt(dkgSuccessLoc), addr.Bytes()) - res := big.NewInt(0) - if success { - res = big.NewInt(1) - } - s.setStateBigInt(mapLoc, res) -} -func (s *GovernanceState) ClearDKGSuccesses(dkgSet map[coreTypes.NodeID]struct{}) { - for id := range dkgSet { - s.PutDKGSuccess(IdToAddress(id), false) - } -} - -// uint256 public dkgSuccessesCount; -func (s *GovernanceState) DKGSuccessesCount() *big.Int { - return s.getStateBigInt(big.NewInt(dkgSuccessesCountLoc)) -} -func (s *GovernanceState) IncDKGSuccessesCount() { - s.setStateBigInt(big.NewInt(dkgSuccessesCountLoc), - new(big.Int).Add(s.getStateBigInt(big.NewInt(dkgSuccessesCountLoc)), big.NewInt(1))) -} -func (s *GovernanceState) ResetDKGSuccessesCount() { - s.setStateBigInt(big.NewInt(dkgSuccessesCountLoc), big.NewInt(0)) -} - -// address public owner; -func (s *GovernanceState) Owner() common.Address { - val := s.getState(common.BigToHash(big.NewInt(ownerLoc))) - return common.BytesToAddress(val.Bytes()) -} -func (s *GovernanceState) SetOwner(newOwner common.Address) { - s.setState(common.BigToHash(big.NewInt(ownerLoc)), newOwner.Hash()) -} - -// uint256 public minStake; -func (s *GovernanceState) MinStake() *big.Int { - return s.getStateBigInt(big.NewInt(minStakeLoc)) -} - -// uint256 public lockupPeriod; -func (s *GovernanceState) LockupPeriod() *big.Int { - return s.getStateBigInt(big.NewInt(lockupPeriodLoc)) -} - -// uint256 public miningVelocity; -func (s *GovernanceState) MiningVelocity() *big.Int { - return s.getStateBigInt(big.NewInt(miningVelocityLoc)) -} -func (s *GovernanceState) HalfMiningVelocity() { - s.setStateBigInt(big.NewInt(miningVelocityLoc), - new(big.Int).Div(s.MiningVelocity(), big.NewInt(2))) -} - -// uint256 public nextHalvingSupply; -func (s *GovernanceState) NextHalvingSupply() *big.Int { - return s.getStateBigInt(big.NewInt(nextHalvingSupplyLoc)) -} -func (s *GovernanceState) IncNextHalvingSupply(amount *big.Int) { - s.setStateBigInt(big.NewInt(nextHalvingSupplyLoc), - new(big.Int).Add(s.NextHalvingSupply(), amount)) -} - -// uint256 public lastHalvedAmount; -func (s *GovernanceState) LastHalvedAmount() *big.Int { - return s.getStateBigInt(big.NewInt(lastHalvedAmountLoc)) -} -func (s *GovernanceState) HalfLastHalvedAmount() { - s.setStateBigInt(big.NewInt(lastHalvedAmountLoc), - new(big.Int).Div(s.LastHalvedAmount(), big.NewInt(2))) -} -func (s *GovernanceState) MiningHalved() { - s.HalfMiningVelocity() - s.HalfLastHalvedAmount() - s.IncNextHalvingSupply(s.LastHalvedAmount()) -} - -// uint256 public minGasPrice; -func (s *GovernanceState) MinGasPrice() *big.Int { - return s.getStateBigInt(big.NewInt(minGasPriceLoc)) -} - -// uint256 public blockGasLimit; -func (s *GovernanceState) BlockGasLimit() *big.Int { - return s.getStateBigInt(big.NewInt(blockGasLimitLoc)) -} -func (s *GovernanceState) SetBlockGasLimit(reward *big.Int) { - s.setStateBigInt(big.NewInt(blockGasLimitLoc), reward) -} - -// uint256 public lambdaBA; -func (s *GovernanceState) LambdaBA() *big.Int { - return s.getStateBigInt(big.NewInt(lambdaBALoc)) -} - -// uint256 public lambdaDKG; -func (s *GovernanceState) LambdaDKG() *big.Int { - return s.getStateBigInt(big.NewInt(lambdaDKGLoc)) -} - -// uint256 public notarySetSize; -func (s *GovernanceState) NotarySetSize() *big.Int { - return s.getStateBigInt(big.NewInt(notarySetSizeLoc)) -} -func (s *GovernanceState) CalNotarySetSize() { - nodeSetSize := float64(len(s.QualifiedNodes())) - setSize := math.Ceil((nodeSetSize*0.6-1)/3)*3 + 1 - - if nodeSetSize >= 80 { - alpha := float64(s.NotaryParamAlpha().Uint64()) / decimalMultiplier - beta := float64(s.NotaryParamBeta().Uint64()) / decimalMultiplier - setSize = math.Ceil(alpha*math.Log(nodeSetSize) - beta) - } - s.setStateBigInt(big.NewInt(notarySetSizeLoc), big.NewInt(int64(setSize))) -} - -// uint256 public notaryParamAlpha; -func (s *GovernanceState) NotaryParamAlpha() *big.Int { - return s.getStateBigInt(big.NewInt(notaryParamAlphaLoc)) -} - -// uint256 public notaryParamBeta; -func (s *GovernanceState) NotaryParamBeta() *big.Int { - return s.getStateBigInt(big.NewInt(notaryParamBetaLoc)) -} - -// uint256 public roundLength; -func (s *GovernanceState) RoundLength() *big.Int { - return s.getStateBigInt(big.NewInt(roundLengthLoc)) -} - -// uint256 public minBlockInterval; -func (s *GovernanceState) MinBlockInterval() *big.Int { - return s.getStateBigInt(big.NewInt(minBlockIntervalLoc)) -} - -// uint256[] public fineValues; -func (s *GovernanceState) FineValue(index *big.Int) *big.Int { - arrayBaseLoc := s.getSlotLoc(big.NewInt(fineValuesLoc)) - return s.getStateBigInt(new(big.Int).Add(arrayBaseLoc, index)) -} -func (s *GovernanceState) FineValues() []*big.Int { - len := s.getStateBigInt(big.NewInt(fineValuesLoc)) - result := make([]*big.Int, len.Uint64()) - for i := 0; i < int(len.Uint64()); i++ { - result[i] = s.FineValue(big.NewInt(int64(i))) - } - return result -} -func (s *GovernanceState) SetFineValues(values []*big.Int) { - s.setStateBigInt(big.NewInt(fineValuesLoc), big.NewInt(int64(len(values)))) - - arrayBaseLoc := s.getSlotLoc(big.NewInt(fineValuesLoc)) - for i, v := range values { - s.setStateBigInt(new(big.Int).Add(arrayBaseLoc, big.NewInt(int64(i))), v) - } -} - -// mapping(bytes32 => bool) public fineRdecords; -func (s *GovernanceState) FineRecords(recordHash Bytes32) bool { - loc := s.getMapLoc(big.NewInt(finedRecordsLoc), recordHash[:]) - return s.getStateBigInt(loc).Cmp(big.NewInt(0)) > 0 -} -func (s *GovernanceState) SetFineRecords(recordHash Bytes32, status bool) { - loc := s.getMapLoc(big.NewInt(finedRecordsLoc), recordHash[:]) - value := int64(0) - if status { - value = int64(1) - } - s.setStateBigInt(loc, big.NewInt(value)) -} - -// Initialize initializes governance contract state. -func (s *GovernanceState) Initialize(config *params.DexconConfig, totalSupply *big.Int) { - if config.NextHalvingSupply.Cmp(totalSupply) <= 0 { - panic(fmt.Sprintf("invalid genesis found, totalSupply: %s, nextHavlingSupply: %s", - totalSupply, config.NextHalvingSupply)) - } - - // Genesis CRS. - crs := crypto.Keccak256Hash([]byte(config.GenesisCRSText)) - s.SetCRS(crs) - - // Round 0 height. - s.PushRoundHeight(big.NewInt(0)) - - // Owner. - s.SetOwner(config.Owner) - - // Governance configuration. - s.UpdateConfiguration(config) - - // Set totalSupply. - s.IncTotalSupply(totalSupply) - - // Set DKGRound. - s.SetDKGRound(big.NewInt(int64(dexCore.DKGDelayRound))) -} - -// Register is a helper function for creating genesis state. -func (s *GovernanceState) Register( - addr common.Address, publicKey []byte, - name, email, location, url string, staked *big.Int) { - offset := s.LenNodes() - node := &nodeInfo{ - Owner: addr, - PublicKey: publicKey, - Staked: staked, - Fined: big.NewInt(0), - Name: name, - Email: email, - Location: location, - Url: url, - Unstaked: big.NewInt(0), - UnstakedAt: big.NewInt(0), - } - s.PushNode(node) - s.PutNodeOffsets(node, offset) - - if staked.Cmp(big.NewInt(0)) == 0 { - return - } - - // Add to network total staked. - s.IncTotalStaked(staked) -} - -func (s *GovernanceState) Disqualify(n *nodeInfo) error { - nodeAddr, err := publicKeyToNodeKeyAddress(n.PublicKey) - if err != nil { - return err - } - - // Node might already been unstaked in the latest state. - offset := s.NodesOffsetByNodeKeyAddress(nodeAddr) - if offset.Cmp(big.NewInt(0)) < 0 { - return errors.New("node does not exist") - } - - // Set fined value. - node := s.Node(offset) - amount := s.FineValue(big.NewInt(FineTypeFailStop)) - node.Fined = new(big.Int).Add(node.Fined, amount) - s.UpdateNode(offset, node) - - return nil -} - -const decimalMultiplier = 100000000.0 - -// Configuration returns the current configuration. -func (s *GovernanceState) Configuration() *params.DexconConfig { - return ¶ms.DexconConfig{ - MinStake: s.getStateBigInt(big.NewInt(minStakeLoc)), - LockupPeriod: s.getStateBigInt(big.NewInt(lockupPeriodLoc)).Uint64(), - MiningVelocity: float32(s.getStateBigInt(big.NewInt(miningVelocityLoc)).Uint64()) / decimalMultiplier, - NextHalvingSupply: s.getStateBigInt(big.NewInt(nextHalvingSupplyLoc)), - LastHalvedAmount: s.getStateBigInt(big.NewInt(lastHalvedAmountLoc)), - MinGasPrice: s.getStateBigInt(big.NewInt(minGasPriceLoc)), - BlockGasLimit: s.getStateBigInt(big.NewInt(blockGasLimitLoc)).Uint64(), - LambdaBA: s.getStateBigInt(big.NewInt(lambdaBALoc)).Uint64(), - LambdaDKG: s.getStateBigInt(big.NewInt(lambdaDKGLoc)).Uint64(), - NotarySetSize: uint32(s.getStateBigInt(big.NewInt(notarySetSizeLoc)).Uint64()), - NotaryParamAlpha: float32(s.getStateBigInt(big.NewInt(notaryParamAlphaLoc)).Uint64()) / decimalMultiplier, - NotaryParamBeta: float32(s.getStateBigInt(big.NewInt(notaryParamBetaLoc)).Uint64()) / decimalMultiplier, - RoundLength: s.getStateBigInt(big.NewInt(roundLengthLoc)).Uint64(), - MinBlockInterval: s.getStateBigInt(big.NewInt(minBlockIntervalLoc)).Uint64(), - FineValues: s.FineValues(), - } -} - -// UpdateConfiguration updates system configuration. -func (s *GovernanceState) UpdateConfiguration(cfg *params.DexconConfig) { - s.setStateBigInt(big.NewInt(minStakeLoc), cfg.MinStake) - s.setStateBigInt(big.NewInt(lockupPeriodLoc), big.NewInt(int64(cfg.LockupPeriod))) - s.setStateBigInt(big.NewInt(miningVelocityLoc), big.NewInt(int64(cfg.MiningVelocity*decimalMultiplier))) - s.setStateBigInt(big.NewInt(nextHalvingSupplyLoc), cfg.NextHalvingSupply) - s.setStateBigInt(big.NewInt(lastHalvedAmountLoc), cfg.LastHalvedAmount) - s.setStateBigInt(big.NewInt(minGasPriceLoc), cfg.MinGasPrice) - s.setStateBigInt(big.NewInt(blockGasLimitLoc), big.NewInt(int64(cfg.BlockGasLimit))) - s.setStateBigInt(big.NewInt(lambdaBALoc), big.NewInt(int64(cfg.LambdaBA))) - s.setStateBigInt(big.NewInt(lambdaDKGLoc), big.NewInt(int64(cfg.LambdaDKG))) - s.setStateBigInt(big.NewInt(notarySetSizeLoc), big.NewInt(int64(cfg.NotarySetSize))) - s.setStateBigInt(big.NewInt(notaryParamAlphaLoc), big.NewInt(int64(cfg.NotaryParamAlpha*decimalMultiplier))) - s.setStateBigInt(big.NewInt(notaryParamBetaLoc), big.NewInt(int64(cfg.NotaryParamBeta*decimalMultiplier))) - s.setStateBigInt(big.NewInt(roundLengthLoc), big.NewInt(int64(cfg.RoundLength))) - s.setStateBigInt(big.NewInt(minBlockIntervalLoc), big.NewInt(int64(cfg.MinBlockInterval))) - s.SetFineValues(cfg.FineValues) - - // Calculate set size. - s.CalNotarySetSize() -} - -type rawConfigStruct struct { - MinStake *big.Int - LockupPeriod *big.Int - BlockGasLimit *big.Int - MinGasPrice *big.Int - LambdaBA *big.Int - LambdaDKG *big.Int - NotaryParamAlpha *big.Int - NotaryParamBeta *big.Int - RoundLength *big.Int - MinBlockInterval *big.Int - FineValues []*big.Int -} - -// UpdateConfigurationRaw updates system configuration. -func (s *GovernanceState) UpdateConfigurationRaw(cfg *rawConfigStruct) { - s.setStateBigInt(big.NewInt(minStakeLoc), cfg.MinStake) - s.setStateBigInt(big.NewInt(lockupPeriodLoc), cfg.LockupPeriod) - s.setStateBigInt(big.NewInt(minGasPriceLoc), cfg.MinGasPrice) - s.setStateBigInt(big.NewInt(blockGasLimitLoc), cfg.BlockGasLimit) - s.setStateBigInt(big.NewInt(lambdaBALoc), cfg.LambdaBA) - s.setStateBigInt(big.NewInt(lambdaDKGLoc), cfg.LambdaDKG) - s.setStateBigInt(big.NewInt(notaryParamAlphaLoc), cfg.NotaryParamAlpha) - s.setStateBigInt(big.NewInt(notaryParamBetaLoc), cfg.NotaryParamBeta) - s.setStateBigInt(big.NewInt(roundLengthLoc), cfg.RoundLength) - s.setStateBigInt(big.NewInt(minBlockIntervalLoc), cfg.MinBlockInterval) - s.SetFineValues(cfg.FineValues) - - // Calculate set size. - s.CalNotarySetSize() -} - -// event ConfigurationChanged(); -func (s *GovernanceState) emitConfigurationChangedEvent() { - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{GovernanceABI.Events["ConfigurationChanged"].Id()}, - Data: []byte{}, - }) -} - -// event CRSProposed(uint256 indexed Round, bytes32 CRS); -func (s *GovernanceState) emitCRSProposed(round *big.Int, crs common.Hash) { - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{GovernanceABI.Events["CRSProposed"].Id(), common.BigToHash(round)}, - Data: crs.Bytes(), - }) -} - -// event NodeOwnershipTransfered(address indexed NodeAddress, address indexed NewOwnerAddress); -func (s *GovernanceState) emitNodeOwnershipTransfered(nodeAddr, newNodeAddr common.Address) { - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{GovernanceABI.Events["NodeOwnershipTransfered"].Id(), - nodeAddr.Hash(), newNodeAddr.Hash()}, - Data: []byte{}, - }) -} - -// event NodePublicKeyReplaced(address indexed NodeAddress, bytes PublicKey); -func (s *GovernanceState) emitNodePublicKeyReplaced(nodeAddr common.Address, pk []byte) { - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{GovernanceABI.Events["NodePublicKeyReplaced"].Id(), nodeAddr.Hash()}, - Data: pk, - }) -} - -// event Staked(address indexed NodeAddress, uint256 Amount); -func (s *GovernanceState) emitStaked(nodeAddr common.Address, amount *big.Int) { - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{GovernanceABI.Events["Staked"].Id(), nodeAddr.Hash()}, - Data: common.BigToHash(amount).Bytes(), - }) -} - -// event Unstaked(address indexed NodeAddress, uint256 Amount); -func (s *GovernanceState) emitUnstaked(nodeAddr common.Address, amount *big.Int) { - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{GovernanceABI.Events["Unstaked"].Id(), nodeAddr.Hash()}, - Data: common.BigToHash(amount).Bytes(), - }) -} - -// event Withdrawn(address indexed NodeAddress, uint256 Amount); -func (s *GovernanceState) emitWithdrawn(nodeAddr common.Address, amount *big.Int) { - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{GovernanceABI.Events["Withdrawn"].Id(), nodeAddr.Hash()}, - Data: common.BigToHash(amount).Bytes(), - }) -} - -// event NodeAdded(address indexed NodeAddress); -func (s *GovernanceState) emitNodeAdded(nodeAddr common.Address) { - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{GovernanceABI.Events["NodeAdded"].Id(), nodeAddr.Hash()}, - Data: []byte{}, - }) -} - -// event NodeRemoved(address indexed NodeAddress); -func (s *GovernanceState) emitNodeRemoved(nodeAddr common.Address) { - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{GovernanceABI.Events["NodeRemoved"].Id(), nodeAddr.Hash()}, - Data: []byte{}, - }) -} - -// event Reported(address indexed NodeAddress, uint256 Type, bytes Arg1, bytes Arg2); -func (s *GovernanceState) emitReported(nodeAddr common.Address, reportType *big.Int, arg1, arg2 []byte) { - - t1, err := abi.NewType("uint256", nil) - if err != nil { - panic(err) - } - t2, err := abi.NewType("bytes", nil) - if err != nil { - panic(err) - } - - arg := abi.Arguments{ - abi.Argument{ - Name: "ReportType", - Type: t1, - Indexed: false, - }, - abi.Argument{ - Name: "Arg1", - Type: t2, - Indexed: false, - }, - abi.Argument{ - Name: "Arg2", - Type: t2, - Indexed: false, - }, - } - - data, err := arg.Pack(reportType, arg1, arg2) - if err != nil { - panic(err) - } - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{GovernanceABI.Events["Reported"].Id(), nodeAddr.Hash()}, - Data: data, - }) -} - -// event Fined(address indexed NodeAddress, uint256 Amount); -func (s *GovernanceState) emitFined(nodeAddr common.Address, amount *big.Int) { - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{GovernanceABI.Events["Fined"].Id(), nodeAddr.Hash()}, - Data: common.BigToHash(amount).Bytes(), - }) -} - -// event FinePaid(address indexed NodeAddress, uint256 Amount); -func (s *GovernanceState) emitFinePaid(nodeAddr common.Address, amount *big.Int) { - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{GovernanceABI.Events["FinePaid"].Id(), nodeAddr.Hash()}, - Data: common.BigToHash(amount).Bytes(), - }) -} - -// event DKGReset(uint256 indexed Round, uint256 BlockHeight); -func (s *GovernanceState) emitDKGReset(round *big.Int, blockHeight *big.Int) { - s.StateDB.AddLog(&types.Log{ - Address: GovernanceContractAddress, - Topics: []common.Hash{GovernanceABI.Events["DKGReset"].Id(), common.BigToHash(round)}, - Data: common.BigToHash(blockHeight).Bytes(), - }) -} - -func getRoundState(evm *EVM, round *big.Int) (*GovernanceState, error) { - gs := &GovernanceState{evm.StateDB} - height := gs.RoundHeight(round).Uint64() - if round.Uint64() > dexCore.ConfigRoundShift { - if height == 0 { - return nil, errExecutionReverted - } - } - statedb, err := evm.StateAtNumber(height) - return &GovernanceState{statedb}, err -} - -func getConfigState(evm *EVM, round *big.Int) (*GovernanceState, error) { - configRound := big.NewInt(0) - if round.Uint64() > dexCore.ConfigRoundShift { - configRound = new(big.Int).Sub(round, big.NewInt(int64(dexCore.ConfigRoundShift))) - } - return getRoundState(evm, configRound) -} - -type coreDKGUtils interface { - NewGroupPublicKey(*GovernanceState, *big.Int, int) (tsigVerifierIntf, error) -} -type tsigVerifierIntf interface { - VerifySignature(coreCommon.Hash, coreCrypto.Signature) bool -} - -// GovernanceContract represents the governance contract of DEXCON. -type GovernanceContract struct { - evm *EVM - state GovernanceState - contract *Contract - coreDKGUtils coreDKGUtils -} - -// defaultCoreDKGUtils implements coreDKGUtils. -type defaultCoreDKGUtils struct { - gpk atomic.Value -} - -func (c *defaultCoreDKGUtils) NewGroupPublicKey( - state *GovernanceState, round *big.Int, threshold int) (tsigVerifierIntf, error) { - var gpk *dkgTypes.GroupPublicKey - var err error - - v := c.gpk.Load() - if v != nil { - gpk = v.(*dkgTypes.GroupPublicKey) - if gpk.Round == round.Uint64() { - return gpk, nil - } - } - - mpks := state.DKGMasterPublicKeyItems() - comps := state.DKGComplaintItems() - gpk, err = dkgTypes.NewGroupPublicKey(round.Uint64(), mpks, comps, threshold) - if err != nil { - return nil, err - } - c.gpk.Store(gpk) - return gpk, nil -} - -func (g *GovernanceContract) Address() common.Address { - return GovernanceContractAddress -} - -func (g *GovernanceContract) transfer(from, to common.Address, amount *big.Int) bool { - // TODO(w): add this to debug trace so it shows up as internal transaction. - if g.evm.CanTransfer(g.evm.StateDB, from, amount) { - g.evm.Transfer(g.evm.StateDB, from, to, amount) - return true - } - return false -} - -func (g *GovernanceContract) useGas(gas uint64) ([]byte, error) { - if !g.contract.UseGas(gas) { - return nil, ErrOutOfGas - } - return nil, nil -} - -func (g *GovernanceContract) configNotarySetSize(round *big.Int) *big.Int { - s, err := getConfigState(g.evm, round) - if err != nil { - return big.NewInt(0) - } - return s.NotarySetSize() -} - -func (g *GovernanceContract) getNotarySet(round *big.Int) map[coreTypes.NodeID]struct{} { - crsRound := g.state.CRSRound() - var crs common.Hash - cmp := round.Cmp(crsRound) - if round.Cmp(big.NewInt(int64(dexCore.DKGDelayRound))) <= 0 { - state, err := getRoundState(g.evm, big.NewInt(0)) - if err != nil { - return map[coreTypes.NodeID]struct{}{} - } - crs = state.CRS() - for i := uint64(0); i < round.Uint64(); i++ { - crs = crypto.Keccak256Hash(crs[:]) - } - } else if cmp > 0 { - return map[coreTypes.NodeID]struct{}{} - } else if cmp == 0 { - crs = g.state.CRS() - } else { - state, err := getRoundState(g.evm, round) - if err != nil { - return map[coreTypes.NodeID]struct{}{} - } - crs = state.CRS() - } - - target := coreTypes.NewNotarySetTarget(coreCommon.Hash(crs)) - ns := coreTypes.NewNodeSet() - - state, err := getConfigState(g.evm, round) - if err != nil { - return map[coreTypes.NodeID]struct{}{} - } - for _, x := range state.QualifiedNodes() { - mpk, err := ecdsa.NewPublicKeyFromByteSlice(x.PublicKey) - if err != nil { - panic(err) - } - ns.Add(coreTypes.NewNodeID(mpk)) - } - return ns.GetSubSet(int(g.configNotarySetSize(round).Uint64()), target) -} - -func (g *GovernanceContract) inNotarySet(round *big.Int, nodeID coreTypes.NodeID) bool { - dkgSet := g.getNotarySet(round) - _, ok := dkgSet[nodeID] - return ok -} - -func (g *GovernanceContract) clearDKG() { - dkgSet := g.getNotarySet(g.state.DKGRound()) - g.state.ClearDKGMasterPublicKeyOffset() - g.state.ClearDKGMasterPublicKeys() - g.state.ClearDKGComplaintProposed() - g.state.ClearDKGComplaints() - g.state.ClearDKGMPKReadys(dkgSet) - g.state.ResetDKGMPKReadysCount() - g.state.ClearDKGFinalizeds(dkgSet) - g.state.ResetDKGFinalizedsCount() - g.state.ClearDKGSuccesses(dkgSet) - g.state.ResetDKGSuccessesCount() -} - -func (g *GovernanceContract) fineFailStopDKG(threshold int) { - fineNode := make(map[coreTypes.NodeID]struct{}) - dkgSet := g.getNotarySet(g.state.DKGRound()) - for id := range dkgSet { - offset := g.state.DKGMasterPublicKeyOffset(Bytes32(id.Hash)) - if offset.Cmp(big.NewInt(0)) >= 0 { - continue - } - fineNode[id] = struct{}{} - } - complaintsByID := map[coreTypes.NodeID]map[coreTypes.NodeID]struct{}{} - for _, complaint := range g.state.DKGComplaints() { - comp := new(dkgTypes.Complaint) - if err := rlp.DecodeBytes(complaint, comp); err != nil { - panic(err) - } - - if comp.IsNack() { - if _, exist := complaintsByID[comp.PrivateShare.ProposerID]; !exist { - complaintsByID[comp.PrivateShare.ProposerID] = - make(map[coreTypes.NodeID]struct{}) - } - complaintsByID[comp.PrivateShare.ProposerID][comp.ProposerID] = struct{}{} - } - } - for id, complaints := range complaintsByID { - if len(complaints) >= threshold { - fineNode[id] = struct{}{} - } - } - nodes := make(coreTypes.NodeIDs, 0, len(fineNode)) - for id := range fineNode { - nodes = append(nodes, id) - } - sort.Sort(nodes) - for _, id := range nodes { - offset := g.state.NodesOffsetByNodeKeyAddress(IdToAddress(id)) - // Node might have been unstaked. - if offset.Cmp(big.NewInt(0)) < 0 { - continue - } - - node := g.state.Node(offset) - amount := g.state.FineValue(big.NewInt(FineTypeFailStopDKG)) - node.Fined = new(big.Int).Add(node.Fined, amount) - g.state.UpdateNode(offset, node) - g.state.emitFined(node.Owner, amount) - } -} - -func (g *GovernanceContract) addDKGComplaint(comp []byte) ([]byte, error) { - caller := g.contract.Caller() - offset := g.state.NodesOffsetByNodeKeyAddress(caller) - - // Can not add complaint if caller does not exists. - if offset.Cmp(big.NewInt(0)) < 0 { - return nil, errExecutionReverted - } - - // Finalized caller is not allowed to propose complaint. - if g.state.DKGFinalized(caller) { - return nil, errExecutionReverted - } - - // Calculate 2f + 1 - threshold := 2*g.configNotarySetSize(g.evm.Round).Uint64()/3 + 1 - - // If 2f + 1 of DKG set is finalized, one can not propose complaint anymore. - if g.state.DKGFinalizedsCount().Uint64() >= threshold { - return nil, errExecutionReverted - } - - var dkgComplaint dkgTypes.Complaint - if err := rlp.DecodeBytes(comp, &dkgComplaint); err != nil { - return nil, errExecutionReverted - } - - if g.state.DKGComplaintProposed(getDKGComplaintID(&dkgComplaint)) { - return nil, errExecutionReverted - } - round := big.NewInt(int64(dkgComplaint.Round)) - if round.Uint64() != g.evm.Round.Uint64()+1 { - return nil, errExecutionReverted - } - - if dkgComplaint.Reset != g.state.DKGResetCount(round).Uint64() { - return nil, errExecutionReverted - } - - // DKGComplaint must belongs to someone in DKG set. - if !g.inNotarySet(round, dkgComplaint.ProposerID) { - return nil, errExecutionReverted - } - - verified, _ := coreUtils.VerifyDKGComplaintSignature(&dkgComplaint) - if !verified { - return nil, errExecutionReverted - } - - mpkOffset := g.state.DKGMasterPublicKeyOffset(Bytes32(dkgComplaint.PrivateShare.ProposerID.Hash)) - mpk := g.state.DKGMasterPublicKeyItem(mpkOffset) - - // Verify DKG complaint is correct. - ok, err := coreUtils.VerifyDKGComplaint(&dkgComplaint, mpk) - if !ok || err != nil { - return nil, errExecutionReverted - } - - // Fine the attacker. - need, err := coreUtils.NeedPenaltyDKGPrivateShare(&dkgComplaint, mpk) - if err != nil { - return nil, errExecutionReverted - } - if need { - node, err := g.state.GetNodeByID(dkgComplaint.PrivateShare.ProposerID) - if err != nil { - return nil, errExecutionReverted - } - fineValue := g.state.FineValue(big.NewInt(FineTypeInvalidDKG)) - if err := g.fine(node.Owner, fineValue, comp, nil); err != nil { - return nil, errExecutionReverted - } - } - - g.state.PushDKGComplaint(comp) - g.state.PutDKGComplaintProposed(getDKGComplaintID(&dkgComplaint), true) - - return g.useGas(GovernanceActionGasCost) -} - -func (g *GovernanceContract) addDKGMasterPublicKey(mpk []byte) ([]byte, error) { - var dkgMasterPK dkgTypes.MasterPublicKey - if err := rlp.DecodeBytes(mpk, &dkgMasterPK); err != nil { - return nil, errExecutionReverted - } - round := big.NewInt(int64(dkgMasterPK.Round)) - if round.Uint64() != g.evm.Round.Uint64()+1 { - return nil, errExecutionReverted - } - - if g.state.DKGRound().Cmp(g.evm.Round) == 0 { - // Clear DKG states for next round. - g.clearDKG() - g.state.SetDKGRound(round) - } - - mpkOffset := g.state.DKGMasterPublicKeyOffset(getDKGMasterPublicKeyID(&dkgMasterPK)) - if mpkOffset.Cmp(big.NewInt(0)) >= 0 { - return nil, errExecutionReverted - } - - caller := g.contract.Caller() - offset := g.state.NodesOffsetByNodeKeyAddress(caller) - - // Can not add dkg mpk if not staked. - if offset.Cmp(big.NewInt(0)) < 0 { - return nil, errExecutionReverted - } - - // MPKReady caller is not allowed to propose mpk. - if g.state.DKGMPKReady(caller) { - return nil, errExecutionReverted - } - - // Calculate 2f + 1 - threshold := 2*g.configNotarySetSize(g.evm.Round).Uint64()/3 + 1 - - // If 2f + 1 of DKG set is mpk ready, one can not propose mpk anymore. - if g.state.DKGMPKReadysCount().Uint64() >= threshold { - return nil, errExecutionReverted - } - - if dkgMasterPK.Reset != g.state.DKGResetCount(round).Uint64() { - return nil, errExecutionReverted - } - - // DKGMasterPublicKey must belongs to someone in DKG set. - if !g.inNotarySet(round, dkgMasterPK.ProposerID) { - return nil, errExecutionReverted - } - - verified, _ := coreUtils.VerifyDKGMasterPublicKeySignature(&dkgMasterPK) - if !verified { - return nil, errExecutionReverted - } - - mpkOffset = g.state.LenDKGMasterPublicKeys() - g.state.PushDKGMasterPublicKey(mpk) - g.state.PutDKGMasterPublicKeyOffset(getDKGMasterPublicKeyID(&dkgMasterPK), mpkOffset) - - return g.useGas(GovernanceActionGasCost) -} - -func (g *GovernanceContract) addDKGMPKReady(ready []byte) ([]byte, error) { - caller := g.contract.Caller() - - var dkgReady dkgTypes.MPKReady - if err := rlp.DecodeBytes(ready, &dkgReady); err != nil { - return nil, errExecutionReverted - } - round := big.NewInt(int64(dkgReady.Round)) - if round.Uint64() != g.evm.Round.Uint64()+1 { - return nil, errExecutionReverted - } - - if dkgReady.Reset != g.state.DKGResetCount(round).Uint64() { - return nil, errExecutionReverted - } - - // DKGFInalize must belongs to someone in DKG set. - if !g.inNotarySet(round, dkgReady.ProposerID) { - return nil, errExecutionReverted - } - - verified, _ := coreUtils.VerifyDKGMPKReadySignature(&dkgReady) - if !verified { - return nil, errExecutionReverted - } - - if !g.state.DKGMPKReady(caller) { - g.state.PutDKGMPKReady(caller, true) - g.state.IncDKGMPKReadysCount() - } - - return g.useGas(GovernanceActionGasCost) -} - -func (g *GovernanceContract) addDKGFinalize(finalize []byte) ([]byte, error) { - caller := g.contract.Caller() - - var dkgFinalize dkgTypes.Finalize - if err := rlp.DecodeBytes(finalize, &dkgFinalize); err != nil { - return nil, errExecutionReverted - } - round := big.NewInt(int64(dkgFinalize.Round)) - if round.Uint64() != g.evm.Round.Uint64()+1 { - return nil, errExecutionReverted - } - - if dkgFinalize.Reset != g.state.DKGResetCount(round).Uint64() { - return nil, errExecutionReverted - } - - // DKGFInalize must belongs to someone in DKG set. - if !g.inNotarySet(round, dkgFinalize.ProposerID) { - return nil, errExecutionReverted - } - - verified, _ := coreUtils.VerifyDKGFinalizeSignature(&dkgFinalize) - if !verified { - return nil, errExecutionReverted - } - - if !g.state.DKGFinalized(caller) { - g.state.PutDKGFinalized(caller, true) - g.state.IncDKGFinalizedsCount() - } - - threshold := 2*g.configNotarySetSize(g.evm.Round).Uint64()/3 + 1 - - if g.state.DKGFinalizedsCount().Uint64() == threshold { - tsigThreshold := coreUtils.GetDKGThreshold(&coreTypes.Config{ - NotarySetSize: uint32(g.configNotarySetSize(g.evm.Round).Uint64())}) - g.fineFailStopDKG(tsigThreshold) - } - - return g.useGas(GovernanceActionGasCost) -} - -func (g *GovernanceContract) addDKGSuccess(success []byte) ([]byte, error) { - caller := g.contract.Caller() - - var dkgSuccess dkgTypes.Success - if err := rlp.DecodeBytes(success, &dkgSuccess); err != nil { - return nil, errExecutionReverted - } - round := big.NewInt(int64(dkgSuccess.Round)) - if round.Uint64() != g.evm.Round.Uint64()+1 { - return nil, errExecutionReverted - } - - if dkgSuccess.Reset != g.state.DKGResetCount(round).Uint64() { - return nil, errExecutionReverted - } - - // DKGFInalize must belongs to someone in DKG set. - if !g.inNotarySet(round, dkgSuccess.ProposerID) { - return nil, errExecutionReverted - } - - verified, _ := coreUtils.VerifyDKGSuccessSignature(&dkgSuccess) - if !verified { - return nil, errExecutionReverted - } - - if !g.state.DKGSuccess(caller) { - g.state.PutDKGSuccess(caller, true) - g.state.IncDKGSuccessesCount() - } - - return g.useGas(GovernanceActionGasCost) -} - -func (g *GovernanceContract) updateConfiguration(cfg *rawConfigStruct) ([]byte, error) { - // Only owner can update configuration. - if g.contract.Caller() != g.state.Owner() { - return nil, errExecutionReverted - } - - // Sanity checks. - if cfg.MinStake.Cmp(big.NewInt(0)) <= 0 || - cfg.LockupPeriod.Cmp(big.NewInt(0)) <= 0 || - cfg.BlockGasLimit.Cmp(big.NewInt(0)) <= 0 || - cfg.MinGasPrice.Cmp(big.NewInt(0)) <= 0 || - cfg.LambdaBA.Cmp(big.NewInt(0)) <= 0 || - cfg.LambdaDKG.Cmp(big.NewInt(0)) <= 0 || - cfg.RoundLength.Cmp(big.NewInt(0)) <= 0 || - cfg.MinBlockInterval.Cmp(big.NewInt(0)) <= 0 { - return nil, errExecutionReverted - } - - g.state.UpdateConfigurationRaw(cfg) - g.state.emitConfigurationChangedEvent() - - return nil, nil -} - -func (g *GovernanceContract) register( - publicKey []byte, name, email, location, url string) ([]byte, error) { - - // Reject invalid inputs. - if len(name) >= 32 || len(email) >= 32 || len(location) >= 32 || len(url) >= 128 { - return nil, errExecutionReverted - } - - caller := g.contract.Caller() - value := g.contract.Value() - offset := g.state.NodesOffsetByAddress(caller) - - // Can not register if already registered. - if offset.Cmp(big.NewInt(0)) >= 0 { - return nil, errExecutionReverted - } - - nodeKeyAddr, err := publicKeyToNodeKeyAddress(publicKey) - if err != nil { - return nil, errExecutionReverted - } - - offset = g.state.NodesOffsetByNodeKeyAddress(nodeKeyAddr) - - // Can not register if node key is duplicate. - if offset.Cmp(big.NewInt(0)) >= 0 { - return nil, errExecutionReverted - } - - offset = g.state.LenNodes() - node := &nodeInfo{ - Owner: caller, - PublicKey: publicKey, - Staked: value, - Fined: big.NewInt(0), - Name: name, - Email: email, - Location: location, - Url: url, - Unstaked: big.NewInt(0), - UnstakedAt: big.NewInt(0), - } - g.state.PushNode(node) - g.state.PutNodeOffsets(node, offset) - g.state.emitNodeAdded(caller) - - if value.Cmp(big.NewInt(0)) > 0 { - g.state.IncTotalStaked(value) - g.state.emitStaked(caller, value) - } - return g.useGas(GovernanceActionGasCost) -} - -func (g *GovernanceContract) stake() ([]byte, error) { - caller := g.contract.Caller() - value := g.contract.Value() - - if big.NewInt(0).Cmp(value) == 0 { - return nil, errExecutionReverted - } - - offset := g.state.NodesOffsetByAddress(caller) - if offset.Cmp(big.NewInt(0)) < 0 { - return nil, errExecutionReverted - } - - node := g.state.Node(offset) - if node.Fined.Cmp(big.NewInt(0)) > 0 { - return nil, errExecutionReverted - } - - node.Staked = new(big.Int).Add(node.Staked, value) - g.state.UpdateNode(offset, node) - - g.state.IncTotalStaked(value) - g.state.emitStaked(caller, value) - - return g.useGas(GovernanceActionGasCost) -} - -func (g *GovernanceContract) unstake(amount *big.Int) ([]byte, error) { - caller := g.contract.Caller() - - offset := g.state.NodesOffsetByAddress(caller) - if offset.Cmp(big.NewInt(0)) < 0 { - return nil, errExecutionReverted - } - - node := g.state.Node(offset) - - // Can not unstake if there are unpaied fine. - if node.Fined.Cmp(big.NewInt(0)) > 0 { - return nil, errExecutionReverted - } - - // Can not unstake if there are unwithdrawn stake. - if node.Unstaked.Cmp(big.NewInt(0)) > 0 { - return nil, errExecutionReverted - } - if node.Staked.Cmp(amount) < 0 { - return nil, errExecutionReverted - } - - node.Staked = new(big.Int).Sub(node.Staked, amount) - node.Unstaked = amount - node.UnstakedAt = g.evm.Time - g.state.UpdateNode(offset, node) - - g.state.DecTotalStaked(amount) - g.state.emitUnstaked(caller, amount) - - return g.useGas(GovernanceActionGasCost) -} - -func (g *GovernanceContract) withdraw() ([]byte, error) { - if !g.withdrawable() { - return nil, errExecutionReverted - } - caller := g.contract.Caller() - - offset := g.state.NodesOffsetByAddress(caller) - if offset.Cmp(big.NewInt(0)) < 0 { - return nil, errExecutionReverted - } - - node := g.state.Node(offset) - - amount := node.Unstaked - node.Unstaked = big.NewInt(0) - node.UnstakedAt = big.NewInt(0) - g.state.UpdateNode(offset, node) - - if node.Staked.Cmp(big.NewInt(0)) == 0 { - length := g.state.LenNodes() - lastIndex := new(big.Int).Sub(length, big.NewInt(1)) - - // Delete the node. - if offset.Cmp(lastIndex) != 0 { - lastNode := g.state.Node(lastIndex) - g.state.UpdateNode(offset, lastNode) - g.state.PutNodeOffsets(lastNode, offset) - } - g.state.DeleteNodeOffsets(node) - g.state.PopLastNode() - g.state.emitNodeRemoved(caller) - } - - // Return the staked fund. - if !g.transfer(GovernanceContractAddress, node.Owner, amount) { - return nil, errExecutionReverted - } - g.state.emitWithdrawn(caller, amount) - - return g.useGas(GovernanceActionGasCost) -} - -func (g *GovernanceContract) withdrawable() bool { - caller := g.contract.Caller() - - offset := g.state.NodesOffsetByAddress(caller) - if offset.Cmp(big.NewInt(0)) < 0 { - return false - } - - node := g.state.Node(offset) - - // Can not withdraw if there are unpaied fine. - if node.Fined.Cmp(big.NewInt(0)) > 0 { - return false - } - - // Can not withdraw if there are no pending withdrawal. - if node.Unstaked.Cmp(big.NewInt(0)) == 0 { - return false - } - - unlockTime := new(big.Int).Add(node.UnstakedAt, g.state.LockupPeriod()) - return g.evm.Time.Cmp(unlockTime) > 0 -} - -func (g *GovernanceContract) payFine(nodeAddr common.Address) ([]byte, error) { - nodeOffset := g.state.NodesOffsetByAddress(nodeAddr) - if nodeOffset.Cmp(big.NewInt(0)) < 0 { - return nil, errExecutionReverted - } - - node := g.state.Node(nodeOffset) - if node.Fined.Cmp(big.NewInt(0)) <= 0 || node.Fined.Cmp(g.contract.Value()) < 0 { - return nil, errExecutionReverted - } - - node.Fined = new(big.Int).Sub(node.Fined, g.contract.Value()) - g.state.UpdateNode(nodeOffset, node) - - // Pay the fine to governance owner. - g.evm.StateDB.AddBalance(g.state.Owner(), g.contract.Value) - - g.state.emitFinePaid(nodeAddr, g.contract.Value()) - - return g.useGas(GovernanceActionGasCost) -} - -func (g *GovernanceContract) proposeCRS(nextRound *big.Int, signedCRS []byte) ([]byte, error) { - if nextRound.Uint64() != g.evm.Round.Uint64()+1 || - g.state.CRSRound().Uint64() == nextRound.Uint64() { - return nil, errExecutionReverted - } - - prevCRS := g.state.CRS() - - // CRS(n) = hash(CRS(n-1)) if n <= core.DKGRoundDelay - if g.evm.Round.Uint64() == dexCore.DKGDelayRound { - for i := uint64(0); i < dexCore.DKGDelayRound; i++ { - prevCRS = crypto.Keccak256Hash(prevCRS[:]) - } - } - - threshold := coreUtils.GetDKGThreshold(&coreTypes.Config{ - NotarySetSize: uint32(g.state.NotarySetSize().Uint64())}) - dkgGPK, err := g.coreDKGUtils.NewGroupPublicKey(&g.state, nextRound, threshold) - if err != nil { - return nil, errExecutionReverted - } - signature := coreCrypto.Signature{ - Type: "bls", - Signature: signedCRS, - } - if !dkgGPK.VerifySignature(coreCommon.Hash(prevCRS), signature) { - return nil, errExecutionReverted - } - - // Save new CRS into state and increase round. - crs := crypto.Keccak256Hash(signedCRS) - - g.state.SetCRS(crs) - g.state.SetCRSRound(nextRound) - g.state.emitCRSProposed(nextRound, crs) - - return g.useGas(GovernanceActionGasCost) -} - -type sortBytes [][]byte - -func (s sortBytes) Less(i, j int) bool { - return bytes.Compare(s[i], s[j]) < 0 -} - -func (s sortBytes) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -func (s sortBytes) Len() int { - return len(s) -} - -func (g *GovernanceContract) fine(nodeAddr common.Address, amount *big.Int, payloads ...[]byte) error { - sort.Sort(sortBytes(payloads)) - - hash := Bytes32(crypto.Keccak256Hash(payloads...)) - if g.state.FineRecords(hash) { - return errors.New("already fined") - } - g.state.SetFineRecords(hash, true) - - nodeOffset := g.state.NodesOffsetByAddress(nodeAddr) - if nodeOffset.Cmp(big.NewInt(0)) < 0 { - return errExecutionReverted - } - - // Set fined value. - node := g.state.Node(nodeOffset) - node.Fined = new(big.Int).Add(node.Fined, amount) - g.state.UpdateNode(nodeOffset, node) - - g.state.emitFined(nodeAddr, amount) - - return nil -} - -func (g *GovernanceContract) report(reportType *big.Int, arg1, arg2 []byte) ([]byte, error) { - typeEnum := FineType(reportType.Uint64()) - var reportedNodeID coreTypes.NodeID - - switch typeEnum { - case FineTypeForkVote: - vote1 := new(coreTypes.Vote) - if err := rlp.DecodeBytes(arg1, vote1); err != nil { - return nil, errExecutionReverted - } - vote2 := new(coreTypes.Vote) - if err := rlp.DecodeBytes(arg2, vote2); err != nil { - return nil, errExecutionReverted - } - need, err := coreUtils.NeedPenaltyForkVote(vote1, vote2) - if !need || err != nil { - return nil, errExecutionReverted - } - reportedNodeID = vote1.ProposerID - case FineTypeForkBlock: - block1 := new(coreTypes.Block) - if err := rlp.DecodeBytes(arg1, block1); err != nil { - return nil, errExecutionReverted - } - block2 := new(coreTypes.Block) - if err := rlp.DecodeBytes(arg2, block2); err != nil { - return nil, errExecutionReverted - } - need, err := coreUtils.NeedPenaltyForkBlock(block1, block2) - if !need || err != nil { - return nil, errExecutionReverted - } - reportedNodeID = block1.ProposerID - default: - return nil, errExecutionReverted - } - - node, err := g.state.GetNodeByID(reportedNodeID) - if err != nil { - return nil, errExecutionReverted - } - - g.state.emitReported(node.Owner, reportType, arg1, arg2) - - fineValue := g.state.FineValue(reportType) - if err := g.fine(node.Owner, fineValue, arg1, arg2); err != nil { - return nil, errExecutionReverted - } - return nil, nil -} - -func (g *GovernanceContract) resetDKG(newSignedCRS []byte) ([]byte, error) { - round := g.evm.Round - nextRound := new(big.Int).Add(round, big.NewInt(1)) - - // If no one call addDKGMasterPublicKey, DKG of previous round will not be - // cleared. - if g.state.DKGRound().Cmp(round) == 0 { - // Clear DKG states for next round. - g.clearDKG() - g.state.SetDKGRound(nextRound) - } - - resetCount := g.state.DKGResetCount(nextRound) - - // Just restart DEXON if failed at round 0. - if round.Cmp(big.NewInt(0)) == 0 { - return nil, errExecutionReverted - } - - // Extend the the current round. - // target = (85 + 100 * DKGResetCount)% - target := new(big.Int).Add( - big.NewInt(85), - new(big.Int).Mul(big.NewInt(100), resetCount)) - - roundHeight := g.state.RoundHeight(round) - gs, err := getConfigState(g.evm, round) - if err != nil { - return nil, err - } - config := gs.Configuration() - - targetBlockNum := new(big.Int).SetUint64(config.RoundLength) - targetBlockNum.Mul(targetBlockNum, target) - targetBlockNum.Quo(targetBlockNum, big.NewInt(100)) - targetBlockNum.Add(targetBlockNum, roundHeight) - - // Check if current block over 85%of current round. - blockHeight := g.evm.Context.BlockNumber - if blockHeight.Cmp(targetBlockNum) < 0 { - return nil, errExecutionReverted - } - - tsigThreshold := coreUtils.GetDKGThreshold(&coreTypes.Config{ - NotarySetSize: uint32(g.configNotarySetSize(nextRound).Uint64())}) - // Check if next DKG has not enough of success. - if g.state.DKGSuccessesCount().Uint64() >= - uint64(coreUtils.GetDKGValidThreshold(&coreTypes.Config{ - NotarySetSize: uint32(g.configNotarySetSize(nextRound).Uint64()), - })) { - // Check if next DKG did not success. - // Calculate 2f + 1 - threshold := 2*g.configNotarySetSize(nextRound).Uint64()/3 + 1 - - // If 2f + 1 of DKG set is finalized, check if DKG succeeded. - if g.state.DKGFinalizedsCount().Uint64() >= threshold { - gpk, err := g.coreDKGUtils.NewGroupPublicKey(&g.state, nextRound, tsigThreshold) - if gpk, ok := gpk.(*dkgTypes.GroupPublicKey); ok { - if len(gpk.QualifyNodeIDs) < coreUtils.GetDKGValidThreshold(&coreTypes.Config{ - NotarySetSize: uint32(g.configNotarySetSize(nextRound).Uint64())}) { - err = dkgTypes.ErrNotReachThreshold - } - } - - // DKG success. - if err == nil { - return nil, errExecutionReverted - } - switch err { - case dkgTypes.ErrNotReachThreshold, dkgTypes.ErrInvalidThreshold: - default: - return nil, errExecutionReverted - } - } - } - - // Fine fail stop DKGs. - g.fineFailStopDKG(tsigThreshold) - - // Update CRS. - state, err := getRoundState(g.evm, round) - if err != nil { - return nil, errExecutionReverted - } - prevCRS := state.CRS() - - // CRS(n) = hash(CRS(n-1)) if n <= core.DKGRoundDelay - if round.Uint64() == dexCore.DKGDelayRound { - for i := uint64(0); i < dexCore.DKGDelayRound; i++ { - prevCRS = crypto.Keccak256Hash(prevCRS[:]) - } - } - - for i := uint64(0); i < resetCount.Uint64()+1; i++ { - prevCRS = crypto.Keccak256Hash(prevCRS[:]) - } - - dkgGPK, err := g.coreDKGUtils.NewGroupPublicKey(state, round, - coreUtils.GetDKGThreshold(&coreTypes.Config{ - NotarySetSize: uint32(g.configNotarySetSize(round).Uint64())})) - if err != nil { - return nil, errExecutionReverted - } - signature := coreCrypto.Signature{ - Type: "bls", - Signature: newSignedCRS, - } - if !dkgGPK.VerifySignature(coreCommon.Hash(prevCRS), signature) { - return nil, errExecutionReverted - } - - // Clear DKG states for next round. - g.clearDKG() - g.state.SetDKGRound(nextRound) - - // Save new CRS into state and increase round. - newCRS := crypto.Keccak256(newSignedCRS) - crs := common.BytesToHash(newCRS) - - g.state.SetCRS(crs) - g.state.SetCRSRound(nextRound) - g.state.emitCRSProposed(nextRound, crs) - - // Increase reset count. - g.state.IncDKGResetCount(nextRound) - g.state.emitDKGReset(round, blockHeight) - - return nil, nil -} - -// Run executes governance contract. -func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (ret []byte, err error) { - if len(input) < 4 { - return nil, errExecutionReverted - } - - // Initialize contract state. - g.evm = evm - g.state = GovernanceState{evm.StateDB} - g.contract = contract - - // Parse input. - method, exists := GovernanceABI.Sig2Method[string(input[:4])] - if !exists { - return nil, errExecutionReverted - } - - arguments := input[4:] - - // Dispatch method call. - switch method.Name { - case "addDKGComplaint": - var Complaint []byte - if err := method.Inputs.Unpack(&Complaint, arguments); err != nil { - return nil, errExecutionReverted - } - return g.addDKGComplaint(Complaint) - case "addDKGMasterPublicKey": - var PublicKey []byte - if err := method.Inputs.Unpack(&PublicKey, arguments); err != nil { - return nil, errExecutionReverted - } - return g.addDKGMasterPublicKey(PublicKey) - case "addDKGMPKReady": - var MPKReady []byte - if err := method.Inputs.Unpack(&MPKReady, arguments); err != nil { - return nil, errExecutionReverted - } - return g.addDKGMPKReady(MPKReady) - case "addDKGFinalize": - var Finalize []byte - if err := method.Inputs.Unpack(&Finalize, arguments); err != nil { - return nil, errExecutionReverted - } - return g.addDKGFinalize(Finalize) - case "addDKGSuccess": - var Success []byte - if err := method.Inputs.Unpack(&Success, arguments); err != nil { - return nil, errExecutionReverted - } - return g.addDKGSuccess(Success) - case "nodesLength": - res, err := method.Outputs.Pack(g.state.LenNodes()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "payFine": - address := common.Address{} - if err := method.Inputs.Unpack(&address, arguments); err != nil { - return nil, errExecutionReverted - } - return g.payFine(address) - case "proposeCRS": - args := struct { - Round *big.Int - SignedCRS []byte - }{} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - return g.proposeCRS(args.Round, args.SignedCRS) - case "report": - args := struct { - Type *big.Int - Arg1 []byte - Arg2 []byte - }{} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - return g.report(args.Type, args.Arg1, args.Arg2) - case "resetDKG": - args := struct { - NewSignedCRS []byte - }{} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - return g.resetDKG(args.NewSignedCRS) - case "register": - args := struct { - PublicKey []byte - Name string - Email string - Location string - Url string - }{} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - return g.register(args.PublicKey, args.Name, args.Email, args.Location, args.Url) - case "stake": - return g.stake() - case "transferOwnership": - var newOwner common.Address - if err := method.Inputs.Unpack(&newOwner, arguments); err != nil { - return nil, errExecutionReverted - } - return g.transferOwnership(newOwner) - case "transferNodeOwnership": - var newOwner common.Address - if err := method.Inputs.Unpack(&newOwner, arguments); err != nil { - return nil, errExecutionReverted - } - return g.transferNodeOwnership(newOwner) - case "transferNodeOwnershipByFoundation": - args := struct { - OldOwner common.Address - NewOwner common.Address - }{} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - return g.transferNodeOwnershipByFoundation(args.OldOwner, args.NewOwner) - case "unstake": - amount := new(big.Int) - if err := method.Inputs.Unpack(&amount, arguments); err != nil { - return nil, errExecutionReverted - } - return g.unstake(amount) - case "updateConfiguration": - var cfg rawConfigStruct - if err := method.Inputs.Unpack(&cfg, arguments); err != nil { - return nil, errExecutionReverted - } - return g.updateConfiguration(&cfg) - case "withdraw": - return g.withdraw() - case "withdrawable": - res, err := method.Outputs.Pack(g.withdrawable()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - - // -------------------------------- - // Solidity auto generated methods. - // -------------------------------- - - case "blockGasLimit": - res, err := method.Outputs.Pack(g.state.BlockGasLimit()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "crs": - res, err := method.Outputs.Pack(g.state.CRS()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "crsRound": - res, err := method.Outputs.Pack(g.state.CRSRound()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgComplaints": - offset := new(big.Int) - if err := method.Inputs.Unpack(&offset, arguments); err != nil { - return nil, errExecutionReverted - } - complaint := g.state.DKGComplaint(offset) - res, err := method.Outputs.Pack(complaint) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgComplaintsProposed": - id := Bytes32{} - if err := method.Inputs.Unpack(&id, arguments); err != nil { - return nil, errExecutionReverted - } - proposed := g.state.DKGComplaintProposed(id) - res, err := method.Outputs.Pack(proposed) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgFinalizeds": - addr := common.Address{} - if err := method.Inputs.Unpack(&addr, arguments); err != nil { - return nil, errExecutionReverted - } - finalized := g.state.DKGFinalized(addr) - res, err := method.Outputs.Pack(finalized) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgFinalizedsCount": - count := g.state.DKGFinalizedsCount() - res, err := method.Outputs.Pack(count) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgSuccesses": - addr := common.Address{} - if err := method.Inputs.Unpack(&addr, arguments); err != nil { - return nil, errExecutionReverted - } - finalized := g.state.DKGSuccess(addr) - res, err := method.Outputs.Pack(finalized) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgSuccessesCount": - count := g.state.DKGSuccessesCount() - res, err := method.Outputs.Pack(count) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgMasterPublicKeys": - offset := new(big.Int) - if err := method.Inputs.Unpack(&offset, arguments); err != nil { - return nil, errExecutionReverted - } - mpk := g.state.DKGMasterPublicKey(offset) - res, err := method.Outputs.Pack(mpk) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgMasterPublicKeyOffset": - id := Bytes32{} - if err := method.Inputs.Unpack(&id, arguments); err != nil { - return nil, errExecutionReverted - } - offset := g.state.DKGMasterPublicKeyOffset(id) - res, err := method.Outputs.Pack(offset) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgMPKReadys": - addr := common.Address{} - if err := method.Inputs.Unpack(&addr, arguments); err != nil { - return nil, errExecutionReverted - } - ready := g.state.DKGMPKReady(addr) - res, err := method.Outputs.Pack(ready) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgMPKReadysCount": - count := g.state.DKGMPKReadysCount() - res, err := method.Outputs.Pack(count) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgResetCount": - round := new(big.Int) - if err := method.Inputs.Unpack(&round, arguments); err != nil { - return nil, errExecutionReverted - } - res, err := method.Outputs.Pack(g.state.DKGResetCount(round)) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "dkgRound": - res, err := method.Outputs.Pack(g.state.DKGRound()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "finedRecords": - record := Bytes32{} - if err := method.Inputs.Unpack(&record, arguments); err != nil { - return nil, errExecutionReverted - } - value := g.state.FineRecords(record) - res, err := method.Outputs.Pack(value) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "fineValues": - index := new(big.Int) - if err := method.Inputs.Unpack(&index, arguments); err != nil { - return nil, errExecutionReverted - } - value := g.state.FineValue(index) - res, err := method.Outputs.Pack(value) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "lambdaBA": - res, err := method.Outputs.Pack(g.state.LambdaBA()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "lambdaDKG": - res, err := method.Outputs.Pack(g.state.LambdaDKG()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "lastHalvedAmount": - res, err := method.Outputs.Pack(g.state.LastHalvedAmount()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "lastProposedHeight": - address := common.Address{} - if err := method.Inputs.Unpack(&address, arguments); err != nil { - return nil, errExecutionReverted - } - res, err := method.Outputs.Pack(g.state.LastProposedHeight(address)) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "lockupPeriod": - res, err := method.Outputs.Pack(g.state.LockupPeriod()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "minBlockInterval": - res, err := method.Outputs.Pack(g.state.MinBlockInterval()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "minGasPrice": - res, err := method.Outputs.Pack(g.state.MinGasPrice()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "miningVelocity": - res, err := method.Outputs.Pack(g.state.MiningVelocity()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "minStake": - res, err := method.Outputs.Pack(g.state.MinStake()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "nextHalvingSupply": - res, err := method.Outputs.Pack(g.state.NextHalvingSupply()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "nodes": - index := new(big.Int) - if err := method.Inputs.Unpack(&index, arguments); err != nil { - return nil, errExecutionReverted - } - info := g.state.Node(index) - res, err := method.Outputs.Pack( - info.Owner, info.PublicKey, info.Staked, info.Fined, - info.Name, info.Email, info.Location, info.Url, - info.Unstaked, info.UnstakedAt) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "nodesOffsetByAddress": - address := common.Address{} - if err := method.Inputs.Unpack(&address, arguments); err != nil { - return nil, errExecutionReverted - } - res, err := method.Outputs.Pack(g.state.NodesOffsetByAddress(address)) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "nodesOffsetByNodeKeyAddress": - address := common.Address{} - if err := method.Inputs.Unpack(&address, arguments); err != nil { - return nil, errExecutionReverted - } - res, err := method.Outputs.Pack(g.state.NodesOffsetByNodeKeyAddress(address)) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "notarySetSize": - res, err := method.Outputs.Pack(g.state.NotarySetSize()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "notaryParamAlpha": - res, err := method.Outputs.Pack(g.state.NotaryParamAlpha()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "notaryParamBeta": - res, err := method.Outputs.Pack(g.state.NotaryParamBeta()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "owner": - res, err := method.Outputs.Pack(g.state.Owner()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "replaceNodePublicKey": - var pk []byte - if err := method.Inputs.Unpack(&pk, arguments); err != nil { - return nil, errExecutionReverted - } - return g.replaceNodePublicKey(pk) - case "roundHeight": - round := new(big.Int) - if err := method.Inputs.Unpack(&round, arguments); err != nil { - return nil, errExecutionReverted - } - res, err := method.Outputs.Pack(g.state.RoundHeight(round)) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "roundLength": - res, err := method.Outputs.Pack(g.state.RoundLength()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "totalStaked": - res, err := method.Outputs.Pack(g.state.TotalStaked()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "totalSupply": - res, err := method.Outputs.Pack(g.state.TotalSupply()) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - } - return nil, errExecutionReverted -} - -func (g *GovernanceContract) transferOwnership(newOwner common.Address) ([]byte, error) { - // Only owner can update configuration. - if g.contract.Caller() != g.state.Owner() { - return nil, errExecutionReverted - } - if newOwner == (common.Address{}) { - return nil, errExecutionReverted - } - g.state.SetOwner(newOwner) - return nil, nil -} - -func (g *GovernanceContract) transferNodeOwnership(newOwner common.Address) ([]byte, error) { - if newOwner == (common.Address{}) { - return nil, errExecutionReverted - } - caller := g.contract.Caller() - - offset := g.state.NodesOffsetByAddress(caller) - if offset.Cmp(big.NewInt(0)) < 0 { - return nil, errExecutionReverted - } - - newOffset := g.state.NodesOffsetByAddress(newOwner) - if newOffset.Cmp(big.NewInt(0)) >= 0 { - return nil, errExecutionReverted - } - - node := g.state.Node(offset) - g.state.DeleteNodeOffsets(node) - - node.Owner = newOwner - g.state.PutNodeOffsets(node, offset) - g.state.UpdateNode(offset, node) - - g.state.emitNodeOwnershipTransfered(caller, newOwner) - - return nil, nil -} - -func (g *GovernanceContract) transferNodeOwnershipByFoundation(oldOwner, newOwner common.Address) ([]byte, error) { - // Only owner can update configuration. - if g.contract.Caller() != g.state.Owner() { - return nil, errExecutionReverted - } - - if newOwner == (common.Address{}) { - return nil, errExecutionReverted - } - - offset := g.state.NodesOffsetByAddress(oldOwner) - if offset.Cmp(big.NewInt(0)) < 0 { - return nil, errExecutionReverted - } - - newOffset := g.state.NodesOffsetByAddress(newOwner) - if newOffset.Cmp(big.NewInt(0)) >= 0 { - return nil, errExecutionReverted - } - - node := g.state.Node(offset) - g.state.DeleteNodeOffsets(node) - - node.Owner = newOwner - g.state.PutNodeOffsets(node, offset) - g.state.UpdateNode(offset, node) - - g.state.emitNodeOwnershipTransfered(oldOwner, newOwner) - - return nil, nil -} - -func (g *GovernanceContract) replaceNodePublicKey(newPublicKey []byte) ([]byte, error) { - caller := g.contract.Caller() - - offset := g.state.NodesOffsetByAddress(caller) - if offset.Cmp(big.NewInt(0)) < 0 { - return nil, errExecutionReverted - } - - node := g.state.Node(offset) - - _, err := publicKeyToNodeKeyAddress(newPublicKey) - if err != nil { - return nil, errExecutionReverted - } - - g.state.DeleteNodeOffsets(node) - - node.PublicKey = newPublicKey - g.state.PutNodeOffsets(node, offset) - g.state.UpdateNode(offset, node) - - g.state.emitNodePublicKeyReplaced(caller, newPublicKey) - - return nil, nil -} - -func PackProposeCRS(round uint64, signedCRS []byte) ([]byte, error) { - method := GovernanceABI.Name2Method["proposeCRS"] - res, err := method.Inputs.Pack(big.NewInt(int64(round)), signedCRS) - if err != nil { - return nil, err - } - data := append(method.Id(), res...) - return data, nil -} - -func PackAddDKGMasterPublicKey(mpk *dkgTypes.MasterPublicKey) ([]byte, error) { - method := GovernanceABI.Name2Method["addDKGMasterPublicKey"] - encoded, err := rlp.EncodeToBytes(mpk) - if err != nil { - return nil, err - } - res, err := method.Inputs.Pack(encoded) - if err != nil { - return nil, err - } - data := append(method.Id(), res...) - return data, nil -} - -func PackAddDKGMPKReady(ready *dkgTypes.MPKReady) ([]byte, error) { - method := GovernanceABI.Name2Method["addDKGMPKReady"] - encoded, err := rlp.EncodeToBytes(ready) - if err != nil { - return nil, err - } - res, err := method.Inputs.Pack(encoded) - if err != nil { - return nil, err - } - data := append(method.Id(), res...) - return data, nil -} - -func PackAddDKGComplaint(complaint *dkgTypes.Complaint) ([]byte, error) { - method := GovernanceABI.Name2Method["addDKGComplaint"] - encoded, err := rlp.EncodeToBytes(complaint) - if err != nil { - return nil, err - } - - res, err := method.Inputs.Pack(encoded) - if err != nil { - return nil, err - } - data := append(method.Id(), res...) - return data, nil -} - -func PackAddDKGFinalize(final *dkgTypes.Finalize) ([]byte, error) { - method := GovernanceABI.Name2Method["addDKGFinalize"] - encoded, err := rlp.EncodeToBytes(final) - if err != nil { - return nil, err - } - - res, err := method.Inputs.Pack(encoded) - if err != nil { - return nil, err - } - data := append(method.Id(), res...) - return data, nil -} - -func PackAddDKGSuccess(final *dkgTypes.Success) ([]byte, error) { - method := GovernanceABI.Name2Method["addDKGSuccess"] - encoded, err := rlp.EncodeToBytes(final) - if err != nil { - return nil, err - } - - res, err := method.Inputs.Pack(encoded) - if err != nil { - return nil, err - } - data := append(method.Id(), res...) - return data, nil -} - -func PackReportForkVote(vote1, vote2 *coreTypes.Vote) ([]byte, error) { - method := GovernanceABI.Name2Method["report"] - - vote1Bytes, err := rlp.EncodeToBytes(vote1) - if err != nil { - return nil, err - } - - vote2Bytes, err := rlp.EncodeToBytes(vote2) - if err != nil { - return nil, err - } - - res, err := method.Inputs.Pack(big.NewInt(FineTypeForkVote), vote1Bytes, vote2Bytes) - if err != nil { - return nil, err - } - data := append(method.Id(), res...) - return data, nil -} - -func PackReportForkBlock(block1, block2 *coreTypes.Block) ([]byte, error) { - method := GovernanceABI.Name2Method["report"] - - block1Bytes, err := rlp.EncodeToBytes(block1) - if err != nil { - return nil, err - } - - block2Bytes, err := rlp.EncodeToBytes(block2) - if err != nil { - return nil, err - } - - res, err := method.Inputs.Pack(big.NewInt(FineTypeForkBlock), block1Bytes, block2Bytes) - if err != nil { - return nil, err - } - data := append(method.Id(), res...) - return data, nil -} - -func PackResetDKG(newSignedCRS []byte) ([]byte, error) { - method := GovernanceABI.Name2Method["resetDKG"] - res, err := method.Inputs.Pack(newSignedCRS) - if err != nil { - return nil, err - } - data := append(method.Id(), res...) - return data, nil -} diff --git a/core/vm/oracle_contracts_test.go b/core/vm/oracle_contracts_test.go deleted file mode 100644 index c77313ba7..000000000 --- a/core/vm/oracle_contracts_test.go +++ /dev/null @@ -1,1202 +0,0 @@ -// Copyright 2018 The dexon-consensus Authors -// This file is part of the dexon-consensus library. -// -// The dexon-consensus library is free software: you can redistribute it -// and/or modify it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of the License, -// or (at your option) any later version. -// -// The dexon-consensus library is distributed in the hope that it will be -// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the dexon-consensus library. If not, see -// . - -package vm - -import ( - "bytes" - "crypto/ecdsa" - "math/big" - "math/rand" - "sort" - "testing" - "time" - - coreCommon "github.com/dexon-foundation/dexon-consensus/common" - dexCore "github.com/dexon-foundation/dexon-consensus/core" - coreCrypto "github.com/dexon-foundation/dexon-consensus/core/crypto" - coreEcdsa "github.com/dexon-foundation/dexon-consensus/core/crypto/ecdsa" - coreTypes "github.com/dexon-foundation/dexon-consensus/core/types" - dkgTypes "github.com/dexon-foundation/dexon-consensus/core/types/dkg" - coreUtils "github.com/dexon-foundation/dexon-consensus/core/utils" - - "github.com/dexon-foundation/dexon/common" - "github.com/dexon-foundation/dexon/core/state" - "github.com/dexon-foundation/dexon/crypto" - "github.com/dexon-foundation/dexon/ethdb" - "github.com/dexon-foundation/dexon/params" - "github.com/dexon-foundation/dexon/rlp" - "github.com/stretchr/testify/suite" -) - -func init() { - rand.Seed(time.Now().UnixNano()) -} - -func randomBytes(minLength, maxLength int32) []byte { - length := minLength - if maxLength != minLength { - length += rand.Int31() % (maxLength - minLength) - } - b := make([]byte, length) - for i := range b { - b[i] = byte(65 + rand.Int31()%60) - } - return b -} - -func newPrefundAccount(s *state.StateDB) (*ecdsa.PrivateKey, common.Address) { - privKey, err := crypto.GenerateKey() - if err != nil { - panic(err) - } - address := crypto.PubkeyToAddress(privKey.PublicKey) - - s.AddBalance(address, new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2e6))) - return privKey, address -} - -type GovernanceStateTestSuite struct { - suite.Suite - - stateDB *state.StateDB - s *GovernanceState -} - -func (g *GovernanceStateTestSuite) SetupTest() { - db := state.NewDatabase(ethdb.NewMemDatabase()) - statedb, err := state.New(common.Hash{}, db) - if err != nil { - panic(err) - } - g.stateDB = statedb - g.s = &GovernanceState{statedb} - - config := params.TestnetChainConfig.Dexcon - g.s.Initialize(config, new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e7))) - - statedb.AddBalance(GovernanceContractAddress, big.NewInt(1)) - statedb.Commit(true) -} - -func (g *GovernanceStateTestSuite) TestReadWriteEraseBytes() { - for i := 0; i < 100; i++ { - // Short bytes. - loc := big.NewInt(rand.Int63()) - data := randomBytes(3, 32) - g.s.writeBytes(loc, data) - read := g.s.readBytes(loc) - g.Require().Equal(0, bytes.Compare(data, read)) - g.s.eraseBytes(loc) - read = g.s.readBytes(loc) - g.Require().Len(read, 0) - - // long bytes. - loc = big.NewInt(rand.Int63()) - data = randomBytes(33, 2560) - g.s.writeBytes(loc, data) - read = g.s.readBytes(loc) - g.Require().Equal(0, bytes.Compare(data, read)) - g.s.eraseBytes(loc) - read = g.s.readBytes(loc) - g.Require().Len(read, 0) - } -} - -func (g *GovernanceStateTestSuite) TestReadWriteErase1DArray() { - emptyOffset := 100 - for j := 0; j < 50; j++ { - idx := big.NewInt(int64(j + emptyOffset)) - data := make([][]byte, 30) - for key := range data { - data[key] = randomBytes(3, 32) - g.s.appendTo1DByteArray(idx, data[key]) - } - read := g.s.read1DByteArray(idx) - g.Require().Len(read, len(data)) - for key := range data { - g.Require().Equal(0, bytes.Compare(data[key], read[key])) - } - g.s.erase1DByteArray(idx) - read = g.s.read1DByteArray(idx) - g.Require().Len(read, 0) - } -} - -func (g *GovernanceStateTestSuite) TestDisqualify() { - privKey, addr := newPrefundAccount(g.stateDB) - pk := crypto.FromECDSAPub(&privKey.PublicKey) - - g.s.Register(addr, pk, "Test", "test@dexon.org", "Taipei", "https://test.com", g.s.MinStake()) - - node := g.s.Node(big.NewInt(0)) - g.Require().Equal(uint64(0), node.Fined.Uint64()) - - // Disqualify - g.s.Disqualify(node) - node = g.s.Node(big.NewInt(0)) - g.Require().Equal(uint64(0xd78ebc5ac6200000), node.Fined.Uint64()) - - // Disqualify none exist node should return error. - privKey2, _ := newPrefundAccount(g.stateDB) - node.PublicKey = crypto.FromECDSAPub(&privKey2.PublicKey) - g.Require().Error(g.s.Disqualify(node)) -} - -func TestGovernanceState(t *testing.T) { - suite.Run(t, new(GovernanceStateTestSuite)) -} - -type OracleContractsTestSuite struct { - suite.Suite - - context Context - config *params.DexconConfig - memDB *ethdb.MemDatabase - stateDB *state.StateDB - s *GovernanceState -} - -func (g *OracleContractsTestSuite) SetupTest() { - memDB := ethdb.NewMemDatabase() - stateDB, err := state.New(common.Hash{}, state.NewDatabase(memDB)) - if err != nil { - panic(err) - } - g.memDB = memDB - g.stateDB = stateDB - g.s = &GovernanceState{stateDB} - - config := params.TestnetChainConfig.Dexcon - config.LockupPeriod = 1000 - config.NextHalvingSupply = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2.5e9)) - config.LastHalvedAmount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1.5e9)) - config.MiningVelocity = 0.1875 - config.NotarySetSize = 7 - - g.config = config - - // Give governance contract balance so it will not be deleted because of being an empty state object. - stateDB.AddBalance(GovernanceContractAddress, big.NewInt(1)) - - // Genesis CRS. - crs := crypto.Keccak256Hash([]byte(config.GenesisCRSText)) - g.s.SetCRS(crs) - - // Round 0 height. - g.s.PushRoundHeight(big.NewInt(0)) - - // Owner. - g.s.SetOwner(g.config.Owner) - - // Governance configuration. - g.s.UpdateConfiguration(config) - - g.stateDB.Commit(true) - - g.context = Context{ - CanTransfer: func(db StateDB, addr common.Address, amount *big.Int) bool { - return db.GetBalance(addr).Cmp(amount) >= 0 - }, - Transfer: func(db StateDB, sender common.Address, recipient common.Address, amount *big.Int) { - db.SubBalance(sender, amount) - db.AddBalance(recipient, amount) - }, - GetRoundHeight: func(round uint64) (uint64, bool) { - switch round { - case 0: - return 0, true - case 1: - return 1000, true - case 2: - return 2000, true - } - return 0, false - }, - StateAtNumber: func(n uint64) (*state.StateDB, error) { - return g.stateDB, nil - }, - BlockNumber: big.NewInt(0), - } - -} - -func (g *OracleContractsTestSuite) TearDownTest() { - OracleContracts[GovernanceContractAddress] = func() OracleContract { - return &GovernanceContract{ - coreDKGUtils: &defaultCoreDKGUtils{}, - } - } -} - -func (g *OracleContractsTestSuite) call( - contractAddr common.Address, caller common.Address, input []byte, value *big.Int) ([]byte, error) { - - g.context.Time = big.NewInt(time.Now().UnixNano() / 1000000) - - evm := NewEVM(g.context, g.stateDB, params.TestChainConfig, Config{IsBlockProposer: true}) - ret, _, err := evm.Call(AccountRef(caller), contractAddr, input, 10000000, value) - return ret, err -} - -func (g *OracleContractsTestSuite) TestTransferOwnership() { - input, err := GovernanceABI.ABI.Pack("transferOwnership", common.Address{}) - g.Require().NoError(err) - // Call with owner but invalid new owner. - _, err = g.call(GovernanceContractAddress, g.config.Owner, input, big.NewInt(0)) - g.Require().NotNil(err) - - _, addr := newPrefundAccount(g.stateDB) - - input, err = GovernanceABI.ABI.Pack("transferOwnership", addr) - g.Require().NoError(err) - - // Call with non-owner. - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NotNil(err) - - // Call with owner. - _, err = g.call(GovernanceContractAddress, g.config.Owner, input, big.NewInt(0)) - g.Require().NoError(err) - g.Require().Equal(addr, g.s.Owner()) -} - -func (g *OracleContractsTestSuite) TestTransferNodeOwnership() { - privKey, addr := newPrefundAccount(g.stateDB) - pk := crypto.FromECDSAPub(&privKey.PublicKey) - - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)) - input, err := GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, amount) - g.Require().NoError(err) - - // Call with not valid new owner. - input, err = GovernanceABI.ABI.Pack("transferNodeOwnership", common.Address{}) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NotNil(err) - - _, newAddr := newPrefundAccount(g.stateDB) - - input, err = GovernanceABI.ABI.Pack("transferNodeOwnership", newAddr) - g.Require().NoError(err) - - // Call with non-owner. - _, noneOwner := newPrefundAccount(g.stateDB) - _, err = g.call(GovernanceContractAddress, noneOwner, input, big.NewInt(0)) - g.Require().Error(err) - - // Call with owner. - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - g.Require().Equal(-1, int(g.s.NodesOffsetByAddress(addr).Int64())) - g.Require().Equal(0, int(g.s.NodesOffsetByNodeKeyAddress(addr).Int64())) - g.Require().Equal(0, int(g.s.NodesOffsetByAddress(newAddr).Int64())) - - // New node for duplication test. - privKey2, addr2 := newPrefundAccount(g.stateDB) - pk2 := crypto.FromECDSAPub(&privKey2.PublicKey) - input, err = GovernanceABI.ABI.Pack("register", pk2, "Test2", "test1@dexon.org", "Taipei", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr2, input, amount) - g.Require().NoError(err) - - // Transfer to duplicate owner address. - input, err = GovernanceABI.ABI.Pack("transferNodeOwnership", addr2) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, newAddr, input, amount) - g.Require().Error(err) -} - -func (g *OracleContractsTestSuite) TestTransferNodeOwnershipByFoundation() { - privKey, addr := newPrefundAccount(g.stateDB) - pk := crypto.FromECDSAPub(&privKey.PublicKey) - - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)) - input, err := GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, amount) - g.Require().NoError(err) - - _, newAddr := newPrefundAccount(g.stateDB) - - // Call with not valid new owner. - input, err = GovernanceABI.ABI.Pack("transferNodeOwnershipByFoundation", common.Address{}, newAddr) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NotNil(err) - - input, err = GovernanceABI.ABI.Pack("transferNodeOwnershipByFoundation", addr, newAddr) - g.Require().NoError(err) - - // Call with gov owner. - _, noneOwner := newPrefundAccount(g.stateDB) - _, err = g.call(GovernanceContractAddress, noneOwner, input, big.NewInt(0)) - g.Require().Error(err) - - // Call with gov owner. - _, err = g.call(GovernanceContractAddress, g.config.Owner, input, big.NewInt(0)) - g.Require().NoError(err) - g.Require().Equal(-1, int(g.s.NodesOffsetByAddress(addr).Int64())) - g.Require().Equal(0, int(g.s.NodesOffsetByNodeKeyAddress(addr).Int64())) - g.Require().Equal(0, int(g.s.NodesOffsetByAddress(newAddr).Int64())) -} - -func (g *OracleContractsTestSuite) TestReplaceNodePublicKey() { - privKey, addr := newPrefundAccount(g.stateDB) - pk := crypto.FromECDSAPub(&privKey.PublicKey) - - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)) - input, err := GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, amount) - g.Require().NoError(err) - - privKey2, addr2 := newPrefundAccount(g.stateDB) - pk2 := crypto.FromECDSAPub(&privKey2.PublicKey) - - input, err = GovernanceABI.ABI.Pack("replaceNodePublicKey", pk2) - g.Require().NoError(err) - - // Call with non-owner. - _, noneOwner := newPrefundAccount(g.stateDB) - _, err = g.call(GovernanceContractAddress, noneOwner, input, big.NewInt(0)) - g.Require().Error(err) - - // Call with owner. - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - - g.Require().Equal(-1, int(g.s.NodesOffsetByNodeKeyAddress(addr).Int64())) - g.Require().Equal(0, int(g.s.NodesOffsetByAddress(addr).Int64())) - g.Require().Equal(0, int(g.s.NodesOffsetByNodeKeyAddress(addr2).Int64())) -} - -func (g *OracleContractsTestSuite) TestStakingMechanism() { - privKey, addr := newPrefundAccount(g.stateDB) - pk := crypto.FromECDSAPub(&privKey.PublicKey) - - // Register with some stake. - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - balanceBeforeStake := g.stateDB.GetBalance(addr) - input, err := GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, amount) - g.Require().NoError(err) - - g.Require().Equal(1, int(g.s.LenNodes().Uint64())) - g.Require().Equal(0, len(g.s.QualifiedNodes())) - g.Require().Equal("Test1", g.s.Node(big.NewInt(0)).Name) - g.Require().Equal(amount.String(), g.s.TotalStaked().String()) - - // Check balance. - g.Require().Equal(new(big.Int).Sub(balanceBeforeStake, amount), g.stateDB.GetBalance(addr)) - g.Require().Equal(new(big.Int).Add(big.NewInt(1), amount), g.stateDB.GetBalance(GovernanceContractAddress)) - - // Registering again should fail. - _, err = g.call(GovernanceContractAddress, addr, input, amount) - g.Require().Error(err) - - // Duplicate public key should fail - _, addrDup := newPrefundAccount(g.stateDB) - input, err = GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addrDup, input, amount) - g.Require().Error(err) - - // Stake more to qualify. - input, err = GovernanceABI.ABI.Pack("stake") - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, amount) - g.Require().NoError(err) - g.Require().Equal(1, len(g.s.QualifiedNodes())) - g.Require().Equal(new(big.Int).Add(amount, amount).String(), g.s.TotalStaked().String()) - - // Unstake more then staked should fail. - unstakeAmount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e6)) - input, err = GovernanceABI.ABI.Pack("unstake", unstakeAmount) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().Error(err) - - // Unstake. - input, err = GovernanceABI.ABI.Pack("unstake", amount) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - g.Require().Equal(0, len(g.s.QualifiedNodes())) - g.Require().Equal(amount.String(), g.s.TotalStaked().String()) - - var ok bool - // Withdraw immediately should fail. - input, err = GovernanceABI.ABI.Pack("withdrawable") - g.Require().NoError(err) - output, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - GovernanceABI.ABI.Unpack(&ok, "withdrawable", output) - g.Require().False(ok) - input, err = GovernanceABI.ABI.Pack("withdraw") - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().Error(err) - - // Wait for lockup time than withdraw. - input, err = GovernanceABI.ABI.Pack("withdrawable") - g.Require().NoError(err) - output, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - GovernanceABI.ABI.Unpack(&ok, "withdrawable", output) - g.Require().False(ok) - time.Sleep(time.Second * 2) - input, err = GovernanceABI.ABI.Pack("withdraw") - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - - g.Require().Equal(0, len(g.s.QualifiedNodes())) - g.Require().Equal(1, int(g.s.LenNodes().Uint64())) - - // Unstake all to remove node. - input, err = GovernanceABI.ABI.Pack("unstake", amount) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - - time.Sleep(time.Second * 2) - input, err = GovernanceABI.ABI.Pack("withdrawable") - g.Require().NoError(err) - output, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - GovernanceABI.ABI.Unpack(&ok, "withdrawable", output) - g.Require().True(ok) - input, err = GovernanceABI.ABI.Pack("withdraw") - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - - g.Require().Equal(0, len(g.s.QualifiedNodes())) - g.Require().Equal(0, int(g.s.LenNodes().Uint64())) - - node := g.s.Node(big.NewInt(0)) - g.Require().Equal(big.NewInt(0).String(), node.Staked.String()) - g.Require().Equal(big.NewInt(0).String(), g.s.TotalStaked().String()) - - // Stake 2 nodes, and unstake the first then the second. - amount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)) - - // 2nd node Stake. - privKey2, addr2 := newPrefundAccount(g.stateDB) - pk2 := crypto.FromECDSAPub(&privKey2.PublicKey) - input, err = GovernanceABI.ABI.Pack("register", pk2, "Test2", "test2@dexon.org", "Taipei", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr2, input, amount) - g.Require().NoError(err) - g.Require().Equal("Test2", g.s.Node(big.NewInt(0)).Name) - g.Require().Equal(0, int(g.s.NodesOffsetByAddress(addr2).Int64())) - - // 1st node Stake. - input, err = GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, amount) - g.Require().NoError(err) - - g.Require().Equal(2, int(g.s.LenNodes().Uint64())) - g.Require().Equal(2, len(g.s.QualifiedNodes())) - g.Require().Equal(new(big.Int).Mul(amount, big.NewInt(2)).String(), g.s.TotalStaked().String()) - - // 2nd node Unstake. - input, err = GovernanceABI.ABI.Pack("unstake", amount) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr2, input, big.NewInt(0)) - g.Require().NoError(err) - - node = g.s.Node(big.NewInt(0)) - g.Require().Equal("Test2", node.Name) - g.Require().Equal(big.NewInt(0).String(), node.Staked.String()) - g.Require().Equal(1, len(g.s.QualifiedNodes())) - g.Require().Equal(amount.String(), g.s.TotalStaked().String()) - - time.Sleep(time.Second * 2) - input, err = GovernanceABI.ABI.Pack("withdraw") - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr2, input, big.NewInt(0)) - g.Require().NoError(err) - - g.Require().Equal(1, len(g.s.QualifiedNodes())) - g.Require().Equal(1, int(g.s.LenNodes().Uint64())) - g.Require().Equal("Test1", g.s.Node(big.NewInt(0)).Name) - g.Require().Equal(-1, int(g.s.NodesOffsetByAddress(addr2).Int64())) - - // 1st node Unstake. - input, err = GovernanceABI.ABI.Pack("unstake", amount) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - g.Require().Equal(0, len(g.s.QualifiedNodes())) - g.Require().Equal(big.NewInt(0).String(), g.s.TotalStaked().String()) - - time.Sleep(time.Second * 2) - input, err = GovernanceABI.ABI.Pack("withdraw") - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - - g.Require().Equal(0, int(g.s.LenNodes().Uint64())) - g.Require().Equal(-1, int(g.s.NodesOffsetByAddress(addr).Int64())) - - // Check balance. - g.Require().Equal(balanceBeforeStake, g.stateDB.GetBalance(addr)) - g.Require().Equal(balanceBeforeStake, g.stateDB.GetBalance(addr2)) - g.Require().Equal(big.NewInt(1), g.stateDB.GetBalance(GovernanceContractAddress)) -} - -func (g *OracleContractsTestSuite) TestFine() { - privKey, addr := newPrefundAccount(g.stateDB) - pk := crypto.FromECDSAPub(&privKey.PublicKey) - - // Stake. - input, err := GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org") - g.Require().NoError(err) - ownerStaked := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)) - _, err = g.call(GovernanceContractAddress, addr, input, ownerStaked) - g.Require().NoError(err) - g.Require().Equal(1, len(g.s.QualifiedNodes())) - g.Require().Equal(ownerStaked, g.s.Node(big.NewInt(0)).Staked) - - _, finePayer := newPrefundAccount(g.stateDB) - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - - // Paying to node without fine should fail. - input, err = GovernanceABI.ABI.Pack("payFine", addr) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, finePayer, input, amount) - g.Require().NotNil(err) - - // Fined. - offset := g.s.NodesOffsetByAddress(addr) - g.Require().True(offset.Cmp(big.NewInt(0)) >= 0) - node := g.s.Node(offset) - node.Fined = new(big.Int).Set(amount) - g.s.UpdateNode(offset, node) - node = g.s.Node(offset) - g.Require().Equal(0, node.Fined.Cmp(amount)) - - // Not qualified after fined. - g.Require().Equal(0, len(g.s.QualifiedNodes())) - - // Cannot unstake before fines are paied. - input, err = GovernanceABI.ABI.Pack("unstake", big.NewInt(10)) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, finePayer, input, big.NewInt(0)) - g.Require().NotNil(err) - - // Paying more than fine should fail. - payAmount := new(big.Int).Add(amount, amount) - input, err = GovernanceABI.ABI.Pack("payFine", addr) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, finePayer, input, payAmount) - g.Require().NotNil(err) - - // Pay the fine. - input, err = GovernanceABI.ABI.Pack("payFine", addr) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, finePayer, input, amount) - g.Require().NoError(err) - - // Qualified. - g.Require().Equal(1, len(g.s.QualifiedNodes())) -} - -func (g *OracleContractsTestSuite) TestUpdateConfiguration() { - _, addr := newPrefundAccount(g.stateDB) - - input, err := GovernanceABI.ABI.Pack("updateConfiguration", - new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)), - big.NewInt(1000), - big.NewInt(2e9), - big.NewInt(8000000), - big.NewInt(250), - big.NewInt(2500), - big.NewInt(int64(70.5*decimalMultiplier)), - big.NewInt(264*decimalMultiplier), - big.NewInt(600), - big.NewInt(900), - []*big.Int{big.NewInt(1), big.NewInt(1), big.NewInt(1), big.NewInt(1), big.NewInt(1)}) - g.Require().NoError(err) - - // Call with non-owner. - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NotNil(err) - - // Call with owner. - _, err = g.call(GovernanceContractAddress, g.config.Owner, input, big.NewInt(0)) - g.Require().NoError(err) -} - -func (g *OracleContractsTestSuite) TestConfigurationReading() { - _, addr := newPrefundAccount(g.stateDB) - - // CRS. - input, err := GovernanceABI.ABI.Pack("crs") - g.Require().NoError(err) - res, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - var crs0 [32]byte - err = GovernanceABI.ABI.Unpack(&crs0, "crs", res) - g.Require().NoError(err) - g.Require().Equal(crypto.Keccak256Hash([]byte(g.config.GenesisCRSText)), - common.BytesToHash(crs0[:])) - - // CRSRound. - input, err = GovernanceABI.ABI.Pack("crsRound") - g.Require().NoError(err) - res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - - // Owner. - input, err = GovernanceABI.ABI.Pack("owner") - g.Require().NoError(err) - res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - var owner common.Address - err = GovernanceABI.ABI.Unpack(&owner, "owner", res) - g.Require().NoError(err) - g.Require().Equal(g.config.Owner, owner) - - // MinStake. - input, err = GovernanceABI.ABI.Pack("minStake") - g.Require().NoError(err) - res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - var value *big.Int - err = GovernanceABI.ABI.Unpack(&value, "minStake", res) - g.Require().NoError(err) - g.Require().Equal(g.config.MinStake.String(), value.String()) - - // BlockReward. - input, err = GovernanceABI.ABI.Pack("miningVelocity") - g.Require().NoError(err) - res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = GovernanceABI.ABI.Unpack(&value, "miningVelocity", res) - g.Require().NoError(err) - g.Require().Equal(g.config.MiningVelocity, float32(value.Uint64())/decimalMultiplier) - - // BlockGasLimit. - input, err = GovernanceABI.ABI.Pack("blockGasLimit") - g.Require().NoError(err) - res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = GovernanceABI.ABI.Unpack(&value, "blockGasLimit", res) - g.Require().NoError(err) - g.Require().Equal(g.config.BlockGasLimit, value.Uint64()) - - // LambdaBA. - input, err = GovernanceABI.ABI.Pack("lambdaBA") - g.Require().NoError(err) - res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = GovernanceABI.ABI.Unpack(&value, "lambdaBA", res) - g.Require().NoError(err) - g.Require().Equal(g.config.LambdaBA, value.Uint64()) - - // LambdaDKG. - input, err = GovernanceABI.ABI.Pack("lambdaDKG") - g.Require().NoError(err) - res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = GovernanceABI.ABI.Unpack(&value, "lambdaDKG", res) - g.Require().NoError(err) - g.Require().Equal(g.config.LambdaDKG, value.Uint64()) - - // NotarySetSize. - input, err = GovernanceABI.ABI.Pack("notarySetSize") - g.Require().NoError(err) - res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = GovernanceABI.ABI.Unpack(&value, "notarySetSize", res) - g.Require().NoError(err) - g.Require().True(uint32(value.Uint64()) > 0) - - // DKGRound. - input, err = GovernanceABI.ABI.Pack("dkgRound") - g.Require().NoError(err) - res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - - // DKGResetCount. - input, err = GovernanceABI.ABI.Pack("dkgResetCount", big.NewInt(3)) - g.Require().NoError(err) - res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - - // RoundLength. - input, err = GovernanceABI.ABI.Pack("roundLength") - g.Require().NoError(err) - res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = GovernanceABI.ABI.Unpack(&value, "roundLength", res) - g.Require().NoError(err) - g.Require().Equal(g.config.RoundLength, value.Uint64()) - - // MinBlockInterval. - input, err = GovernanceABI.ABI.Pack("minBlockInterval") - g.Require().NoError(err) - res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = GovernanceABI.ABI.Unpack(&value, "minBlockInterval", res) - g.Require().NoError(err) - g.Require().Equal(g.config.MinBlockInterval, value.Uint64()) - - // MinGasPrice. - input, err = GovernanceABI.ABI.Pack("minGasPrice") - g.Require().NoError(err) - res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = GovernanceABI.ABI.Unpack(&value, "minGasPrice", res) - g.Require().NoError(err) - g.Require().Equal(g.config.MinGasPrice, value) -} - -func (g *OracleContractsTestSuite) TestReportForkVote() { - key, addr := newPrefundAccount(g.stateDB) - pkBytes := crypto.FromECDSAPub(&key.PublicKey) - - // Stake. - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - input, err := GovernanceABI.ABI.Pack("register", pkBytes, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, amount) - g.Require().NoError(err) - - pubKey := coreEcdsa.NewPublicKeyFromECDSA(&key.PublicKey) - privKey := coreEcdsa.NewPrivateKeyFromECDSA(key) - vote1 := coreTypes.NewVote(coreTypes.VoteCom, coreCommon.NewRandomHash(), uint64(0)) - vote1.ProposerID = coreTypes.NewNodeID(pubKey) - - vote2 := vote1.Clone() - for vote2.BlockHash == vote1.BlockHash { - vote2.BlockHash = coreCommon.NewRandomHash() - } - vote1.Signature, err = privKey.Sign(coreUtils.HashVote(vote1)) - g.Require().NoError(err) - vote2.Signature, err = privKey.Sign(coreUtils.HashVote(vote2)) - g.Require().NoError(err) - - vote1Bytes, err := rlp.EncodeToBytes(vote1) - g.Require().NoError(err) - vote2Bytes, err := rlp.EncodeToBytes(vote2) - g.Require().NoError(err) - - // Report wrong type (fork block) - input, err = GovernanceABI.ABI.Pack("report", big.NewInt(FineTypeForkBlock), vote1Bytes, vote2Bytes) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().Error(err) - - input, err = GovernanceABI.ABI.Pack("report", big.NewInt(FineTypeForkVote), vote1Bytes, vote2Bytes) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - - node := g.s.Node(big.NewInt(0)) - g.Require().Equal(node.Fined, g.s.FineValue(big.NewInt(FineTypeForkVote))) - - // Duplicate report should fail. - input, err = GovernanceABI.ABI.Pack("report", big.NewInt(FineTypeForkVote), vote1Bytes, vote2Bytes) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().Error(err) - - // Check if finedRecords is set. - payloads := [][]byte{vote1Bytes, vote2Bytes} - sort.Sort(sortBytes(payloads)) - - hash := Bytes32(crypto.Keccak256Hash(payloads...)) - input, err = GovernanceABI.ABI.Pack("finedRecords", hash) - g.Require().NoError(err) - res, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - - var value bool - err = GovernanceABI.ABI.Unpack(&value, "finedRecords", res) - g.Require().NoError(err) - g.Require().True(value) -} - -func (g *OracleContractsTestSuite) TestReportForkBlock() { - key, addr := newPrefundAccount(g.stateDB) - pkBytes := crypto.FromECDSAPub(&key.PublicKey) - - // Stake. - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - input, err := GovernanceABI.ABI.Pack("register", pkBytes, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, amount) - g.Require().NoError(err) - - privKey := coreEcdsa.NewPrivateKeyFromECDSA(key) - block1 := &coreTypes.Block{ - ProposerID: coreTypes.NewNodeID(privKey.PublicKey()), - ParentHash: coreCommon.NewRandomHash(), - Timestamp: time.Now(), - } - - block2 := block1.Clone() - for block2.ParentHash == block1.ParentHash { - block2.ParentHash = coreCommon.NewRandomHash() - } - - hashBlock := func(block *coreTypes.Block) coreCommon.Hash { - block.PayloadHash = coreCrypto.Keccak256Hash(block.Payload) - var err error - block.Hash, err = coreUtils.HashBlock(block) - g.Require().NoError(err) - return block.Hash - } - - block1.Signature, err = privKey.Sign(hashBlock(block1)) - g.Require().NoError(err) - block2.Signature, err = privKey.Sign(hashBlock(block2)) - g.Require().NoError(err) - - block1Bytes, err := rlp.EncodeToBytes(block1) - g.Require().NoError(err) - block2Bytes, err := rlp.EncodeToBytes(block2) - g.Require().NoError(err) - - // Report wrong type (fork vote) - input, err = GovernanceABI.ABI.Pack("report", big.NewInt(FineTypeForkVote), block1Bytes, block2Bytes) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().Error(err) - - input, err = GovernanceABI.ABI.Pack("report", big.NewInt(FineTypeForkBlock), block1Bytes, block2Bytes) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - - node := g.s.Node(big.NewInt(0)) - g.Require().Equal(node.Fined, g.s.FineValue(big.NewInt(FineTypeForkBlock))) - - // Duplicate report should fail. - input, err = GovernanceABI.ABI.Pack("report", big.NewInt(FineTypeForkBlock), block1Bytes, block2Bytes) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().Error(err) - - // Check if finedRecords is set. - payloads := [][]byte{block1Bytes, block2Bytes} - sort.Sort(sortBytes(payloads)) - - hash := Bytes32(crypto.Keccak256Hash(payloads...)) - input, err = GovernanceABI.ABI.Pack("finedRecords", hash) - g.Require().NoError(err) - res, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - - var value bool - err = GovernanceABI.ABI.Unpack(&value, "finedRecords", res) - g.Require().NoError(err) - g.Require().True(value) -} - -func (g *OracleContractsTestSuite) TestMiscVariableReading() { - privKey, addr := newPrefundAccount(g.stateDB) - pk := crypto.FromECDSAPub(&privKey.PublicKey) - - input, err := GovernanceABI.ABI.Pack("totalSupply") - g.Require().NoError(err) - res, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - - input, err = GovernanceABI.ABI.Pack("totalStaked") - g.Require().NoError(err) - res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - - // Stake. - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - input, err = GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, amount) - g.Require().NoError(err) - - input, err = GovernanceABI.ABI.Pack("nodes", big.NewInt(0)) - g.Require().NoError(err) - res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - - input, err = GovernanceABI.ABI.Pack("nodesLength") - g.Require().NoError(err) - res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - var value *big.Int - err = GovernanceABI.ABI.Unpack(&value, "nodesLength", res) - g.Require().NoError(err) - g.Require().Equal(1, int(value.Uint64())) - - input, err = GovernanceABI.ABI.Pack("nodesOffsetByAddress", addr) - g.Require().NoError(err) - res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = GovernanceABI.ABI.Unpack(&value, "nodesOffsetByAddress", res) - g.Require().NoError(err) - g.Require().Equal(0, int(value.Uint64())) - - addr, err = publicKeyToNodeKeyAddress(pk) - g.Require().NoError(err) - input, err = GovernanceABI.ABI.Pack("nodesOffsetByNodeKeyAddress", addr) - g.Require().NoError(err) - res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = GovernanceABI.ABI.Unpack(&value, "nodesOffsetByNodeKeyAddress", res) - g.Require().NoError(err) - g.Require().Equal(0, int(value.Uint64())) - - input, err = GovernanceABI.ABI.Pack("fineValues", big.NewInt(0)) - g.Require().NoError(err) - res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) -} - -func (g *OracleContractsTestSuite) TestHalvingCondition() { - // TotalSupply 2.5B reached - g.s.MiningHalved() - g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3.25e9)).String(), - g.s.NextHalvingSupply().String()) - g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(0.75e9)).String(), - g.s.LastHalvedAmount().String()) - - // TotalSupply 3.25B reached - g.s.MiningHalved() - g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3.625e9)).String(), - g.s.NextHalvingSupply().String()) - g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(0.375e9)).String(), - g.s.LastHalvedAmount().String()) -} - -type testCoreMock struct { - newDKGGPKError error - tsigReturn bool -} - -func (m *testCoreMock) NewGroupPublicKey(*GovernanceState, *big.Int, int) (tsigVerifierIntf, error) { - if m.newDKGGPKError != nil { - return nil, m.newDKGGPKError - } - return &testTSigVerifierMock{m.tsigReturn}, nil -} - -type testTSigVerifierMock struct { - ret bool -} - -func (v *testTSigVerifierMock) VerifySignature(coreCommon.Hash, coreCrypto.Signature) bool { - return v.ret -} - -func (g *OracleContractsTestSuite) TestResetDKG() { - for i := uint32(0); i < g.config.NotarySetSize; i++ { - privKey, addr := newPrefundAccount(g.stateDB) - pk := crypto.FromECDSAPub(&privKey.PublicKey) - - // Stake. - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)) - input, err := GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, amount) - g.Require().NoError(err) - } - g.Require().Len(g.s.QualifiedNodes(), int(g.config.NotarySetSize)) - - addrs := make(map[int][]common.Address) - dkgSets := make(map[int]map[coreTypes.NodeID]struct{}) - addDKG := func(round int, final, proposeCRS bool) { - if proposeCRS && uint64(round) > dexCore.DKGDelayRound { - // ProposeCRS and clear DKG state. - input, err := GovernanceABI.ABI.Pack( - "proposeCRS", big.NewInt(int64(round)), randomBytes(32, 32)) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addrs[round-1][0], input, big.NewInt(0)) - g.Require().NoError(err) - - // Clear DKG states for next round. - dkgSet := dkgSets[round-1] - g.s.ClearDKGMasterPublicKeyOffset() - g.s.ClearDKGMasterPublicKeys() - g.s.ClearDKGComplaintProposed() - g.s.ClearDKGComplaints() - g.s.ClearDKGMPKReadys(dkgSet) - g.s.ResetDKGMPKReadysCount() - g.s.ClearDKGFinalizeds(dkgSet) - g.s.ResetDKGFinalizedsCount() - g.s.ClearDKGSuccesses(dkgSet) - g.s.ResetDKGSuccessesCount() - g.s.SetDKGRound(big.NewInt(int64(round))) - } - - addrs[round] = []common.Address{} - target := coreTypes.NewNotarySetTarget(coreCommon.Hash(g.s.CRS())) - ns := coreTypes.NewNodeSet() - - for _, x := range g.s.QualifiedNodes() { - mpk, err := coreEcdsa.NewPublicKeyFromByteSlice(x.PublicKey) - if err != nil { - panic(err) - } - ns.Add(coreTypes.NewNodeID(mpk)) - } - dkgSet := ns.GetSubSet(int(g.s.NotarySetSize().Uint64()), target) - g.Require().Len(dkgSet, int(g.config.NotarySetSize)) - dkgSets[round] = dkgSet - - i := 0 - for id := range dkgSet { - offset := g.s.NodesOffsetByNodeKeyAddress(IdToAddress(id)) - if offset.Cmp(big.NewInt(0)) < 0 { - panic("DKG node does not exist") - } - node := g.s.Node(offset) - // Prepare MPK. - x := dkgTypes.MasterPublicKey{} - b, err := rlp.EncodeToBytes(&x) - if err != nil { - panic(err) - } - g.s.PushDKGMasterPublicKey(b) - g.s.PutDKGMasterPublicKeyOffset(Bytes32(id.Hash), big.NewInt(int64(i))) - // Prepare Complaint. - y := dkgTypes.Complaint{} - b, err = rlp.EncodeToBytes(&y) - if err != nil { - panic(err) - } - g.s.PushDKGComplaint(b) - addr := node.Owner - addrs[round] = append(addrs[round], addr) - // Prepare MPK Ready. - g.s.PutDKGMPKReady(addr, true) - g.s.IncDKGMPKReadysCount() - if final { - // Prepare Finalized. - g.s.PutDKGFinalized(addr, true) - g.s.IncDKGFinalizedsCount() - // Prepare Success. - g.s.PutDKGSuccess(addr, true) - g.s.IncDKGSuccessesCount() - } - i += 1 - } - dkgSetSize := len(dkgSet) - g.Require().Len(g.s.DKGMasterPublicKeys(), dkgSetSize) - g.Require().Len(g.s.DKGComplaints(), dkgSetSize) - g.Require().Equal(int64(dkgSetSize), g.s.DKGMPKReadysCount().Int64()) - for _, addr := range addrs[round] { - g.Require().True(g.s.DKGMPKReady(addr)) - } - - if final { - g.Require().Equal(int64(dkgSetSize), g.s.DKGFinalizedsCount().Int64()) - for _, addr := range addrs[round] { - g.Require().True(g.s.DKGFinalized(addr)) - } - g.Require().Equal(int64(dkgSetSize), g.s.DKGSuccessesCount().Int64()) - for _, addr := range addrs[round] { - g.Require().True(g.s.DKGSuccess(addr)) - } - } - - } - - mock := &testCoreMock{ - tsigReturn: true, - } - OracleContracts[GovernanceContractAddress] = func() OracleContract { - return &GovernanceContract{ - coreDKGUtils: mock, - } - } - - // Fill data for previous rounds. - roundHeight := int64(g.config.RoundLength) - round := int(dexCore.DKGDelayRound) + 3 - for i := 0; i <= round; i++ { - g.context.Round = big.NewInt(int64(i)) - - // Prepare Round Height - if i != 0 { - g.s.PushRoundHeight(big.NewInt(int64(i) * roundHeight)) - } - - addDKG(i+1, true, true) - } - - round++ - g.s.PushRoundHeight(big.NewInt(int64(round) * roundHeight)) - g.context.Round = big.NewInt(int64(round)) - addDKG(round+1, false, true) - repeat := 3 - for r := 0; r < repeat; r++ { - // Add one finalized for test. - roundPlusOne := big.NewInt(int64(round + 1)) - g.s.PutDKGFinalized(addrs[round+1][0], true) - g.s.IncDKGFinalizedsCount() - - g.context.BlockNumber = big.NewInt( - roundHeight*int64(round) + roundHeight*int64(r) + roundHeight*85/100) - _, addr := newPrefundAccount(g.stateDB) - newCRS := randomBytes(common.HashLength, common.HashLength) - input, err := GovernanceABI.ABI.Pack("resetDKG", newCRS) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - - // Test if CRS is reset. - newCRSHash := crypto.Keccak256Hash(newCRS) - g.Require().Equal(newCRSHash, g.s.CRS()) - - // Test if MPK is purged. - g.Require().Len(g.s.DKGMasterPublicKeys(), 0) - // Test if MPKReady is purged. - g.Require().Equal(int64(0), g.s.DKGMPKReadysCount().Int64()) - for _, addr := range addrs[round+1] { - g.Require().False(g.s.DKGMPKReady(addr)) - } - // Test if Complaint is purged. - g.Require().Len(g.s.DKGComplaints(), 0) - // Test if Finalized is purged. - g.Require().Equal(int64(0), g.s.DKGFinalizedsCount().Int64()) - for _, addr := range addrs[round+1] { - g.Require().False(g.s.DKGFinalized(addr)) - } - // Test if Success is purged. - g.Require().Equal(int64(0), g.s.DKGSuccessesCount().Int64()) - for _, addr := range addrs[round+1] { - g.Require().False(g.s.DKGSuccess(addr)) - } - - g.Require().Equal(int64(r+1), g.s.DKGResetCount(roundPlusOne).Int64()) - - addDKG(round+1, false, false) - } -} - -func TestOracleContracts(t *testing.T) { - suite.Run(t, new(OracleContractsTestSuite)) -} -- cgit