aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJimmy Hu <jimmy.hu@dexon.org>2019-04-18 14:14:54 +0800
committerGitHub <noreply@github.com>2019-04-18 14:14:54 +0800
commit9abba1d1a25b47a21666b6abfc30a3ce4ff88ed6 (patch)
tree8d7d882d3188d49122af71337b793f87de3d3d31
parentc8f482bbd870afff38397dac52cd8d396ca65fdb (diff)
downloaddexon-9abba1d1a25b47a21666b6abfc30a3ce4ff88ed6.tar.gz
dexon-9abba1d1a25b47a21666b6abfc30a3ce4ff88ed6.tar.zst
dexon-9abba1d1a25b47a21666b6abfc30a3ce4ff88ed6.zip
core: vm: add withdrawable (#373)
-rw-r--r--core/vm/oracle_contract_abi.go14
-rw-r--r--core/vm/oracle_contracts.go48
-rw-r--r--core/vm/oracle_contracts_test.go19
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))