diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/genesis.go | 5 | ||||
-rw-r--r-- | core/genesis_test.go | 2 | ||||
-rw-r--r-- | core/vm/oracle.go | 4 | ||||
-rw-r--r-- | core/vm/oracle_contract_abi.go | 255 | ||||
-rw-r--r-- | core/vm/oracle_contracts.go | 573 | ||||
-rw-r--r-- | core/vm/oracle_contracts_test.go | 421 |
6 files changed, 263 insertions, 997 deletions
diff --git a/core/genesis.go b/core/genesis.go index f6935830c..7f2cafbf5 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -302,9 +302,10 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block { for _, addr := range keys { account := g.Alloc[addr] if account.Staked.Cmp(big.NewInt(0)) > 0 { - govStateHelper.Stake(addr, account.PublicKey, account.Staked, + govStateHelper.Register(addr, account.PublicKey, account.NodeInfo.Name, account.NodeInfo.Email, - account.NodeInfo.Location, account.NodeInfo.Url) + account.NodeInfo.Location, account.NodeInfo.Url, + account.Staked) } } diff --git a/core/genesis_test.go b/core/genesis_test.go index c083ed9aa..de843e05a 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -43,7 +43,7 @@ func TestDefaultGenesisBlock(t *testing.T) { func TestSetupGenesis(t *testing.T) { var ( - customghash = common.HexToHash("0xbd64608d51b78fd61aeb6d91669fd3ff09c12c7552f0923b0c2d19910887efda") + customghash = common.HexToHash("0x1f619d2e0f8293d83dad154ef95f6e09dcfdbe92b7f06f658d5dece20e5132e4") customg = Genesis{ Config: ¶ms.ChainConfig{HomesteadBlock: big.NewInt(3)}, Alloc: GenesisAlloc{ diff --git a/core/vm/oracle.go b/core/vm/oracle.go index 14ba9b2f5..81755cd9b 100644 --- a/core/vm/oracle.go +++ b/core/vm/oracle.go @@ -25,14 +25,11 @@ import ( ) var GovernanceContractAddress = common.HexToAddress("63751838d6485578b23e8b051d40861ecc416794") -var NodeInfoOracleAddress = common.HexToAddress("58a7c88ad1f32e7252bebba54def98d3e7b3df11") var GovernanceABI *OracleContractABI -var NodeInfoOracleABI *OracleContractABI func init() { GovernanceABI = NewOracleContractABI(GovernanceABIJSON) - NodeInfoOracleABI = NewOracleContractABI(NodeInfoOracleABIJSON) } // OracleContract represent special system contracts written in Go. @@ -45,7 +42,6 @@ var OracleContracts = map[common.Address]OracleContract{ GovernanceContractAddress: &GovernanceContract{ coreDKGUtils: &defaultCoreDKGUtils{}, }, - NodeInfoOracleAddress: &NodeInfoOracleContract{}, } // Run oracle contract. diff --git a/core/vm/oracle_contract_abi.go b/core/vm/oracle_contract_abi.go index 2de3d650f..23fb99ae5 100644 --- a/core/vm/oracle_contract_abi.go +++ b/core/vm/oracle_contract_abi.go @@ -24,29 +24,6 @@ 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": "notarySetSize", "outputs": [ @@ -128,6 +105,14 @@ const GovernanceABIJSON = ` { "name": "url", "type": "string" + }, + { + "name": "unstaked", + "type": "uint256" + }, + { + "name": "unstaked_at", + "type": "uint256" } ], "payable": false, @@ -196,37 +181,6 @@ const GovernanceABIJSON = ` { "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": "", - "type": "address" } ], "name": "dkgFinalizeds", @@ -637,6 +591,11 @@ const GovernanceABIJSON = ` "indexed": true, "name": "NodeAddress", "type": "address" + }, + { + "indexed": false, + "name": "Amount", + "type": "uint256" } ], "name": "Staked", @@ -649,21 +608,14 @@ const GovernanceABIJSON = ` "indexed": true, "name": "NodeAddress", "type": "address" - } - ], - "name": "Unstaked", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + }, { - "indexed": true, - "name": "NodeAddress", - "type": "address" + "indexed": false, + "name": "Amount", + "type": "uint256" } ], - "name": "NodeRemoved", + "name": "Unstaked", "type": "event" }, { @@ -675,17 +627,12 @@ const GovernanceABIJSON = ` "type": "address" }, { - "indexed": true, - "name": "DelegatorAddress", - "type": "address" - }, - { "indexed": false, "name": "Amount", "type": "uint256" } ], - "name": "Delegated", + "name": "Withdrawn", "type": "event" }, { @@ -695,19 +642,9 @@ const GovernanceABIJSON = ` "indexed": true, "name": "NodeAddress", "type": "address" - }, - { - "indexed": true, - "name": "DelegatorAddress", - "type": "address" - }, - { - "indexed": false, - "name": "Amount", - "type": "uint256" } ], - "name": "Undelegated", + "name": "NodeAdded", "type": "event" }, { @@ -717,19 +654,9 @@ const GovernanceABIJSON = ` "indexed": true, "name": "NodeAddress", "type": "address" - }, - { - "indexed": true, - "name": "DelegatorAddress", - "type": "address" - }, - { - "indexed": false, - "name": "Amount", - "type": "uint256" } ], - "name": "Withdrawn", + "name": "NodeRemoved", "type": "event" }, { @@ -893,25 +820,6 @@ const GovernanceABIJSON = ` "type": "function" }, { - "constant": true, - "inputs": [ - { - "name": "NodeAddress", - "type": "address" - } - ], - "name": "delegatorsLength", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { "constant": false, "inputs": [ { @@ -1025,7 +933,7 @@ const GovernanceABIJSON = ` "type": "string" } ], - "name": "stake", + "name": "register", "outputs": [], "payable": true, "stateMutability": "payable", @@ -1034,21 +942,7 @@ const GovernanceABIJSON = ` { "constant": false, "inputs": [], - "name": "unstake", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "NodeAddress", - "type": "address" - } - ], - "name": "delegate", + "name": "stake", "outputs": [], "payable": true, "stateMutability": "payable", @@ -1058,11 +952,11 @@ const GovernanceABIJSON = ` "constant": false, "inputs": [ { - "name": "NodeAddress", - "type": "address" + "name": "Amount", + "type": "uint256" } ], - "name": "undelegate", + "name": "unstake", "outputs": [], "payable": false, "stateMutability": "nonpayable", @@ -1070,12 +964,7 @@ const GovernanceABIJSON = ` }, { "constant": false, - "inputs": [ - { - "name": "NodeAddress", - "type": "address" - } - ], + "inputs": [], "name": "withdraw", "outputs": [], "payable": false, @@ -1134,93 +1023,3 @@ const GovernanceABIJSON = ` } ] ` - -const NodeInfoOracleABIJSON = ` -[ - { - "constant": true, - "inputs": [ - { - "name": "Round", - "type": "uint256" - }, - { - "name": "NodeAddress", - "type": "address" - }, - { - "name": "Index", - "type": "uint256" - } - ], - "name": "delegators", - "outputs": [ - { - "name": "owner", - "type": "address" - }, - { - "name": "value", - "type": "uint256" - }, - { - "name": "undelegated_at", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "Round", - "type": "uint256" - }, - { - "name": "NodeAddress", - "type": "address" - } - ], - "name": "delegatorsLength", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "Round", - "type": "uint256" - }, - { - "name": "NodeAddress", - "type": "address" - }, - { - "name": "DelegatorAddress", - "type": "address" - } - ], - "name": "delegatorsOffset", - "outputs": [ - { - "name": "", - "type": "int256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - } -] -` diff --git a/core/vm/oracle_contracts.go b/core/vm/oracle_contracts.go index 5c5a44185..0904c2430 100644 --- a/core/vm/oracle_contracts.go +++ b/core/vm/oracle_contracts.go @@ -59,8 +59,6 @@ const ( nodesLoc nodesOffsetByAddressLoc nodesOffsetByNodeKeyAddressLoc - delegatorsLoc - delegatorsOffsetLoc crsRoundLoc crsLoc dkgRoundLoc @@ -316,22 +314,26 @@ func (s *GovernanceState) DecTotalStaked(amount *big.Int) { // string email; // string location; // string url; +// uint256 unstaked; +// uint256 unstaked_at; // } // // Node[] nodes; type nodeInfo struct { - Owner common.Address - PublicKey []byte - Staked *big.Int - Fined *big.Int - Name string - Email string - Location string - Url string + 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 = 8 +const nodeStructSize = 10 func (s *GovernanceState) LenNodes() *big.Int { return s.getStateBigInt(big.NewInt(nodesLoc)) @@ -375,6 +377,14 @@ func (s *GovernanceState) Node(index *big.Int) *nodeInfo { 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) { @@ -420,6 +430,14 @@ func (s *GovernanceState) UpdateNode(index *big.Int, n *nodeInfo) { // 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) } func (s *GovernanceState) PopLastNode() { // Decrease length by 1. @@ -428,8 +446,10 @@ func (s *GovernanceState) PopLastNode() { s.setStateBigInt(big.NewInt(nodesLoc), newArrayLength) s.UpdateNode(newArrayLength, &nodeInfo{ - Staked: big.NewInt(0), - Fined: big.NewInt(0), + Staked: big.NewInt(0), + Fined: big.NewInt(0), + Unstaked: big.NewInt(0), + UnstakedAt: big.NewInt(0), }) } func (s *GovernanceState) Nodes() []*nodeInfo { @@ -487,6 +507,15 @@ func (s *GovernanceState) PutNodeOffsets(n *nodeInfo, offset *big.Int) error { s.PutNodesOffsetByAddress(n.Owner, offset) return nil } +func (s *GovernanceState) DeleteNodeOffsets(n *nodeInfo) error { + address, err := publicKeyToNodeKeyAddress(n.PublicKey) + if err != nil { + return err + } + s.DeleteNodesOffsetByNodeKeyAddress(address) + s.DeleteNodesOffsetByAddress(n.Owner) + return nil +} func (s *GovernanceState) GetNodeOwnerByID(id coreTypes.NodeID) (common.Address, error) { offset := s.NodesOffsetByNodeKeyAddress(idToAddress(id)) @@ -497,99 +526,6 @@ func (s *GovernanceState) GetNodeOwnerByID(id coreTypes.NodeID) (common.Address, return node.Owner, 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 *GovernanceState) LenDelegators(nodeAddr common.Address) *big.Int { - loc := s.getMapLoc(big.NewInt(delegatorsLoc), nodeAddr.Bytes()) - return s.getStateBigInt(loc) -} -func (s *GovernanceState) 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 *GovernanceState) 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 *GovernanceState) 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 *GovernanceState) 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 *GovernanceState) 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 *GovernanceState) 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 *GovernanceState) DeleteDelegatorsOffset(nodeAddr, delegatorAddr common.Address) { - loc := s.getMapLoc(s.getMapLoc(big.NewInt(delegatorsOffsetLoc), nodeAddr.Bytes()), delegatorAddr.Bytes()) - s.setStateBigInt(loc, big.NewInt(0)) -} - // uint256 public crsRound; func (s *GovernanceState) CRSRound() *big.Int { return s.getStateBigInt(big.NewInt(crsRoundLoc)) @@ -900,20 +836,22 @@ func (s *GovernanceState) Initialize(config *params.DexconConfig, totalSupply *b s.SetDKGRound(big.NewInt(int64(dexCore.DKGDelayRound))) } -// Stake is a helper function for creating genesis state. -func (s *GovernanceState) Stake( - addr common.Address, publicKey []byte, staked *big.Int, - name, email, location, url string) { +// 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, + 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) if err := s.PutNodeOffsets(node, offset); err != nil { @@ -924,14 +862,6 @@ func (s *GovernanceState) Stake( 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) } @@ -1024,56 +954,47 @@ func (s *GovernanceState) emitCRSProposed(round *big.Int, crs common.Hash) { } // event Staked(address indexed NodeAddress, uint256 Amount); -func (s *GovernanceState) emitStaked(nodeAddr common.Address) { +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: []byte{}, + Data: common.BigToHash(amount).Bytes(), }) } -// event Unstaked(address indexed NodeAddress); -func (s *GovernanceState) emitUnstaked(nodeAddr common.Address) { +// 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: []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{}, + Data: common.BigToHash(amount).Bytes(), }) } -// event Delegated(address indexed NodeAddress, address indexed DelegatorAddress, uint256 Amount); -func (s *GovernanceState) emitDelegated(nodeAddr, delegatorAddr common.Address, amount *big.Int) { +// 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["Delegated"].Id(), nodeAddr.Hash(), delegatorAddr.Hash()}, + Topics: []common.Hash{GovernanceABI.Events["Withdrawn"].Id(), nodeAddr.Hash()}, Data: common.BigToHash(amount).Bytes(), }) } -// event Undelegated(address indexed NodeAddress, address indexed DelegatorAddress, uint256 Amount); -func (s *GovernanceState) emitUndelegated(nodeAddr, delegatorAddr common.Address, amount *big.Int) { +// event NodeAdded(address indexed NodeAddress); +func (s *GovernanceState) emitNodeAdded(nodeAddr common.Address) { s.StateDB.AddLog(&types.Log{ Address: GovernanceContractAddress, - Topics: []common.Hash{GovernanceABI.Events["Undelegated"].Id(), nodeAddr.Hash(), delegatorAddr.Hash()}, - Data: common.BigToHash(amount).Bytes(), + Topics: []common.Hash{GovernanceABI.Events["NodeAdded"].Id(), nodeAddr.Hash()}, + Data: []byte{}, }) } -// event Withdrawn(address indexed NodeAddress, address indexed DelegatorAddress, uint256 Amount); -func (s *GovernanceState) emitWithdrawn(nodeAddr common.Address, delegatorAddr common.Address, amount *big.Int) { +// event NodeRemoved(address indexed NodeAddress); +func (s *GovernanceState) emitNodeRemoved(nodeAddr common.Address) { s.StateDB.AddLog(&types.Log{ Address: GovernanceContractAddress, - Topics: []common.Hash{GovernanceABI.Events["Withdrawn"].Id(), nodeAddr.Hash(), delegatorAddr.Hash()}, - Data: common.BigToHash(amount).Bytes(), + Topics: []common.Hash{GovernanceABI.Events["NodeRemoved"].Id(), nodeAddr.Hash()}, + Data: []byte{}, }) } @@ -1476,47 +1397,6 @@ func (g *GovernanceContract) addDKGFinalize(round *big.Int, finalize []byte) ([] 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() { @@ -1528,7 +1408,7 @@ func (g *GovernanceContract) updateConfiguration(cfg *rawConfigStruct) ([]byte, return nil, nil } -func (g *GovernanceContract) stake( +func (g *GovernanceContract) register( publicKey []byte, name, email, location, url string) ([]byte, error) { // Reject invalid inputs. @@ -1537,6 +1417,7 @@ func (g *GovernanceContract) stake( } caller := g.contract.Caller() + value := g.contract.Value() offset := g.state.NodesOffsetByAddress(caller) // Can not stake if already staked. @@ -1546,119 +1427,121 @@ func (g *GovernanceContract) stake( 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, + 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) if err := g.state.PutNodeOffsets(node, offset); err != nil { return g.penalize() } + g.state.emitNodeAdded(caller) - // Delegate fund to itself. - if g.contract.Value().Cmp(big.NewInt(0)) > 0 { - if ret, err := g.delegate(caller); err != nil { - return ret, err - } + if value.Cmp(big.NewInt(0)) > 0 { + g.state.IncTotalStaked(value) + g.state.emitStaked(caller, value) } - - 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 { +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.DelegatorsOffset(nodeAddr, caller) + offset := g.state.NodesOffsetByAddress(caller) if offset.Cmp(big.NewInt(0)) < 0 { return nil, errExecutionReverted } - node := g.state.Node(nodeOffset) + node := g.state.Node(offset) if node.Fined.Cmp(big.NewInt(0)) > 0 { return nil, errExecutionReverted } - delegator := g.state.Delegator(nodeAddr, offset) + 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(100000) +} - if delegator.UndelegatedAt.Cmp(big.NewInt(0)) != 0 { +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 } - // Set undelegate time. - delegator.UndelegatedAt = g.evm.Time - g.state.UpdateDelegator(nodeAddr, offset, delegator) + node := g.state.Node(offset) - // Subtract from the total staked of node. - node.Staked = new(big.Int).Sub(node.Staked, delegator.Value) - g.state.UpdateNode(nodeOffset, node) + // Can not unstake if there are unpaied fine. + if node.Fined.Cmp(big.NewInt(0)) > 0 { + return nil, errExecutionReverted + } - // Subtract to network total staked. - g.state.DecTotalStaked(delegator.Value) + // 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 + } - g.state.emitUndelegated(nodeAddr, caller, delegator.Value) + node.Staked = new(big.Int).Sub(node.Staked, amount) + node.Unstaked = amount + node.UnstakedAt = g.evm.Time + g.state.UpdateNode(offset, node) - return g.useGas(100000) -} + g.state.DecTotalStaked(amount) + g.state.emitUnstaked(caller, amount) -func (g *GovernanceContract) undelegate(nodeAddr common.Address) ([]byte, error) { - return g.undelegateHelper(nodeAddr, g.contract.Caller()) + return g.useGas(100000) } -func (g *GovernanceContract) withdraw(nodeAddr common.Address) ([]byte, error) { +func (g *GovernanceContract) withdraw() ([]byte, error) { caller := g.contract.Caller() - nodeOffset := g.state.NodesOffsetByAddress(nodeAddr) - if nodeOffset.Cmp(big.NewInt(0)) < 0 { + offset := g.state.NodesOffsetByAddress(caller) + if offset.Cmp(big.NewInt(0)) < 0 { return nil, errExecutionReverted } - offset := g.state.DelegatorsOffset(nodeAddr, caller) - if offset.Cmp(big.NewInt(0)) < 0 { + node := g.state.Node(offset) + + // Can not withdraw if there are unpaied fine. + if node.Fined.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() + // Can not withdraw if there are no pending withdrawal. + if node.Unstaked.Cmp(big.NewInt(0)) == 0 { + return nil, errExecutionReverted } - unlockTime := new(big.Int).Add(delegator.UndelegatedAt, g.state.LockupPeriod()) + unlockTime := new(big.Int).Add(node.UnstakedAt, 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.Owner, delegator.Value) + amount := node.Unstaked + node.Unstaked = big.NewInt(0) + node.UnstakedAt = big.NewInt(0) + g.state.UpdateNode(offset, node) - // We are the last delegator to withdraw the fund, remove the node info. - if g.state.LenDelegators(nodeAddr).Cmp(big.NewInt(0)) == 0 { + if node.Staked.Cmp(big.NewInt(0)) == 0 { length := g.state.LenNodes() lastIndex := new(big.Int).Sub(length, big.NewInt(1)) @@ -1670,55 +1553,26 @@ func (g *GovernanceContract) withdraw(nodeAddr common.Address) ([]byte, error) { panic(err) } } - g.state.DeleteNodesOffsetByAddress(nodeAddr) + g.state.DeleteNodeOffsets(node) g.state.PopLastNode() - g.state.emitNodeRemoved(nodeAddr) + g.state.emitNodeRemoved(caller) } - 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 the staked fund. + if !g.transfer(GovernanceContractAddress, node.Owner, amount) { 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) + g.state.emitWithdrawn(caller, amount) 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 @@ -2017,22 +1871,6 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re 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 { @@ -2072,7 +1910,7 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re return nil, errExecutionReverted } return g.resetDKG(args.NewSignedCRS) - case "stake": + case "register": args := struct { PublicKey []byte Name string @@ -2083,21 +1921,21 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re 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) + 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 "undelegate": - address := common.Address{} - if err := method.Inputs.Unpack(&address, arguments); err != nil { + case "unstake": + amount := new(big.Int) + if err := method.Inputs.Unpack(&amount, arguments); err != nil { return nil, errExecutionReverted } - return g.undelegate(address) - case "unstake": - return g.unstake() + return g.unstake(amount) case "updateConfiguration": var cfg rawConfigStruct if err := method.Inputs.Unpack(&cfg, arguments); err != nil { @@ -2105,11 +1943,7 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re } 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) + return g.withdraw() // -------------------------------- // Solidity auto generated methods. @@ -2133,29 +1967,6 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re 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": index := new(big.Int) if err := method.Inputs.Unpack(&index, arguments); err != nil { @@ -2328,7 +2139,8 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re 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.Name, info.Email, info.Location, info.Url, + info.Unstaked, info.UnstakedAt) if err != nil { return nil, errExecutionReverted } @@ -2525,72 +2337,3 @@ func PackResetDKG(newSignedCRS []byte) ([]byte, error) { data := append(method.Id(), res...) return data, nil } - -// NodeInfoOracleContract representing a oracle providing the node information. -type NodeInfoOracleContract struct { -} - -func (g *NodeInfoOracleContract) Run(evm *EVM, input []byte, contract *Contract) (ret []byte, err error) { - if len(input) < 4 { - return nil, errExecutionReverted - } - - // Parse input. - method, exists := NodeInfoOracleABI.Sig2Method[string(input[:4])] - if !exists { - return nil, errExecutionReverted - } - - arguments := input[4:] - - // Dispatch method call. - switch method.Name { - case "delegators": - round, nodeAddr, index := new(big.Int), common.Address{}, new(big.Int) - args := []interface{}{&round, &nodeAddr, &index} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - state, err := getConfigState(evm, round) - if err != nil { - return nil, err - } - delegator := state.Delegator(nodeAddr, index) - res, err := method.Outputs.Pack(delegator.Owner, delegator.Value, delegator.UndelegatedAt) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "delegatorsLength": - round, address := new(big.Int), common.Address{} - args := []interface{}{&round, &address} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - state, err := getConfigState(evm, round) - if err != nil { - return nil, err - } - res, err := method.Outputs.Pack(state.LenDelegators(address)) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - case "delegatorsOffset": - round, nodeAddr, delegatorAddr := new(big.Int), common.Address{}, common.Address{} - args := []interface{}{&round, &nodeAddr, &delegatorAddr} - if err := method.Inputs.Unpack(&args, arguments); err != nil { - return nil, errExecutionReverted - } - state, err := getConfigState(evm, round) - if err != nil { - return nil, err - } - res, err := method.Outputs.Pack(state.DelegatorsOffset(nodeAddr, delegatorAddr)) - if err != nil { - return nil, errExecutionReverted - } - return res, nil - } - return nil, errExecutionReverted -} diff --git a/core/vm/oracle_contracts_test.go b/core/vm/oracle_contracts_test.go index 81afe810c..f8f327a68 100644 --- a/core/vm/oracle_contracts_test.go +++ b/core/vm/oracle_contracts_test.go @@ -235,20 +235,20 @@ func (g *OracleContractsTestSuite) TestTransferOwnership() { g.Require().Equal(addr, g.s.Owner()) } -func (g *OracleContractsTestSuite) TestStakeUnstakeWithoutExtraDelegators() { +func (g *OracleContractsTestSuite) TestStakingMechanism() { privKey, addr := g.newPrefundAccount() pk := crypto.FromECDSAPub(&privKey.PublicKey) - // Stake. - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)) + // 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("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + 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(1, len(g.s.QualifiedNodes())) + 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()) @@ -256,40 +256,75 @@ func (g *OracleContractsTestSuite) TestStakeUnstakeWithoutExtraDelegators() { 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. + // Registering again should fail. _, err = g.call(GovernanceContractAddress, addr, input, amount) - g.Require().NotNil(err) + 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") + 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(1, int(g.s.LenDelegators(addr).Uint64())) - g.Require().Equal(1, int(g.s.LenNodes().Uint64())) + g.Require().Equal(amount.String(), g.s.TotalStaked().String()) - 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()) + // Withdraw immediately should fail. + 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. time.Sleep(time.Second * 2) - input, err = GovernanceABI.ABI.Pack("withdraw", addr) + 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("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.LenDelegators(addr).Uint64())) 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 := g.newPrefundAccount() pk2 := crypto.FromECDSAPub(&privKey2.PublicKey) - input, err = GovernanceABI.ABI.Pack("stake", pk2, "Test2", "test2@dexon.org", "Taipei, Taiwan", "https://dexon.org") + 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) @@ -297,19 +332,21 @@ func (g *OracleContractsTestSuite) TestStakeUnstakeWithoutExtraDelegators() { g.Require().Equal(0, int(g.s.NodesOffsetByAddress(addr2).Int64())) // 1st node Stake. - input, err = GovernanceABI.ABI.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + 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") + 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()) @@ -317,18 +354,18 @@ func (g *OracleContractsTestSuite) TestStakeUnstakeWithoutExtraDelegators() { g.Require().Equal(amount.String(), g.s.TotalStaked().String()) time.Sleep(time.Second * 2) - input, err = GovernanceABI.ABI.Pack("withdraw", addr2) + 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, 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") + input, err = GovernanceABI.ABI.Pack("unstake", amount) g.Require().NoError(err) _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) @@ -336,14 +373,13 @@ func (g *OracleContractsTestSuite) TestStakeUnstakeWithoutExtraDelegators() { g.Require().Equal(big.NewInt(0).String(), g.s.TotalStaked().String()) time.Sleep(time.Second * 2) - input, err = GovernanceABI.ABI.Pack("withdraw", addr) + 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())) - g.Require().Equal(-1, int(g.s.DelegatorsOffset(addr, addr).Int64())) // Check balance. g.Require().Equal(balanceBeforeStake, g.stateDB.GetBalance(addr)) @@ -351,178 +387,26 @@ func (g *OracleContractsTestSuite) TestStakeUnstakeWithoutExtraDelegators() { g.Require().Equal(big.NewInt(1), g.stateDB.GetBalance(GovernanceContractAddress)) } -func (g *OracleContractsTestSuite) TestDelegateUndelegate() { - privKey, addr := g.newPrefundAccount() - pk := crypto.FromECDSAPub(&privKey.PublicKey) - - // Stake. - input, err := GovernanceABI.ABI.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - ownerStaked := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - _, err = g.call(GovernanceContractAddress, addr, input, ownerStaked) - g.Require().NoError(err) - g.Require().Equal(0, len(g.s.QualifiedNodes())) - g.Require().Equal(addr, g.s.Delegator(addr, big.NewInt(0)).Owner) - g.Require().Equal(ownerStaked, g.s.Node(big.NewInt(0)).Staked) - - // 1st delegator delegate to 1st node. - _, addrDelegator := g.newPrefundAccount() - - balanceBeforeDelegate := g.stateDB.GetBalance(addrDelegator) - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3e5)) - input, err = GovernanceABI.ABI.Pack("delegate", addr) - g.Require().NoError(err) - - _, err = g.call(GovernanceContractAddress, addrDelegator, input, amount) - g.Require().NoError(err) - g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator)) - g.Require().Equal(addrDelegator, g.s.Delegator(addr, big.NewInt(1)).Owner) - g.Require().Equal(new(big.Int).Add(amount, ownerStaked), g.s.Node(big.NewInt(0)).Staked) - g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String()) - g.Require().Equal(1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64())) - - // Same person delegate the 2nd time should fail. - _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(1e18)) - g.Require().NotNil(err) - - // Not yet qualified. - g.Require().Equal(0, len(g.s.QualifiedNodes())) - - // 2nd delegator delegate to 1st node. - _, addrDelegator2 := g.newPrefundAccount() - _, err = g.call(GovernanceContractAddress, addrDelegator2, input, amount) - g.Require().NoError(err) - g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator2)) - g.Require().Equal(addrDelegator2, g.s.Delegator(addr, big.NewInt(2)).Owner) - g.Require().Equal(new(big.Int).Add(ownerStaked, new(big.Int).Mul(amount, big.NewInt(2))), - g.s.Node(big.NewInt(0)).Staked) - g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String()) - g.Require().Equal(2, int(g.s.DelegatorsOffset(addr, addrDelegator2).Int64())) - - // Qualified. - g.Require().Equal(1, len(g.s.QualifiedNodes())) - - // Undelegate addrDelegator. - balanceBeforeUnDelegate := g.stateDB.GetBalance(addrDelegator) - input, err = GovernanceABI.ABI.Pack("undelegate", addr) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) - g.Require().Equal(new(big.Int).Add(amount, ownerStaked), g.s.Node(big.NewInt(0)).Staked) - g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String()) - g.Require().NoError(err) - - // Undelegate the second time should fail. - _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) - g.Require().Error(err) - - // Withdraw within lockup time should fail. - input, err = GovernanceABI.ABI.Pack("withdraw", addr) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) - g.Require().NotNil(err) - - g.Require().Equal(3, int(g.s.LenDelegators(addr).Uint64())) - g.Require().Equal(balanceBeforeUnDelegate, g.stateDB.GetBalance(addrDelegator)) - g.Require().NotEqual(-1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64())) - - // Wait for lockup time than withdraw. - time.Sleep(time.Second * 2) - input, err = GovernanceABI.ABI.Pack("withdraw", addr) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) - g.Require().NoError(err) - - g.Require().Equal(2, int(g.s.LenDelegators(addr).Uint64())) - g.Require().Equal(new(big.Int).Add(balanceBeforeUnDelegate, amount), g.stateDB.GetBalance(addrDelegator)) - g.Require().Equal(-1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64())) - - // Withdraw when their is no delegation should fail. - time.Sleep(time.Second) - input, err = GovernanceABI.ABI.Pack("withdraw", addr) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) - g.Require().Error(err) - - // Undelegate addrDelegator2. - balanceBeforeUnDelegate = g.stateDB.GetBalance(addrDelegator2) - input, err = GovernanceABI.ABI.Pack("undelegate", addr) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addrDelegator2, input, big.NewInt(0)) - g.Require().NoError(err) - - g.Require().Equal(ownerStaked, g.s.Node(big.NewInt(0)).Staked) - g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String()) - - // Wait for lockup time than withdraw. - time.Sleep(time.Second * 2) - input, err = GovernanceABI.ABI.Pack("withdraw", addr) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addrDelegator2, input, big.NewInt(0)) - g.Require().NoError(err) - - g.Require().Equal(1, int(g.s.LenDelegators(addr).Uint64())) - g.Require().Equal(new(big.Int).Add(balanceBeforeUnDelegate, amount), g.stateDB.GetBalance(addrDelegator2)) - g.Require().Equal(-1, int(g.s.DelegatorsOffset(addr, addrDelegator2).Int64())) - - // Unqualified - g.Require().Equal(0, len(g.s.QualifiedNodes())) - - // Owner undelegate itself. - g.Require().Equal(1, int(g.s.LenNodes().Uint64())) - g.Require().Equal(1, int(g.s.LenDelegators(addr).Uint64())) - - input, err = GovernanceABI.ABI.Pack("undelegate", addr) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - g.Require().Equal(big.NewInt(0).String(), g.s.Node(big.NewInt(0)).Staked.String()) - g.Require().Equal(big.NewInt(0).String(), g.s.TotalStaked().String()) - - time.Sleep(time.Second * 2) - input, err = GovernanceABI.ABI.Pack("withdraw", addr) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - - g.Require().Equal(0, int(g.s.LenNodes().Uint64())) - g.Require().Equal(0, int(g.s.LenDelegators(addr).Uint64())) -} - func (g *OracleContractsTestSuite) TestFine() { privKey, addr := g.newPrefundAccount() pk := crypto.FromECDSAPub(&privKey.PublicKey) // Stake. - input, err := GovernanceABI.ABI.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + 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(5e5)) + 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(0, len(g.s.QualifiedNodes())) - g.Require().Equal(addr, g.s.Delegator(addr, big.NewInt(0)).Owner) + g.Require().Equal(1, len(g.s.QualifiedNodes())) 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) + _, finePayer := g.newPrefundAccount() amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - input, err = GovernanceABI.ABI.Pack("delegate", addr) - g.Require().NoError(err) - - _, err = g.call(GovernanceContractAddress, addrDelegator, input, amount) - g.Require().NoError(err) - g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator)) - g.Require().Equal(addrDelegator, g.s.Delegator(addr, big.NewInt(1)).Owner) - g.Require().Equal(new(big.Int).Add(amount, ownerStaked), g.s.Node(big.NewInt(0)).Staked) - g.Require().Equal(1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64())) - - // Qualified. - g.Require().Equal(1, len(g.s.QualifiedNodes())) // Paying to node without fine should fail. input, err = GovernanceABI.ABI.Pack("payFine", addr) g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addrDelegator, input, amount) + _, err = g.call(GovernanceContractAddress, finePayer, input, amount) g.Require().NotNil(err) // Fined. @@ -537,106 +421,27 @@ func (g *OracleContractsTestSuite) TestFine() { // Not qualified after fined. g.Require().Equal(0, len(g.s.QualifiedNodes())) - // Cannot undelegate before fines are paied. - input, err = GovernanceABI.ABI.Pack("undelegate", addr) + // Cannot unstake before fines are paied. + input, err = GovernanceABI.ABI.Pack("unstake", big.NewInt(10)) g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) - g.Require().NotNil(err) - - // Only delegators can pay fine. - _, addrDelegator2 := g.newPrefundAccount() - input, err = GovernanceABI.ABI.Pack("payFine", addr) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addrDelegator2, input, big.NewInt(5e5)) + _, 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, addrDelegator, input, payAmount) + _, 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, addrDelegator, input, amount) + _, err = g.call(GovernanceContractAddress, finePayer, input, amount) g.Require().NoError(err) // Qualified. g.Require().Equal(1, len(g.s.QualifiedNodes())) - - // Can undelegate after all fines are paied. - input, err = GovernanceABI.ABI.Pack("undelegate", addr) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) - g.Require().NoError(err) -} - -func (g *OracleContractsTestSuite) TestUnstakeWithExtraDelegators() { - privKey, addr := g.newPrefundAccount() - pk := crypto.FromECDSAPub(&privKey.PublicKey) - - // Stake. - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - input, err := GovernanceABI.ABI.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, amount) - g.Require().NoError(err) - - // 1st delegator delegate to 1st node. - _, addrDelegator := g.newPrefundAccount() - - balanceBeforeDelegate := g.stateDB.GetBalance(addrDelegator) - amount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3e5)) - input, err = GovernanceABI.ABI.Pack("delegate", addr) - g.Require().NoError(err) - - _, err = g.call(GovernanceContractAddress, addrDelegator, input, amount) - g.Require().NoError(err) - g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator)) - g.Require().Equal(addrDelegator, g.s.Delegator(addr, big.NewInt(1)).Owner) - g.Require().Equal(0, len(g.s.QualifiedNodes())) - - // 2st delegator delegate to 1st node. - _, addrDelegator2 := g.newPrefundAccount() - - balanceBeforeDelegate = g.stateDB.GetBalance(addrDelegator2) - input, err = GovernanceABI.ABI.Pack("delegate", addr) - g.Require().NoError(err) - - _, err = g.call(GovernanceContractAddress, addrDelegator2, input, amount) - g.Require().NoError(err) - g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator2)) - g.Require().Equal(addrDelegator2, g.s.Delegator(addr, big.NewInt(2)).Owner) - - // Node is now qualified. - g.Require().Equal(1, len(g.s.QualifiedNodes())) - - // Unstake. - input, err = GovernanceABI.ABI.Pack("unstake") - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - - time.Sleep(time.Second * 2) - input, err = GovernanceABI.ABI.Pack("withdraw", addr) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addrDelegator, input, big.NewInt(0)) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addrDelegator2, input, big.NewInt(0)) - g.Require().NoError(err) - - g.Require().Equal(0, int(g.s.LenDelegators(addr).Uint64())) - g.Require().Equal(0, int(g.s.LenNodes().Uint64())) - - // Check balance. - g.Require().Equal(balanceBeforeDelegate, g.stateDB.GetBalance(addr)) - g.Require().Equal(balanceBeforeDelegate, g.stateDB.GetBalance(addrDelegator)) - g.Require().Equal(balanceBeforeDelegate, g.stateDB.GetBalance(addrDelegator2)) - g.Require().Equal(big.NewInt(1), g.stateDB.GetBalance(GovernanceContractAddress)) } func (g *OracleContractsTestSuite) TestUpdateConfiguration() { @@ -805,7 +610,7 @@ func (g *OracleContractsTestSuite) TestReportForkVote() { // Stake. amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - input, err := GovernanceABI.ABI.Pack("stake", pkBytes, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + 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) @@ -871,7 +676,7 @@ func (g *OracleContractsTestSuite) TestReportForkBlock() { // Stake. amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - input, err := GovernanceABI.ABI.Pack("stake", pkBytes, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + 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) @@ -958,26 +763,11 @@ func (g *OracleContractsTestSuite) TestMiscVariableReading() { // Stake. amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - input, err = GovernanceABI.ABI.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + 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) - // 1st delegator delegate to 1st node. - _, addrDelegator := g.newPrefundAccount() - amount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3e5)) - input, err = GovernanceABI.ABI.Pack("delegate", addr) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addrDelegator, input, amount) - g.Require().NoError(err) - - // 2st delegator delegate to 1st node. - _, addrDelegator2 := g.newPrefundAccount() - input, err = GovernanceABI.ABI.Pack("delegate", addr) - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addrDelegator2, input, amount) - g.Require().NoError(err) - input, err = GovernanceABI.ABI.Pack("nodes", big.NewInt(0)) g.Require().NoError(err) res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) @@ -1010,27 +800,6 @@ func (g *OracleContractsTestSuite) TestMiscVariableReading() { g.Require().NoError(err) g.Require().Equal(0, int(value.Uint64())) - input, err = GovernanceABI.ABI.Pack("delegators", addr, big.NewInt(0)) - g.Require().NoError(err) - res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - - input, err = GovernanceABI.ABI.Pack("delegatorsLength", addr) - g.Require().NoError(err) - res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = GovernanceABI.ABI.Unpack(&value, "delegatorsLength", res) - g.Require().NoError(err) - g.Require().Equal(3, int(value.Uint64())) - - input, err = GovernanceABI.ABI.Pack("delegatorsOffset", addr, addrDelegator2) - g.Require().NoError(err) - res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = GovernanceABI.ABI.Unpack(&value, "delegatorsOffset", res) - g.Require().NoError(err) - g.Require().Equal(2, int(value.Uint64())) - input, err = GovernanceABI.ABI.Pack("fineValues", big.NewInt(0)) g.Require().NoError(err) res, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) @@ -1053,47 +822,6 @@ func (g *OracleContractsTestSuite) TestHalvingCondition() { g.s.LastHalvedAmount().String()) } -func (g *OracleContractsTestSuite) TestNodeInfoOracleContract() { - privKey, addr := g.newPrefundAccount() - pk := crypto.FromECDSAPub(&privKey.PublicKey) - - // Stake. - amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) - input, err := GovernanceABI.ABI.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") - g.Require().NoError(err) - _, err = g.call(GovernanceContractAddress, addr, input, amount) - g.Require().NoError(err) - - // Invalid round. - input, err = NodeInfoOracleABI.ABI.Pack("delegators", big.NewInt(100), addr, big.NewInt(0)) - g.Require().NoError(err) - res, err := g.call(NodeInfoOracleAddress, addr, input, big.NewInt(0)) - g.Require().Error(err) - - round := big.NewInt(0) - input, err = NodeInfoOracleABI.ABI.Pack("delegators", round, addr, big.NewInt(0)) - g.Require().NoError(err) - res, err = g.call(NodeInfoOracleAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - - var value *big.Int - input, err = NodeInfoOracleABI.ABI.Pack("delegatorsLength", round, addr) - g.Require().NoError(err) - res, err = g.call(NodeInfoOracleAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = NodeInfoOracleABI.ABI.Unpack(&value, "delegatorsLength", res) - g.Require().NoError(err) - g.Require().Equal(1, int(value.Uint64())) - - input, err = NodeInfoOracleABI.ABI.Pack("delegatorsOffset", round, addr, addr) - g.Require().NoError(err) - res, err = g.call(NodeInfoOracleAddress, addr, input, big.NewInt(0)) - g.Require().NoError(err) - err = NodeInfoOracleABI.ABI.Unpack(&value, "delegatorsOffset", res) - g.Require().NoError(err) - g.Require().Equal(0, int(value.Uint64())) -} - type testCoreMock struct { newDKGGPKError error tsigReturn bool @@ -1123,8 +851,7 @@ func (g *OracleContractsTestSuite) TestResetDKG() { // Stake. amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)) - input, err := GovernanceABI.ABI.Pack("stake", pk, "Test1", - "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + 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) @@ -1270,6 +997,6 @@ func (g *OracleContractsTestSuite) TestResetDKG() { } } -func TestGovernanceContract(t *testing.T) { +func TestOracleContracts(t *testing.T) { suite.Run(t, new(OracleContractsTestSuite)) } |