diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/vm/oracle_contract_abi.go | 840 | ||||
-rw-r--r-- | core/vm/oracle_contracts.go | 182 | ||||
-rw-r--r-- | core/vm/oracle_contracts_test.go | 191 |
3 files changed, 842 insertions, 371 deletions
diff --git a/core/vm/oracle_contract_abi.go b/core/vm/oracle_contract_abi.go index 535161bd4..23ec7cd9d 100644 --- a/core/vm/oracle_contract_abi.go +++ b/core/vm/oracle_contract_abi.go @@ -56,6 +56,60 @@ const GovernanceABIJSON = ` "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": true, "inputs": [], "name": "totalSupply", @@ -70,6 +124,39 @@ const GovernanceABIJSON = ` "type": "function" }, { + "constant": false, + "inputs": [ + { + "name": "PublicKey", + "type": "bytes" + } + ], + "name": "addDKGMasterPublicKey", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "addressWhitelist", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { "constant": true, "inputs": [ { @@ -139,6 +226,20 @@ const GovernanceABIJSON = ` "type": "function" }, { + "constant": false, + "inputs": [ + { + "name": "MPKReady", + "type": "bytes" + } + ], + "name": "addDKGMPKReady", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { "constant": true, "inputs": [], "name": "miningVelocity", @@ -153,6 +254,20 @@ const GovernanceABIJSON = ` "type": "function" }, { + "constant": false, + "inputs": [ + { + "name": "Finalize", + "type": "bytes" + } + ], + "name": "addDKGFinalize", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { "constant": true, "inputs": [], "name": "lambdaBA", @@ -167,6 +282,42 @@ const GovernanceABIJSON = ` "type": "function" }, { + "constant": false, + "inputs": [ + { + "name": "Amount", + "type": "uint256" + } + ], + "name": "unstake", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "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": true, "inputs": [], "name": "minStake", @@ -181,6 +332,66 @@ const GovernanceABIJSON = ` "type": "function" }, { + "constant": false, + "inputs": [], + "name": "stake", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "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": "NewPublicKey", + "type": "bytes" + } + ], + "name": "replaceNodePublicKey", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "NewOwner", + "type": "address" + } + ], + "name": "transferNodeOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { "constant": true, "inputs": [], "name": "crsRound", @@ -223,6 +434,48 @@ const GovernanceABIJSON = ` "type": "function" }, { + "constant": false, + "inputs": [ + { + "name": "Success", + "type": "bytes" + } + ], + "name": "addDKGSuccess", + "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": "NewSignedCRS", + "type": "bytes" + } + ], + "name": "resetDKG", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { "constant": true, "inputs": [ { @@ -258,6 +511,20 @@ const GovernanceABIJSON = ` { "constant": true, "inputs": [], + "name": "whitelistLength", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], "name": "dkgRound", "outputs": [ { @@ -270,6 +537,24 @@ const GovernanceABIJSON = ` "type": "function" }, { + "constant": false, + "inputs": [ + { + "name": "OldOwner", + "type": "address" + }, + { + "name": "NewOwner", + "type": "address" + } + ], + "name": "transferNodeOwnershipByFoundation", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { "constant": true, "inputs": [], "name": "totalStaked", @@ -317,6 +602,25 @@ const GovernanceABIJSON = ` "type": "function" }, { + "constant": false, + "inputs": [ + { + "name": "addr", + "type": "address" + } + ], + "name": "removeFromWhitelist", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { "constant": true, "inputs": [], "name": "roundLength", @@ -382,6 +686,25 @@ const GovernanceABIJSON = ` "inputs": [ { "name": "", + "type": "address" + } + ], + "name": "whitelistOffsetByAddress", + "outputs": [ + { + "name": "", + "type": "int256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", "type": "bytes32" } ], @@ -463,6 +786,20 @@ const GovernanceABIJSON = ` "type": "function" }, { + "constant": false, + "inputs": [ + { + "name": "Complaint", + "type": "bytes" + } + ], + "name": "addDKGComplaint", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { "constant": true, "inputs": [ { @@ -529,6 +866,50 @@ const GovernanceABIJSON = ` "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": "Name", + "type": "string" + }, + { + "name": "Email", + "type": "string" + }, + { + "name": "Location", + "type": "string" + }, + { + "name": "Url", + "type": "string" + } + ], + "name": "updateNodeInfo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { "constant": true, "inputs": [ { @@ -548,6 +929,36 @@ const GovernanceABIJSON = ` "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": true, "inputs": [ { @@ -595,6 +1006,25 @@ const GovernanceABIJSON = ` "type": "function" }, { + "constant": false, + "inputs": [ + { + "name": "addr", + "type": "address" + } + ], + "name": "addToWhitelist", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { "constant": true, "inputs": [ { @@ -666,6 +1096,48 @@ const GovernanceABIJSON = ` "type": "function" }, { + "constant": false, + "inputs": [ + { + "name": "NewOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "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": "isConsortium", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { "anonymous": false, "inputs": [], "name": "ConfigurationChanged", @@ -874,374 +1346,6 @@ const GovernanceABIJSON = ` ], "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": "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": "NodeAddress", - "type": "address" - } - ], - "name": "payFine", - "outputs": [], - "payable": true, - "stateMutability": "payable", - "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": "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" - }, - { - "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": "NewPublicKey", - "type": "bytes" - } - ], - "name": "replaceNodePublicKey", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [], - "name": "stake", - "outputs": [], - "payable": true, - "stateMutability": "payable", - "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": "Amount", - "type": "uint256" - } - ], - "name": "unstake", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "Name", - "type": "string" - }, - { - "name": "Email", - "type": "string" - }, - { - "name": "Location", - "type": "string" - }, - { - "name": "Url", - "type": "string" - } - ], - "name": "updateNodeInfo", - "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" } ] ` diff --git a/core/vm/oracle_contracts.go b/core/vm/oracle_contracts.go index ddcd6d3f6..130d5bf24 100644 --- a/core/vm/oracle_contracts.go +++ b/core/vm/oracle_contracts.go @@ -99,6 +99,9 @@ const ( minBlockIntervalLoc fineValuesLoc finedRecordsLoc + isConsortiumLoc + addressWhitelistLoc + whitelistOffsetByAddressLoc ) func publicKeyToNodeKeyAddress(pkBytes []byte) (common.Address, error) { @@ -124,7 +127,7 @@ func IdToAddress(id coreTypes.NodeID) common.Address { return common.BytesToAddress(id.Hash[12:]) } -// State manipulation helper fro the governance contract. +// State manipulation helper for the governance contract. type GovernanceState struct { StateDB StateDB } @@ -984,6 +987,80 @@ func (s *GovernanceState) SetFineRecords(recordHash Bytes32, status bool) { s.setStateBigInt(loc, big.NewInt(value)) } +// bool public isConsortium; +func (s *GovernanceState) IsConsortium() bool { + return s.getStateBigInt(big.NewInt(isConsortiumLoc)).Cmp(big.NewInt(0)) > 0 +} +func (s *GovernanceState) EnableConsortium() { + s.setStateBigInt(big.NewInt(isConsortiumLoc), big.NewInt(1)) +} + +// address[] public addressWhitelist; +func (s *GovernanceState) LenWhitelist() *big.Int { + return s.getStateBigInt(big.NewInt(addressWhitelistLoc)) +} +func (s *GovernanceState) AddressWhitelist(index *big.Int) common.Address { + arrayBaseLoc := s.getSlotLoc(big.NewInt(addressWhitelistLoc)) + return common.BigToAddress(s.getStateBigInt(new(big.Int).Add(arrayBaseLoc, index))) +} +func (s *GovernanceState) AddressWhitelists() []common.Address { + len := s.LenWhitelist() + result := make([]common.Address, len.Uint64()) + for i := 0; i < int(len.Uint64()); i++ { + result[i] = s.AddressWhitelist(big.NewInt(int64(i))) + } + return result +} +func (s *GovernanceState) putAddressWhitelist(addr common.Address, offset *big.Int) { + arrayBaseLoc := s.getSlotLoc(big.NewInt(addressWhitelistLoc)) + loc := new(big.Int).Add(arrayBaseLoc, offset) + s.setState(common.BigToHash(loc), addr.Hash()) + s.putWhitelistOffsetByAddress(addr, offset) +} +func (s *GovernanceState) AddToWhitelist(addr common.Address) *big.Int { + offset := s.WhitelistOffsetByAddress(addr) + if offset.Cmp(bigZero) >= 0 { + return offset + } + len := s.getStateBigInt(big.NewInt(addressWhitelistLoc)) + s.putAddressWhitelist(addr, len) + len = new(big.Int).Add(len, big.NewInt(1)) + s.setStateBigInt(big.NewInt(addressWhitelistLoc), len) + return len +} +func (s *GovernanceState) DeleteAddressWhitelist(addr common.Address) *big.Int { + offset := s.WhitelistOffsetByAddress(addr) + if offset.Cmp(bigZero) < 0 { + return offset + } + s.DeleteWhitelistOffsetByAddress(addr) + len := s.getStateBigInt(big.NewInt(addressWhitelistLoc)) + newLen := new(big.Int).Sub(len, big.NewInt(1)) + if len.Cmp(big.NewInt(1)) > 0 && offset.Cmp(newLen) != 0 { + lastAddr := s.AddressWhitelist(newLen) + s.putAddressWhitelist(lastAddr, offset) + } + s.setStateBigInt( + big.NewInt(addressWhitelistLoc), + newLen, + ) + return len +} + +// mapping(address => int256) whitelistOffsetByAddress +func (s *GovernanceState) WhitelistOffsetByAddress(addr common.Address) *big.Int { + loc := s.getMapLoc(big.NewInt(whitelistOffsetByAddressLoc), addr.Bytes()) + return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1)) +} +func (s *GovernanceState) putWhitelistOffsetByAddress(addr common.Address, offset *big.Int) { + loc := s.getMapLoc(big.NewInt(whitelistOffsetByAddressLoc), addr.Bytes()) + s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1))) +} +func (s *GovernanceState) DeleteWhitelistOffsetByAddress(addr common.Address) { + loc := s.getMapLoc(big.NewInt(whitelistOffsetByAddressLoc), addr.Bytes()) + s.setStateBigInt(loc, big.NewInt(0)) +} + // Initialize initializes governance contract state. func (s *GovernanceState) Initialize(config *params.DexconConfig, totalSupply *big.Int) { if config.NextHalvingSupply.Cmp(totalSupply) <= 0 { @@ -1009,6 +1086,22 @@ func (s *GovernanceState) Initialize(config *params.DexconConfig, totalSupply *b // Set DKGRound. s.SetDKGRound(big.NewInt(int64(dexCore.DKGDelayRound))) + + // Set Whitelist + s.setWhitelist(config.IsConsortium) +} + +func (s *GovernanceState) setWhitelist(isConsortium bool) { + if isConsortium { + s.EnableConsortium() + for _, node := range s.Nodes() { + address, err := publicKeyToNodeKeyAddress(node.PublicKey) + if err != nil { + panic(err) + } + s.AddToWhitelist(address) + } + } } // Register is a helper function for creating genesis state. @@ -1079,6 +1172,8 @@ func (s *GovernanceState) Configuration() *params.DexconConfig { RoundLength: s.getStateBigInt(big.NewInt(roundLengthLoc)).Uint64(), MinBlockInterval: s.getStateBigInt(big.NewInt(minBlockIntervalLoc)).Uint64(), FineValues: s.FineValues(), + AddressWhitelist: s.AddressWhitelists(), + IsConsortium: s.getStateBigInt(big.NewInt(isConsortiumLoc)).Uint64() != 0, } } @@ -1098,7 +1193,11 @@ func (s *GovernanceState) UpdateConfiguration(cfg *params.DexconConfig) { s.setStateBigInt(big.NewInt(roundLengthLoc), big.NewInt(int64(cfg.RoundLength))) s.setStateBigInt(big.NewInt(minBlockIntervalLoc), big.NewInt(int64(cfg.MinBlockInterval))) s.SetFineValues(cfg.FineValues) - + if cfg.IsConsortium { + for _, addr := range cfg.AddressWhitelist { + s.AddToWhitelist(addr) + } + } // Calculate set size. s.CalNotarySetSize() } @@ -2274,6 +2373,20 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re return nil, errExecutionReverted } return g.addDKGSuccess(Success) + case "addToWhitelist": + var address common.Address + if err := method.Inputs.Unpack(&address, arguments); err != nil { + return nil, errExecutionReverted + } + offset, err := g.addToWhitelist(address) + if err != nil { + return nil, errExecutionReverted + } + res, err := method.Outputs.Pack(offset) + if err != nil { + return nil, errExecutionReverted + } + return res, nil case "nodesLength": res, err := method.Outputs.Pack(g.state.LenNodes()) if err != nil { @@ -2295,6 +2408,20 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re return nil, errExecutionReverted } return g.proposeCRS(args.Round, args.SignedCRS) + case "removeFromWhitelist": + var address common.Address + if err := method.Inputs.Unpack(&address, arguments); err != nil { + return nil, errExecutionReverted + } + offset, err := g.removeFromWhitelist(address) + if err != nil { + return nil, errExecutionReverted + } + res, err := method.Outputs.Pack(offset) + if err != nil { + return nil, errExecutionReverted + } + return res, nil case "report": args := struct { Type *big.Int @@ -2371,6 +2498,12 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re return nil, errExecutionReverted } return g.updateNodeInfo(args.Name, args.Email, args.Location, args.Url) + case "whitelistLength": + res, err := method.Outputs.Pack(g.state.LenWhitelist()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil case "withdraw": return g.withdraw() case "withdrawable": @@ -2379,11 +2512,21 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re return nil, errExecutionReverted } return res, nil - // -------------------------------- // Solidity auto generated methods. // -------------------------------- + case "addressWhitelist": + offset := new(big.Int) + if err := method.Inputs.Unpack(&offset, arguments); err != nil { + return nil, errExecutionReverted + } + address := g.state.AddressWhitelist(offset) + res, err := method.Outputs.Pack(address) + if err != nil { + return nil, errExecutionReverted + } + return res, nil case "blockGasLimit": res, err := method.Outputs.Pack(g.state.BlockGasLimit()) if err != nil { @@ -2538,6 +2681,12 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re return nil, errExecutionReverted } return res, nil + case "isConsortium": + res, err := method.Outputs.Pack(g.state.IsConsortium()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil case "lambdaBA": res, err := method.Outputs.Pack(g.state.LambdaBA()) if err != nil { @@ -2694,7 +2843,18 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re return nil, errExecutionReverted } return res, nil + case "whitelistOffsetByAddress": + address := common.Address{} + if err := method.Inputs.Unpack(&address, arguments); err != nil { + return nil, errExecutionReverted + } + res, err := method.Outputs.Pack(g.state.WhitelistOffsetByAddress(address)) + if err != nil { + return nil, errExecutionReverted + } + return res, nil } + return nil, errExecutionReverted } @@ -2801,6 +2961,22 @@ func (g *GovernanceContract) replaceNodePublicKey(newPublicKey []byte) ([]byte, return nil, nil } +func (g *GovernanceContract) addToWhitelist(addr common.Address) (*big.Int, error) { + // Only owner can update whitelist. + if g.contract.Caller() != g.state.Owner() { + return nil, errExecutionReverted + } + return g.state.AddToWhitelist(addr), nil +} + +func (g *GovernanceContract) removeFromWhitelist(addr common.Address) (*big.Int, error) { + // Only owner can update whitelist. + if g.contract.Caller() != g.state.Owner() { + return nil, errExecutionReverted + } + return g.state.DeleteAddressWhitelist(addr), nil +} + func PackProposeCRS(round uint64, signedCRS []byte) ([]byte, error) { method := GovernanceABI.Name2Method["proposeCRS"] res, err := method.Inputs.Pack(big.NewInt(int64(round)), signedCRS) diff --git a/core/vm/oracle_contracts_test.go b/core/vm/oracle_contracts_test.go index 192628b22..bf2f7c71a 100644 --- a/core/vm/oracle_contracts_test.go +++ b/core/vm/oracle_contracts_test.go @@ -1022,6 +1022,137 @@ func (g *GovernanceContractTestSuite) TestMiscVariableReading() { g.Require().NoError(err) } +func (g *GovernanceContractTestSuite) TestIsConsortium() { + var isConsortium bool + + _, addr1 := newPrefundAccount(g.stateDB) + + input, err := GovernanceABI.ABI.Pack("isConsortium") + g.Require().NoError(err) + res, err := g.call(GovernanceContractAddress, addr1, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&isConsortium, "isConsortium", res) + g.Require().NoError(err) + g.Require().Equal(false, isConsortium) + + g.s.EnableConsortium() + res, err = g.call(GovernanceContractAddress, addr1, input, big.NewInt(0)) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&isConsortium, "isConsortium", res) + g.Require().NoError(err) + g.Require().Equal(true, isConsortium) +} + +func (g *GovernanceContractTestSuite) TestUpdateWhitelist() { + checkLength := func(expectLen *big.Int) { + var length *big.Int + + lenInput, err := GovernanceABI.ABI.Pack("whitelistLength") + g.Require().NoError(err) + res, err := g.call(GovernanceContractAddress, g.config.Owner, lenInput, big.NewInt(0)) + err = GovernanceABI.ABI.Unpack(&length, "whitelistLength", res) + g.Require().NoError(err) + g.Require().Equal(expectLen.Int64(), length.Int64()) + } + check := func(addr common.Address, offset *big.Int) { + var resOffset *big.Int + var resAddr common.Address + + value := big.NewInt(0) + // check offset + input, err := GovernanceABI.ABI.Pack("whitelistOffsetByAddress", addr) + g.Require().NoError(err) + res, err := g.call(GovernanceContractAddress, addr, input, value) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&resOffset, "whitelistOffsetByAddress", res) + g.Require().NoError(err) + g.Require().Equal(offset.Int64(), resOffset.Int64()) + + // check address + if offset.Cmp(big.NewInt(0)) >= 0 { + input, err = GovernanceABI.ABI.Pack("addressWhitelist", offset) + res, err = g.call(GovernanceContractAddress, addr, input, value) + g.Require().NoError(err) + err = GovernanceABI.ABI.Unpack(&resAddr, "addressWhitelist", res) + g.Require().NoError(err) + g.Require().Equal(addr, resAddr) + } + } + _, addr1 := newPrefundAccount(g.stateDB) + _, addr2 := newPrefundAccount(g.stateDB) + _, addr3 := newPrefundAccount(g.stateDB) + + input, err := GovernanceABI.ABI.Pack("addToWhitelist", addr1) + g.Require().NoError(err) + + // Call with non-owner. + _, err = g.call(GovernanceContractAddress, addr1, 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) + checkLength(big.NewInt(1)) + // duplicated call should not affect + _, err = g.call(GovernanceContractAddress, g.config.Owner, input, big.NewInt(0)) + g.Require().NoError(err) + checkLength(big.NewInt(1)) + // append addr2 + input, err = GovernanceABI.ABI.Pack("addToWhitelist", addr2) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, g.config.Owner, input, big.NewInt(0)) + g.Require().NoError(err) + + checkLength(big.NewInt(2)) + check(addr1, big.NewInt(0)) + check(addr2, big.NewInt(1)) + + // delete addr2 + input, err = GovernanceABI.ABI.Pack("removeFromWhitelist", addr2) + g.Require().NoError(err) + // Call with non-owner. + _, err = g.call(GovernanceContractAddress, addr1, 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) + check(addr2, big.NewInt(-1)) + checkLength(big.NewInt(1)) + + // append addr2 back + input, err = GovernanceABI.ABI.Pack("addToWhitelist", addr2) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, g.config.Owner, input, big.NewInt(0)) + g.Require().NoError(err) + checkLength(big.NewInt(2)) + check(addr1, big.NewInt(0)) + check(addr2, big.NewInt(1)) + + // delete addr1 + input, err = GovernanceABI.ABI.Pack("removeFromWhitelist", addr1) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, g.config.Owner, input, big.NewInt(0)) + g.Require().NoError(err) + check(addr1, big.NewInt(-1)) + check(addr2, big.NewInt(0)) + checkLength(big.NewInt(1)) + + // delete addr2 + input, err = GovernanceABI.ABI.Pack("removeFromWhitelist", addr2) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, g.config.Owner, input, big.NewInt(0)) + g.Require().NoError(err) + check(addr1, big.NewInt(-1)) + check(addr2, big.NewInt(-1)) + checkLength(big.NewInt(0)) + + // duplicated delete addr2 + input, err = GovernanceABI.ABI.Pack("removeFromWhitelist", addr2) + g.Require().NoError(err) + // delete not in whitelist address + input, err = GovernanceABI.ABI.Pack("removeFromWhitelist", addr3) + g.Require().NoError(err) +} + func (g *GovernanceContractTestSuite) TestHalvingCondition() { // TotalSupply 2.5B reached g.s.MiningHalved() @@ -1244,6 +1375,66 @@ func (g *GovernanceContractTestSuite) TestResetDKG() { } } +func (g *GovernanceContractTestSuite) TestConsortium() { + g.Require().False(g.s.IsConsortium()) + g.s.EnableConsortium() + g.Require().True(g.s.IsConsortium()) +} + +func (g *GovernanceContractTestSuite) TestAddWhitelist() { + _, addr1 := newPrefundAccount(g.stateDB) + _, addr2 := newPrefundAccount(g.stateDB) + _, addr3 := newPrefundAccount(g.stateDB) + // no address in list + expectAddress := g.s.AddressWhitelist(big.NewInt(0)) + g.Require().Equal(common.Address{}, expectAddress) + expectAddrList := g.s.AddressWhitelists() + g.Require().Equal([]common.Address{}, expectAddrList) + + // insert addr + g.s.AddToWhitelist(addr1) + g.s.AddToWhitelist(addr1) // duplicated insertion should be ignored + expectAddress = g.s.AddressWhitelist(big.NewInt(0)) + g.Require().Equal(addr1, expectAddress) + expectAddrList = g.s.AddressWhitelists() + g.Require().Equal([]common.Address{addr1}, expectAddrList) + + g.s.AddToWhitelist(addr2) + expectAddress = g.s.AddressWhitelist(big.NewInt(1)) + g.Require().Equal(addr2, expectAddress) + expectAddrList = g.s.AddressWhitelists() + g.Require().Equal([]common.Address{addr1, addr2}, expectAddrList) + + offset := g.s.WhitelistOffsetByAddress(addr1) + g.Require().Equal(true, offset.Cmp(big.NewInt(0)) == 0) + offset = g.s.WhitelistOffsetByAddress(addr2) + g.Require().Equal(true, offset.Cmp(big.NewInt(1)) == 0) + offset = g.s.WhitelistOffsetByAddress(addr3) + g.Require().Equal(true, offset.Cmp(big.NewInt(-1)) == 0) + + // remove addr + g.s.DeleteAddressWhitelist(addr1) + g.s.DeleteAddressWhitelist(addr1) // duplicated remove should be ignored + + offset = g.s.WhitelistOffsetByAddress(addr1) + g.Require().Equal(true, offset.Cmp(big.NewInt(-1)) == 0) + offset = g.s.WhitelistOffsetByAddress(addr2) + g.Require().Equal(true, offset.Cmp(big.NewInt(0)) == 0) + + expectAddress = g.s.AddressWhitelist(big.NewInt(0)) + g.Require().Equal(addr2, expectAddress) + expectAddrList = g.s.AddressWhitelists() + g.Require().Equal([]common.Address{addr2}, expectAddrList) + + g.s.DeleteAddressWhitelist(addr2) + + offset = g.s.WhitelistOffsetByAddress(addr2) + g.Require().Equal(true, offset.Cmp(big.NewInt(-1)) == 0) + + expectAddrList = g.s.AddressWhitelists() + g.Require().Equal([]common.Address{}, expectAddrList) +} + func TestGovernanceContract(t *testing.T) { suite.Run(t, new(GovernanceContractTestSuite)) } |