diff options
author | Jimmy Hu <jimmy.hu@dexon.org> | 2019-04-18 14:14:54 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-18 14:14:54 +0800 |
commit | 9abba1d1a25b47a21666b6abfc30a3ce4ff88ed6 (patch) | |
tree | 8d7d882d3188d49122af71337b793f87de3d3d31 | |
parent | c8f482bbd870afff38397dac52cd8d396ca65fdb (diff) | |
download | dexon-9abba1d1a25b47a21666b6abfc30a3ce4ff88ed6.tar.gz dexon-9abba1d1a25b47a21666b6abfc30a3ce4ff88ed6.tar.zst dexon-9abba1d1a25b47a21666b6abfc30a3ce4ff88ed6.zip |
core: vm: add withdrawable (#373)
-rw-r--r-- | core/vm/oracle_contract_abi.go | 14 | ||||
-rw-r--r-- | core/vm/oracle_contracts.go | 48 | ||||
-rw-r--r-- | core/vm/oracle_contracts_test.go | 19 |
3 files changed, 66 insertions, 15 deletions
diff --git a/core/vm/oracle_contract_abi.go b/core/vm/oracle_contract_abi.go index dc44552a2..35d0f16d1 100644 --- a/core/vm/oracle_contract_abi.go +++ b/core/vm/oracle_contract_abi.go @@ -1136,6 +1136,20 @@ const GovernanceABIJSON = ` "type": "function" }, { + "constant": true, + "inputs": [], + "name": "withdrawable", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { "constant": false, "inputs": [ { diff --git a/core/vm/oracle_contracts.go b/core/vm/oracle_contracts.go index 40ea86ac9..a6e283abe 100644 --- a/core/vm/oracle_contracts.go +++ b/core/vm/oracle_contracts.go @@ -1829,6 +1829,9 @@ func (g *GovernanceContract) unstake(amount *big.Int) ([]byte, error) { } func (g *GovernanceContract) withdraw() ([]byte, error) { + if !g.withdrawable() { + return nil, errExecutionReverted + } caller := g.contract.Caller() offset := g.state.NodesOffsetByAddress(caller) @@ -1838,21 +1841,6 @@ func (g *GovernanceContract) withdraw() ([]byte, error) { node := g.state.Node(offset) - // Can not withdraw if there are unpaied fine. - if node.Fined.Cmp(big.NewInt(0)) > 0 { - return nil, errExecutionReverted - } - - // 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(node.UnstakedAt, g.state.LockupPeriod()) - if g.evm.Time.Cmp(unlockTime) <= 0 { - return nil, errExecutionReverted - } - amount := node.Unstaked node.Unstaked = big.NewInt(0) node.UnstakedAt = big.NewInt(0) @@ -1882,6 +1870,30 @@ func (g *GovernanceContract) withdraw() ([]byte, error) { return g.useGas(GovernanceActionGasCost) } +func (g *GovernanceContract) withdrawable() bool { + caller := g.contract.Caller() + + offset := g.state.NodesOffsetByAddress(caller) + if offset.Cmp(big.NewInt(0)) < 0 { + return false + } + + node := g.state.Node(offset) + + // Can not withdraw if there are unpaied fine. + if node.Fined.Cmp(big.NewInt(0)) > 0 { + return false + } + + // Can not withdraw if there are no pending withdrawal. + if node.Unstaked.Cmp(big.NewInt(0)) == 0 { + return false + } + + unlockTime := new(big.Int).Add(node.UnstakedAt, g.state.LockupPeriod()) + return g.evm.Time.Cmp(unlockTime) > 0 +} + func (g *GovernanceContract) payFine(nodeAddr common.Address) ([]byte, error) { nodeOffset := g.state.NodesOffsetByAddress(nodeAddr) if nodeOffset.Cmp(big.NewInt(0)) < 0 { @@ -2292,6 +2304,12 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re return g.updateConfiguration(&cfg) case "withdraw": return g.withdraw() + case "withdrawable": + res, err := method.Outputs.Pack(g.withdrawable()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil // -------------------------------- // Solidity auto generated methods. diff --git a/core/vm/oracle_contracts_test.go b/core/vm/oracle_contracts_test.go index bdd407abd..15a519eba 100644 --- a/core/vm/oracle_contracts_test.go +++ b/core/vm/oracle_contracts_test.go @@ -412,13 +412,26 @@ func (g *OracleContractsTestSuite) TestStakingMechanism() { g.Require().Equal(0, len(g.s.QualifiedNodes())) g.Require().Equal(amount.String(), g.s.TotalStaked().String()) + var ok bool // Withdraw immediately should fail. + input, err = GovernanceABI.ABI.Pack("withdrawable") + g.Require().NoError(err) + output, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + GovernanceABI.ABI.Unpack(&ok, "withdrawable", output) + g.Require().False(ok) input, err = GovernanceABI.ABI.Pack("withdraw") g.Require().NoError(err) _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().Error(err) // Wait for lockup time than withdraw. + input, err = GovernanceABI.ABI.Pack("withdrawable") + g.Require().NoError(err) + output, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + GovernanceABI.ABI.Unpack(&ok, "withdrawable", output) + g.Require().False(ok) time.Sleep(time.Second * 2) input, err = GovernanceABI.ABI.Pack("withdraw") g.Require().NoError(err) @@ -435,6 +448,12 @@ func (g *OracleContractsTestSuite) TestStakingMechanism() { g.Require().NoError(err) time.Sleep(time.Second * 2) + input, err = GovernanceABI.ABI.Pack("withdrawable") + g.Require().NoError(err) + output, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) + g.Require().NoError(err) + GovernanceABI.ABI.Unpack(&ok, "withdrawable", output) + g.Require().True(ok) input, err = GovernanceABI.ABI.Pack("withdraw") g.Require().NoError(err) _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) |