aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWei-Ning Huang <w@dexon.org>2019-01-13 00:13:49 +0800
committerWei-Ning Huang <w@byzantine-lab.io>2019-06-12 17:27:21 +0800
commitf82a81c6fa36c8ee6ba6a55e0662930c8f0d2658 (patch)
tree72561d414bcef69d2114578fc1b1d87a428df3a8
parent77fc30443842b1e62311c35b1bdd729fa51d005c (diff)
downloadgo-tangerine-f82a81c6fa36c8ee6ba6a55e0662930c8f0d2658.tar.gz
go-tangerine-f82a81c6fa36c8ee6ba6a55e0662930c8f0d2658.tar.zst
go-tangerine-f82a81c6fa36c8ee6ba6a55e0662930c8f0d2658.zip
core: vm: add totalSupply and totalStaked in the governance contract (#144)
Add totalSupply and totalStaked in the governance contract for the preperation of DEXON cryptoeconomics 4.0. Also removed the unstaked variable in node info and improve tests for delegate/undeleate.
-rw-r--r--core/genesis.go6
-rw-r--r--core/vm/governance.go79
-rw-r--r--core/vm/governance_abi.go32
-rw-r--r--core/vm/governance_test.go62
-rw-r--r--params/config.go4
5 files changed, 146 insertions, 37 deletions
diff --git a/core/genesis.go b/core/genesis.go
index 38216361f..0948569f1 100644
--- a/core/genesis.go
+++ b/core/genesis.go
@@ -265,6 +265,7 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
govStateHelper := vm.GovernanceStateHelper{StateDB: statedb}
+ totalSupply := big.NewInt(0)
totalStaked := big.NewInt(0)
for addr, account := range g.Alloc {
@@ -281,6 +282,8 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
for key, value := range account.Storage {
statedb.SetState(addr, key, value)
}
+
+ totalSupply = new(big.Int).Add(totalSupply, account.Balance)
}
// For DEXON consensus genesis staking.
@@ -316,6 +319,9 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
// Governance configuration.
govStateHelper.UpdateConfiguration(g.Config.Dexcon)
+
+ // Set totalSupply.
+ govStateHelper.IncTotalSupply(totalSupply)
}
root := statedb.IntermediateRoot(false)
diff --git a/core/vm/governance.go b/core/vm/governance.go
index b8228944a..bebc26e03 100644
--- a/core/vm/governance.go
+++ b/core/vm/governance.go
@@ -438,7 +438,7 @@ func RunGovernanceContract(evm *EVM, input []byte, contract *Contract) (ret []by
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.Unstaked)
+ info.Name, info.Email, info.Location, info.Url)
if err != nil {
return nil, errExecutionReverted
}
@@ -497,13 +497,27 @@ func RunGovernanceContract(evm *EVM, input []byte, contract *Contract) (ret []by
return nil, errExecutionReverted
}
return res, nil
+ case "totalStaked":
+ res, err := method.Outputs.Pack(g.state.TotalStaked())
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
+ case "totalSupply":
+ res, err := method.Outputs.Pack(g.state.TotalSupply())
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+ return res, nil
}
- return nil, nil
+ return nil, errExecutionReverted
}
// Storage position enums.
const (
roundHeightLoc = iota
+ totalSupplyLoc
+ totalStakedLoc
nodesLoc
nodesOffsetByAddressLoc
nodesOffsetByIDLoc
@@ -702,6 +716,28 @@ func (s *GovernanceStateHelper) PushRoundHeight(height *big.Int) {
s.setStateBigInt(loc, height)
}
+// uint256 public totalSupply;
+func (s *GovernanceStateHelper) TotalSupply() *big.Int {
+ return s.getStateBigInt(big.NewInt(totalSupplyLoc))
+}
+func (s *GovernanceStateHelper) IncTotalSupply(amount *big.Int) {
+ s.setStateBigInt(big.NewInt(totalSupplyLoc), new(big.Int).Add(s.TotalSupply(), amount))
+}
+func (s *GovernanceStateHelper) DecTotalSupply(amount *big.Int) {
+ s.setStateBigInt(big.NewInt(totalSupplyLoc), new(big.Int).Sub(s.TotalSupply(), amount))
+}
+
+// uint256 public totalStaked;
+func (s *GovernanceStateHelper) TotalStaked() *big.Int {
+ return s.getStateBigInt(big.NewInt(totalStakedLoc))
+}
+func (s *GovernanceStateHelper) IncTotalStaked(amount *big.Int) {
+ s.setStateBigInt(big.NewInt(totalStakedLoc), new(big.Int).Add(s.TotalStaked(), amount))
+}
+func (s *GovernanceStateHelper) DecTotalStaked(amount *big.Int) {
+ s.setStateBigInt(big.NewInt(totalStakedLoc), new(big.Int).Sub(s.TotalStaked(), amount))
+}
+
// struct Node {
// address owner;
// bytes publicKey;
@@ -711,7 +747,6 @@ func (s *GovernanceStateHelper) PushRoundHeight(height *big.Int) {
// string email;
// string location;
// string url;
-// bool unstaked;
// }
//
// Node[] nodes;
@@ -725,10 +760,9 @@ type nodeInfo struct {
Email string
Location string
Url string
- Unstaked bool
}
-const nodeStructSize = 9
+const nodeStructSize = 8
func (s *GovernanceStateHelper) LenNodes() *big.Int {
return s.getStateBigInt(big.NewInt(nodesLoc))
@@ -772,10 +806,6 @@ func (s *GovernanceStateHelper) 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).Cmp(big.NewInt(0)) > 0
-
return node
}
func (s *GovernanceStateHelper) PushNode(n *nodeInfo) {
@@ -787,7 +817,8 @@ func (s *GovernanceStateHelper) PushNode(n *nodeInfo) {
}
func (s *GovernanceStateHelper) UpdateNode(index *big.Int, n *nodeInfo) {
arrayBaseLoc := s.getSlotLoc(big.NewInt(nodesLoc))
- elementBaseLoc := new(big.Int).Add(arrayBaseLoc, new(big.Int).Mul(index, big.NewInt(nodeStructSize)))
+ elementBaseLoc := new(big.Int).Add(arrayBaseLoc,
+ new(big.Int).Mul(index, big.NewInt(nodeStructSize)))
// Owner.
loc := elementBaseLoc
@@ -820,14 +851,6 @@ func (s *GovernanceStateHelper) 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))
- val := big.NewInt(0)
- if n.Unstaked {
- val = big.NewInt(1)
- }
- s.setStateBigInt(loc, val)
}
func (s *GovernanceStateHelper) PopLastNode() {
// Decrease length by 1.
@@ -851,9 +874,6 @@ func (s *GovernanceStateHelper) QualifiedNodes() []*nodeInfo {
var nodes []*nodeInfo
for i := int64(0); i < int64(s.LenNodes().Uint64()); i++ {
node := s.Node(big.NewInt(i))
- if node.Unstaked {
- continue
- }
if new(big.Int).Sub(node.Staked, node.Fined).Cmp(s.MinStake()) >= 0 {
nodes = append(nodes, node)
}
@@ -1265,6 +1285,9 @@ func (s *GovernanceStateHelper) Stake(
UndelegatedAt: big.NewInt(0),
})
s.PutDelegatorOffset(addr, addr, offset)
+
+ // Add to network total staked.
+ s.IncTotalStaked(staked)
}
const phiRatioMultiplier = 1000000.0
@@ -1725,6 +1748,9 @@ func (g *GovernanceContract) delegate(nodeAddr common.Address) ([]byte, error) {
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{
@@ -1810,6 +1836,10 @@ func (g *GovernanceContract) undelegateHelper(nodeAddr, caller common.Address) (
delegator := g.state.Delegator(nodeAddr, offset)
+ if delegator.UndelegatedAt.Cmp(big.NewInt(0)) != 0 {
+ return nil, errExecutionReverted
+ }
+
// Set undelegate time.
delegator.UndelegatedAt = g.evm.Time
g.state.UpdateDelegator(nodeAddr, offset, delegator)
@@ -1818,6 +1848,9 @@ func (g *GovernanceContract) undelegateHelper(nodeAddr, caller common.Address) (
node.Staked = new(big.Int).Sub(node.Staked, delegator.Value)
g.state.UpdateNode(nodeOffset, node)
+ // Subtract to network total staked.
+ g.state.DecTotalStaked(delegator.Value)
+
g.state.emitUndelegated(nodeAddr, caller)
return g.useGas(100000)
@@ -1914,10 +1947,6 @@ func (g *GovernanceContract) unstake() ([]byte, error) {
i = i.Sub(i, big.NewInt(1))
}
- // Mark node as unstaked.
- node.Unstaked = true
- g.state.UpdateNode(offset, node)
-
g.state.emitUnstaked(caller)
return g.useGas(100000)
diff --git a/core/vm/governance_abi.go b/core/vm/governance_abi.go
index 74ccad0b7..1b700ac32 100644
--- a/core/vm/governance_abi.go
+++ b/core/vm/governance_abi.go
@@ -112,6 +112,20 @@ const GovernanceABIJSON = `
},
{
"constant": true,
+ "inputs": [],
+ "name": "totalSupply",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
"inputs": [
{
"name": "",
@@ -151,10 +165,6 @@ const GovernanceABIJSON = `
{
"name": "url",
"type": "string"
- },
- {
- "name": "unstaked",
- "type": "bool"
}
],
"payable": false,
@@ -331,6 +341,20 @@ const GovernanceABIJSON = `
{
"constant": true,
"inputs": [],
+ "name": "totalStaked",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
"name": "roundInterval",
"outputs": [
{
diff --git a/core/vm/governance_test.go b/core/vm/governance_test.go
index 4c5236565..8566d6537 100644
--- a/core/vm/governance_test.go
+++ b/core/vm/governance_test.go
@@ -205,6 +205,7 @@ func (g *GovernanceContractTestSuite) TestStakeUnstakeWithoutExtraDelegators() {
g.Require().Equal(1, int(g.s.LenNodes().Uint64()))
g.Require().Equal(1, len(g.s.QualifiedNodes()))
g.Require().Equal("Test1", g.s.Node(big.NewInt(0)).Name)
+ g.Require().Equal(amount.String(), g.s.TotalStaked().String())
// Check balance.
g.Require().Equal(new(big.Int).Sub(balanceBeforeStake, amount), g.stateDB.GetBalance(addr))
@@ -219,9 +220,14 @@ func (g *GovernanceContractTestSuite) TestStakeUnstakeWithoutExtraDelegators() {
g.Require().NoError(err)
_, err = g.call(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()))
+ 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())
+
// Wait for lockup time than withdraw.
time.Sleep(time.Second * 2)
input, err = abiObject.Pack("withdraw", addr)
@@ -229,6 +235,7 @@ func (g *GovernanceContractTestSuite) TestStakeUnstakeWithoutExtraDelegators() {
_, err = g.call(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()))
@@ -251,16 +258,18 @@ func (g *GovernanceContractTestSuite) TestStakeUnstakeWithoutExtraDelegators() {
g.Require().NoError(err)
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 = abiObject.Pack("unstake")
g.Require().NoError(err)
_, err = g.call(addr2, input, big.NewInt(0))
g.Require().NoError(err)
- node := g.s.Node(big.NewInt(0))
+ node = g.s.Node(big.NewInt(0))
g.Require().Equal("Test2", node.Name)
- g.Require().Equal(true, node.Unstaked)
+ g.Require().Equal(big.NewInt(0).String(), node.Staked.String())
g.Require().Equal(1, len(g.s.QualifiedNodes()))
+ g.Require().Equal(amount.String(), g.s.TotalStaked().String())
time.Sleep(time.Second * 2)
input, err = abiObject.Pack("withdraw", addr2)
@@ -279,6 +288,8 @@ func (g *GovernanceContractTestSuite) TestStakeUnstakeWithoutExtraDelegators() {
_, err = g.call(addr, input, big.NewInt(0))
g.Require().NoError(err)
g.Require().Equal(0, len(g.s.QualifiedNodes()))
+ g.Require().Equal(big.NewInt(0).String(), g.s.TotalStaked().String())
+
time.Sleep(time.Second * 2)
input, err = abiObject.Pack("withdraw", addr)
g.Require().NoError(err)
@@ -322,6 +333,7 @@ func (g *GovernanceContractTestSuite) TestDelegateUndelegate() {
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.
@@ -339,6 +351,7 @@ func (g *GovernanceContractTestSuite) TestDelegateUndelegate() {
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.
@@ -349,8 +362,14 @@ func (g *GovernanceContractTestSuite) TestDelegateUndelegate() {
input, err = abiObject.Pack("undelegate", addr)
g.Require().NoError(err)
_, err = g.call(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(addrDelegator, input, big.NewInt(0))
+ g.Require().Error(err)
+
// Withdraw within lockup time should fail.
input, err = abiObject.Pack("withdraw", addr)
g.Require().NoError(err)
@@ -377,7 +396,7 @@ func (g *GovernanceContractTestSuite) TestDelegateUndelegate() {
input, err = abiObject.Pack("withdraw", addr)
g.Require().NoError(err)
_, err = g.call(addrDelegator, input, big.NewInt(0))
- g.Require().NotNil(err)
+ g.Require().Error(err)
// Undelegate addrDelegator2.
balanceBeforeUnDelegate = g.stateDB.GetBalance(addrDelegator2)
@@ -386,6 +405,9 @@ func (g *GovernanceContractTestSuite) TestDelegateUndelegate() {
_, err = g.call(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 = abiObject.Pack("withdraw", addr)
@@ -399,6 +421,25 @@ func (g *GovernanceContractTestSuite) TestDelegateUndelegate() {
// 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 = abiObject.Pack("undelegate", addr)
+ g.Require().NoError(err)
+ _, err = g.call(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 = abiObject.Pack("withdraw", addr)
+ g.Require().NoError(err)
+ _, err = g.call(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 *GovernanceContractTestSuite) TestFine() {
@@ -485,7 +526,6 @@ func (g *GovernanceContractTestSuite) TestFine() {
g.Require().NoError(err)
_, err = g.call(addrDelegator, input, big.NewInt(0))
g.Require().NoError(err)
-
}
func (g *GovernanceContractTestSuite) TestUnstakeWithExtraDelegators() {
@@ -893,9 +933,19 @@ func (g *GovernanceContractTestSuite) TestMiscVariableReading() {
privKey, addr := g.newPrefundAccount()
pk := crypto.FromECDSAPub(&privKey.PublicKey)
+ input, err := abiObject.Pack("totalSupply")
+ g.Require().NoError(err)
+ res, err := g.call(addr, input, big.NewInt(0))
+ g.Require().NoError(err)
+
+ input, err = abiObject.Pack("totalStaked")
+ g.Require().NoError(err)
+ res, err = g.call(addr, input, big.NewInt(0))
+ g.Require().NoError(err)
+
// Stake.
amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e4))
- input, err := abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org")
+ input, err = abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org")
g.Require().NoError(err)
_, err = g.call(addr, input, amount)
g.Require().NoError(err)
@@ -917,7 +967,7 @@ func (g *GovernanceContractTestSuite) TestMiscVariableReading() {
input, err = abiObject.Pack("nodes", big.NewInt(0))
g.Require().NoError(err)
- res, err := g.call(addr, input, big.NewInt(0))
+ res, err = g.call(addr, input, big.NewInt(0))
g.Require().NoError(err)
input, err = abiObject.Pack("nodesLength")
diff --git a/params/config.go b/params/config.go
index ca99049ba..c2d729c59 100644
--- a/params/config.go
+++ b/params/config.go
@@ -26,8 +26,8 @@ import (
// Genesis hashes to enforce below configs on.
var (
- MainnetGenesisHash = common.HexToHash("0x54db5d33dcdf4707594d8da66369006247ac6b62fe1ff8c94bf63bdeeda87a32")
- TestnetGenesisHash = common.HexToHash("0xbf52fff3a803757e4347a01f1f04f3db59dd672b316eac9e1230b1776567e06a")
+ MainnetGenesisHash = common.HexToHash("0x4310c4984de8bf7ac1c509232d21511fae2cd73e8a1bb8365fe4e489042bc407")
+ TestnetGenesisHash = common.HexToHash("0x1fdd7ca7ccdd7c3a481f4162b8ca02a4db03859b4abaed96f7e259266d818a13")
)
// TrustedCheckpoints associates each known checkpoint with the genesis hash of