aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJimmy Hu <jimmy.hu@dexon.org>2019-04-18 14:14:54 +0800
committerWei-Ning Huang <w@byzantine-lab.io>2019-06-15 22:09:56 +0800
commita1be735b1cd6d02bc69b9bb011c56e62cec290f5 (patch)
tree156d7712033a6e6e0670cbde41900a4ff29569da
parentbb1f7208f1ece943c24e393555e0396d4ef2e7ee (diff)
downloadgo-tangerine-a1be735b1cd6d02bc69b9bb011c56e62cec290f5.tar.gz
go-tangerine-a1be735b1cd6d02bc69b9bb011c56e62cec290f5.tar.zst
go-tangerine-a1be735b1cd6d02bc69b9bb011c56e62cec290f5.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 b47f99ee0..899128493 100644
--- a/core/vm/oracle_contracts.go
+++ b/core/vm/oracle_contracts.go
@@ -1827,6 +1827,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)
@@ -1836,21 +1839,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)
@@ -1880,6 +1868,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 {
@@ -2290,6 +2302,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 7c935913a..a7680b69e 100644
--- a/core/vm/oracle_contracts_test.go
+++ b/core/vm/oracle_contracts_test.go
@@ -411,13 +411,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)
@@ -434,6 +447,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))