aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm/governance.go
diff options
context:
space:
mode:
Diffstat (limited to 'core/vm/governance.go')
-rw-r--r--core/vm/governance.go695
1 files changed, 588 insertions, 107 deletions
diff --git a/core/vm/governance.go b/core/vm/governance.go
index b6a5038c5..36b37b53c 100644
--- a/core/vm/governance.go
+++ b/core/vm/governance.go
@@ -37,12 +37,34 @@ import (
)
var GovernanceContractAddress = common.HexToAddress("5765692d4e696e6720536f6e696320426f6a6965")
-var minStake = big.NewInt(10000000000000)
const GovernanceABIJSON = `
[
{
"constant": true,
+ "inputs": [
+ {
+ "name": "",
+ "type": "address"
+ },
+ {
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "delegatorsOffset",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
"inputs": [],
"name": "blockReward",
"outputs": [
@@ -216,12 +238,20 @@ const GovernanceABIJSON = `
{
"name": "",
"type": "address"
+ },
+ {
+ "name": "",
+ "type": "uint256"
}
],
- "name": "offset",
+ "name": "delegators",
"outputs": [
{
- "name": "",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "name": "value",
"type": "uint256"
}
],
@@ -273,6 +303,25 @@ const GovernanceABIJSON = `
},
{
"constant": true,
+ "inputs": [
+ {
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "nodesOffset",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
"inputs": [],
"name": "lambdaDKG",
"outputs": [
@@ -422,12 +471,12 @@ const GovernanceABIJSON = `
"inputs": [
{
"indexed": true,
- "name": "round",
+ "name": "Round",
"type": "uint256"
},
{
"indexed": false,
- "name": "crs",
+ "name": "CRS",
"type": "bytes32"
}
],
@@ -435,6 +484,69 @@ const GovernanceABIJSON = `
"type": "event"
},
{
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "NodeAddress",
+ "type": "address"
+ }
+ ],
+ "name": "Staked",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "NodeAddress",
+ "type": "address"
+ }
+ ],
+ "name": "Unstaked",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "NodeAddress",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "name": "DelegatorAddress",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "Amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "Delegated",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "NodeAddress",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "name": "DelegatorAddress",
+ "type": "address"
+ }
+ ],
+ "name": "Undelegated",
+ "type": "event"
+ },
+ {
"constant": false,
"inputs": [
{
@@ -507,6 +619,39 @@ const GovernanceABIJSON = `
"type": "function"
},
{
+ "constant": true,
+ "inputs": [],
+ "name": "nodesLength",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "NodeAddress",
+ "type": "address"
+ }
+ ],
+ "name": "delegatorsLength",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
"constant": false,
"inputs": [
{
@@ -636,17 +781,31 @@ const GovernanceABIJSON = `
"type": "function"
},
{
- "constant": true,
- "inputs": [],
- "name": "nodesLength",
- "outputs": [
+ "constant": false,
+ "inputs": [
{
- "name": "",
- "type": "uint256"
+ "name": "NodeAddress",
+ "type": "address"
}
],
+ "name": "delegate",
+ "outputs": [],
+ "payable": true,
+ "stateMutability": "payable",
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "NodeAddress",
+ "type": "address"
+ }
+ ],
+ "name": "undelegate",
+ "outputs": [],
"payable": false,
- "stateMutability": "view",
+ "stateMutability": "nonpayable",
"type": "function"
}
]
@@ -658,8 +817,10 @@ var sig2Method map[string]abi.Method
var events map[string]abi.Event
func init() {
+ var err error
+
// Parse governance contract ABI.
- abiObject, err := abi.JSON(strings.NewReader(GovernanceABIJSON))
+ abiObject, err = abi.JSON(strings.NewReader(GovernanceABIJSON))
if err != nil {
panic(err)
}
@@ -682,8 +843,7 @@ func init() {
}
// RunGovernanceContract executes governance contract.
-func RunGovernanceContract(evm *EVM, input []byte, contract *Contract) (
- ret []byte, err error) {
+func RunGovernanceContract(evm *EVM, input []byte, contract *Contract) (ret []byte, err error) {
if len(input) < 4 {
return nil, nil
}
@@ -726,8 +886,24 @@ func RunGovernanceContract(evm *EVM, input []byte, contract *Contract) (
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.NodesLength())
+ res, err := method.Outputs.Pack(g.state.LenNodes())
if err != nil {
return nil, errExecutionReverted
}
@@ -768,14 +944,20 @@ func RunGovernanceContract(evm *EVM, input []byte, contract *Contract) (
return nil, errExecutionReverted
}
return g.transferOwnership(newOwner)
+ case "undelegate":
+ address := common.Address{}
+ if err := method.Inputs.Unpack(&address, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ return g.undelegate(address)
case "unstake":
return g.unstake()
case "updateConfiguration":
- var cfg params.DexconConfig
+ var cfg rawConfigStruct
if err := method.Inputs.Unpack(&cfg, arguments); err != nil {
return nil, errExecutionReverted
}
- g.updateConfiguration(&cfg)
+ return g.updateConfiguration(&cfg)
// --------------------------------
// Solidity auto generated methods.
@@ -803,6 +985,29 @@ func RunGovernanceContract(evm *EVM, input []byte, contract *Contract) (
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)
+ 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":
round, index := new(big.Int), new(big.Int)
args := []interface{}{&round, &index}
@@ -913,18 +1118,18 @@ func RunGovernanceContract(evm *EVM, input []byte, contract *Contract) (
return nil, errExecutionReverted
}
return res, nil
- case "notarySetSize":
- res, err := method.Outputs.Pack(g.state.NotarySetSize())
- if err != nil {
+ case "nodesOffset":
+ address := common.Address{}
+ if err := method.Inputs.Unpack(&address, arguments); err != nil {
return nil, errExecutionReverted
}
- return res, nil
- case "offset":
- addr := common.Address{}
- if err := method.Inputs.Unpack(&addr, arguments); err != nil {
+ res, err := method.Outputs.Pack(g.state.NodesOffset(address))
+ if err != nil {
return nil, errExecutionReverted
}
- res, err := method.Outputs.Pack(g.state.Offset(addr))
+ return res, nil
+ case "notarySetSize":
+ res, err := method.Outputs.Pack(g.state.NotarySetSize())
if err != nil {
return nil, errExecutionReverted
}
@@ -965,7 +1170,9 @@ func RunGovernanceContract(evm *EVM, input []byte, contract *Contract) (
const (
roundHeightLoc = iota
nodesLoc
- offsetLoc
+ nodesOffsetLoc
+ delegatorsLoc
+ delegatorsOffsetLoc
crsLoc
dkgMasterPublicKeysLoc
dkgComplaintsLoc
@@ -1013,29 +1220,28 @@ func (s *GovernanceStateHelper) getSlotLoc(loc *big.Int) *big.Int {
}
func (s *GovernanceStateHelper) getMapLoc(pos *big.Int, key []byte) *big.Int {
- return new(big.Int).SetBytes(crypto.Keccak256(
- key, common.BigToHash(pos).Bytes()))
+ return new(big.Int).SetBytes(crypto.Keccak256(key, common.BigToHash(pos).Bytes()))
}
func (s *GovernanceStateHelper) readBytes(loc *big.Int) []byte {
- // length of the dynamic array (bytes).
+ // Length of the dynamic array (bytes).
rawLength := s.getStateBigInt(loc)
lengthByte := new(big.Int).Mod(rawLength, big.NewInt(256))
- // bytes length <= 31, lengthByte % 2 == 0
+ // Bytes length <= 31, lengthByte % 2 == 0
// return the high 31 bytes.
if new(big.Int).Mod(lengthByte, big.NewInt(2)).Cmp(big.NewInt(0)) == 0 {
length := new(big.Int).Div(lengthByte, big.NewInt(2)).Uint64()
return rawLength.Bytes()[:length]
}
- // actual length = (rawLength - 1) / 2
+ // Actual length = (rawLength - 1) / 2
length := new(big.Int).Div(new(big.Int).Sub(rawLength, big.NewInt(1)), big.NewInt(2)).Uint64()
- // data address.
+ // Data address.
dataLoc := s.getSlotLoc(loc)
- // read continiously for length bytes.
+ // Read continuously for length bytes.
carry := int64(0)
if length%32 > 0 {
carry = 1
@@ -1053,7 +1259,12 @@ func (s *GovernanceStateHelper) readBytes(loc *big.Int) []byte {
func (s *GovernanceStateHelper) writeBytes(loc *big.Int, data []byte) {
length := int64(len(data))
- // short bytes (length <= 31)
+ if length == 0 {
+ s.setState(common.BigToHash(loc), common.Hash{})
+ return
+ }
+
+ // Short bytes (length <= 31).
if length < 32 {
data2 := append([]byte(nil), data...)
// Right pad with zeros
@@ -1065,11 +1276,11 @@ func (s *GovernanceStateHelper) writeBytes(loc *big.Int, data []byte) {
return
}
- // write 2 * length + 1
+ // Write 2 * length + 1.
storedLength := new(big.Int).Add(new(big.Int).Mul(
big.NewInt(length), big.NewInt(2)), big.NewInt(1))
s.setStateBigInt(loc, storedLength)
- // write data chunck.
+ // Write data chunck.
dataLoc := s.getSlotLoc(loc)
carry := int64(0)
if length%32 > 0 {
@@ -1083,7 +1294,7 @@ func (s *GovernanceStateHelper) writeBytes(loc *big.Int, data []byte) {
maxLoc = length
}
data2 := data[i*32 : maxLoc]
- // Right pad with zeros
+ // Right pad with zeros.
for len(data2) < 32 {
data2 = append(data2, byte(0))
}
@@ -1111,11 +1322,11 @@ func (s *GovernanceStateHelper) appendTo2DByteArray(pos, index *big.Int, data []
baseLoc := s.getSlotLoc(pos)
loc := new(big.Int).Add(baseLoc, index)
- // increase length by 1.
+ // Increase length by 1.
arrayLength := s.getStateBigInt(loc)
s.setStateBigInt(loc, new(big.Int).Add(arrayLength, big.NewInt(1)))
- // write element.
+ // Write element.
dataLoc := s.getSlotLoc(loc)
elementLoc := new(big.Int).Add(dataLoc, arrayLength)
s.writeBytes(elementLoc, data)
@@ -1131,7 +1342,7 @@ func (s *GovernanceStateHelper) RoundHeight(round *big.Int) *big.Int {
return s.getStateBigInt(loc)
}
func (s *GovernanceStateHelper) PushRoundHeight(height *big.Int) {
- // increase length by 1.
+ // Increase length by 1.
length := s.getStateBigInt(big.NewInt(roundHeightLoc))
s.setStateBigInt(big.NewInt(roundHeightLoc), new(big.Int).Add(length, big.NewInt(1)))
@@ -1163,9 +1374,9 @@ type nodeInfo struct {
Url string
}
-const nodesInfoSize = 7
+const nodeStructSize = 7
-func (s *GovernanceStateHelper) NodesLength() *big.Int {
+func (s *GovernanceStateHelper) LenNodes() *big.Int {
return s.getStateBigInt(big.NewInt(nodesLoc))
}
func (s *GovernanceStateHelper) Node(index *big.Int) *nodeInfo {
@@ -1173,97 +1384,194 @@ func (s *GovernanceStateHelper) Node(index *big.Int) *nodeInfo {
arrayBaseLoc := s.getSlotLoc(big.NewInt(nodesLoc))
elementBaseLoc := new(big.Int).Add(arrayBaseLoc,
- new(big.Int).Mul(index, big.NewInt(nodesInfoSize)))
+ new(big.Int).Mul(index, big.NewInt(nodeStructSize)))
- // owner.
+ // Owner.
loc := elementBaseLoc
node.Owner = common.BytesToAddress(s.getState(common.BigToHash(elementBaseLoc)).Bytes())
- // publicKey.
+ // PublicKey.
loc = new(big.Int).Add(elementBaseLoc, big.NewInt(1))
node.PublicKey = s.readBytes(loc)
- // staked.
+ // Staked.
loc = new(big.Int).Add(elementBaseLoc, big.NewInt(2))
node.Staked = s.getStateBigInt(loc)
- // name.
+ // Name.
loc = new(big.Int).Add(elementBaseLoc, big.NewInt(3))
node.Name = string(s.readBytes(loc))
- // email.
+ // Email.
loc = new(big.Int).Add(elementBaseLoc, big.NewInt(4))
node.Email = string(s.readBytes(loc))
- // location.
+ // Location.
loc = new(big.Int).Add(elementBaseLoc, big.NewInt(5))
node.Location = string(s.readBytes(loc))
- // url.
+ // Url.
loc = new(big.Int).Add(elementBaseLoc, big.NewInt(6))
node.Url = string(s.readBytes(loc))
return node
}
func (s *GovernanceStateHelper) PushNode(n *nodeInfo) {
- // increase length by 1
- arrayLength := s.NodesLength()
+ // Increase length by 1.
+ arrayLength := s.LenNodes()
s.setStateBigInt(big.NewInt(nodesLoc), new(big.Int).Add(arrayLength, big.NewInt(1)))
s.UpdateNode(arrayLength, n)
}
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(nodesInfoSize)))
+ elementBaseLoc := new(big.Int).Add(arrayBaseLoc, new(big.Int).Mul(index, big.NewInt(nodeStructSize)))
- // owner.
+ // Owner.
loc := elementBaseLoc
s.setState(common.BigToHash(loc), n.Owner.Hash())
- // publicKey.
+ // PublicKey.
loc = new(big.Int).Add(elementBaseLoc, big.NewInt(1))
s.writeBytes(loc, n.PublicKey)
- // staked.
+ // Staked.
loc = new(big.Int).Add(elementBaseLoc, big.NewInt(2))
s.setStateBigInt(loc, n.Staked)
- // name.
+ // Name.
loc = new(big.Int).Add(elementBaseLoc, big.NewInt(3))
s.writeBytes(loc, []byte(n.Name))
- // email.
+ // Email.
loc = new(big.Int).Add(elementBaseLoc, big.NewInt(4))
s.writeBytes(loc, []byte(n.Email))
- // location.
+ // Location.
loc = new(big.Int).Add(elementBaseLoc, big.NewInt(5))
s.writeBytes(loc, []byte(n.Location))
- // url.
+ // Url.
loc = new(big.Int).Add(elementBaseLoc, big.NewInt(6))
s.writeBytes(loc, []byte(n.Url))
}
+func (s *GovernanceStateHelper) PopLastNode() {
+ // Decrease length by 1.
+ arrayLength := s.LenNodes()
+ newArrayLength := new(big.Int).Sub(arrayLength, big.NewInt(1))
+ s.setStateBigInt(big.NewInt(nodesLoc), newArrayLength)
+
+ s.UpdateNode(newArrayLength, &nodeInfo{Staked: big.NewInt(0)})
+}
func (s *GovernanceStateHelper) Nodes() []*nodeInfo {
var nodes []*nodeInfo
- for i := int64(0); i < int64(s.NodesLength().Uint64()); i++ {
+ for i := int64(0); i < int64(s.LenNodes().Uint64()); i++ {
nodes = append(nodes, s.Node(big.NewInt(i)))
}
return nodes
}
+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.Staked.Cmp(s.MinStake()) >= 0 {
+ nodes = append(nodes, node)
+ }
+ }
+ return nodes
+}
-// mapping(address => uint256) public offset;
-func (s *GovernanceStateHelper) Offset(addr common.Address) *big.Int {
- loc := s.getMapLoc(big.NewInt(offsetLoc), addr.Bytes())
+// mapping(address => uint256) public nodeOffset;
+func (s *GovernanceStateHelper) NodesOffset(addr common.Address) *big.Int {
+ loc := s.getMapLoc(big.NewInt(nodesOffsetLoc), addr.Bytes())
return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1))
}
-func (s *GovernanceStateHelper) PutOffset(addr common.Address, offset *big.Int) {
- loc := s.getMapLoc(big.NewInt(offsetLoc), addr.Bytes())
+func (s *GovernanceStateHelper) PutNodesOffset(addr common.Address, offset *big.Int) {
+ loc := s.getMapLoc(big.NewInt(nodesOffsetLoc), addr.Bytes())
s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1)))
}
-func (s *GovernanceStateHelper) DeleteOffset(addr common.Address) {
- loc := s.getMapLoc(big.NewInt(offsetLoc), addr.Bytes())
+func (s *GovernanceStateHelper) DeleteNodesOffset(addr common.Address) {
+ loc := s.getMapLoc(big.NewInt(nodesOffsetLoc), addr.Bytes())
+ s.setStateBigInt(loc, big.NewInt(0))
+}
+
+// struct Delegator {
+// address node;
+// address owner;
+// uint256 value;
+// }
+
+type delegatorInfo struct {
+ Owner common.Address
+ Value *big.Int
+}
+
+const delegatorStructSize = 2
+
+// mapping(address => Delegator[]) public delegators;
+func (s *GovernanceStateHelper) LenDelegators(nodeAddr common.Address) *big.Int {
+ loc := s.getMapLoc(big.NewInt(delegatorsLoc), nodeAddr.Bytes())
+ return s.getStateBigInt(loc)
+}
+func (s *GovernanceStateHelper) 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)
+
+ return delegator
+}
+func (s *GovernanceStateHelper) 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 *GovernanceStateHelper) 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)
+}
+func (s *GovernanceStateHelper) 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)})
+}
+
+// mapping(address => mapping(address => uint256)) delegatorsOffset;
+func (s *GovernanceStateHelper) 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 *GovernanceStateHelper) 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 *GovernanceStateHelper) DeleteDelegatorsOffset(nodeAddr, delegatorAddr common.Address) {
+ loc := s.getMapLoc(s.getMapLoc(big.NewInt(delegatorsOffsetLoc), nodeAddr.Bytes()), delegatorAddr.Bytes())
s.setStateBigInt(loc, big.NewInt(0))
}
@@ -1418,7 +1726,7 @@ func (s *GovernanceStateHelper) MinBlockInterval() *big.Int {
func (s *GovernanceStateHelper) Stake(
addr common.Address, publicKey []byte, staked *big.Int,
name, email, location, url string) {
- offset := s.NodesLength()
+ offset := s.LenNodes()
s.PushNode(&nodeInfo{
Owner: addr,
PublicKey: publicKey,
@@ -1428,20 +1736,22 @@ func (s *GovernanceStateHelper) Stake(
Location: location,
Url: url,
})
- s.PutOffset(addr, offset)
+ s.PutNodesOffset(addr, offset)
}
+const phiRatioMultiplier = 1000000.0
+
// Configuration returns the current configuration.
func (s *GovernanceStateHelper) Configuration() *params.DexconConfig {
return &params.DexconConfig{
MinStake: s.getStateBigInt(big.NewInt(minStakeLoc)),
BlockReward: s.getStateBigInt(big.NewInt(blockRewardLoc)),
- BlockGasLimit: uint64(s.getStateBigInt(big.NewInt(blockGasLimitLoc)).Uint64()),
+ BlockGasLimit: s.getStateBigInt(big.NewInt(blockGasLimitLoc)).Uint64(),
NumChains: uint32(s.getStateBigInt(big.NewInt(numChainsLoc)).Uint64()),
LambdaBA: s.getStateBigInt(big.NewInt(lambdaBALoc)).Uint64(),
LambdaDKG: s.getStateBigInt(big.NewInt(lambdaDKGLoc)).Uint64(),
- K: int(s.getStateBigInt(big.NewInt(kLoc)).Uint64()),
- PhiRatio: float32(s.getStateBigInt(big.NewInt(phiRatioLoc)).Uint64()) / 1000000.0,
+ K: uint32(s.getStateBigInt(big.NewInt(kLoc)).Uint64()),
+ PhiRatio: float32(s.getStateBigInt(big.NewInt(phiRatioLoc)).Uint64()) / phiRatioMultiplier,
NotarySetSize: uint32(s.getStateBigInt(big.NewInt(notarySetSizeLoc)).Uint64()),
DKGSetSize: uint32(s.getStateBigInt(big.NewInt(dkgSetSizeLoc)).Uint64()),
RoundInterval: s.getStateBigInt(big.NewInt(roundIntervalLoc)).Uint64(),
@@ -1458,13 +1768,44 @@ func (s *GovernanceStateHelper) UpdateConfiguration(cfg *params.DexconConfig) {
s.setStateBigInt(big.NewInt(lambdaBALoc), big.NewInt(int64(cfg.LambdaBA)))
s.setStateBigInt(big.NewInt(lambdaDKGLoc), big.NewInt(int64(cfg.LambdaDKG)))
s.setStateBigInt(big.NewInt(kLoc), big.NewInt(int64(cfg.K)))
- s.setStateBigInt(big.NewInt(phiRatioLoc), big.NewInt(int64(cfg.PhiRatio)))
+ s.setStateBigInt(big.NewInt(phiRatioLoc), big.NewInt(int64(cfg.PhiRatio*phiRatioMultiplier)))
s.setStateBigInt(big.NewInt(notarySetSizeLoc), big.NewInt(int64(cfg.NotarySetSize)))
s.setStateBigInt(big.NewInt(dkgSetSizeLoc), big.NewInt(int64(cfg.DKGSetSize)))
s.setStateBigInt(big.NewInt(roundIntervalLoc), big.NewInt(int64(cfg.RoundInterval)))
s.setStateBigInt(big.NewInt(minBlockIntervalLoc), big.NewInt(int64(cfg.MinBlockInterval)))
}
+type rawConfigStruct struct {
+ MinStake *big.Int
+ BlockReward *big.Int
+ BlockGasLimit *big.Int
+ NumChains *big.Int
+ LambdaBA *big.Int
+ LambdaDKG *big.Int
+ K *big.Int
+ PhiRatio *big.Int
+ NotarySetSize *big.Int
+ DKGSetSize *big.Int
+ RoundInterval *big.Int
+ MinBlockInterval *big.Int
+}
+
+// UpdateConfigurationRaw updates system configuration.
+func (s *GovernanceStateHelper) UpdateConfigurationRaw(cfg *rawConfigStruct) {
+ s.setStateBigInt(big.NewInt(minStakeLoc), cfg.MinStake)
+ s.setStateBigInt(big.NewInt(blockRewardLoc), cfg.BlockReward)
+ s.setStateBigInt(big.NewInt(blockGasLimitLoc), cfg.BlockGasLimit)
+ s.setStateBigInt(big.NewInt(numChainsLoc), cfg.NumChains)
+ s.setStateBigInt(big.NewInt(lambdaBALoc), cfg.LambdaBA)
+ s.setStateBigInt(big.NewInt(lambdaDKGLoc), cfg.LambdaDKG)
+ s.setStateBigInt(big.NewInt(kLoc), cfg.K)
+ s.setStateBigInt(big.NewInt(phiRatioLoc), cfg.PhiRatio)
+ s.setStateBigInt(big.NewInt(notarySetSizeLoc), cfg.NotarySetSize)
+ s.setStateBigInt(big.NewInt(dkgSetSizeLoc), cfg.DKGSetSize)
+ s.setStateBigInt(big.NewInt(roundIntervalLoc), cfg.RoundInterval)
+ s.setStateBigInt(big.NewInt(minBlockIntervalLoc), cfg.MinBlockInterval)
+}
+
// event ConfigurationChanged();
func (s *GovernanceStateHelper) emitConfigurationChangedEvent() {
s.StateDB.AddLog(&types.Log{
@@ -1483,6 +1824,42 @@ func (s *GovernanceStateHelper) emitCRSProposed(round *big.Int, crs common.Hash)
})
}
+// event Staked(address indexed NodeAddress, uint256 Amount);
+func (s *GovernanceStateHelper) emitStaked(nodeAddr common.Address) {
+ s.StateDB.AddLog(&types.Log{
+ Address: GovernanceContractAddress,
+ Topics: []common.Hash{events["Staked"].Id(), nodeAddr.Hash()},
+ Data: []byte{},
+ })
+}
+
+// event Unstaked(address indexed NodeAddress);
+func (s *GovernanceStateHelper) emitUnstaked(nodeAddr common.Address) {
+ s.StateDB.AddLog(&types.Log{
+ Address: GovernanceContractAddress,
+ Topics: []common.Hash{events["Unstaked"].Id(), nodeAddr.Hash()},
+ Data: []byte{},
+ })
+}
+
+// event Delegated(address indexed NodeAddress, address indexed DelegatorAddress, uint256 Amount);
+func (s *GovernanceStateHelper) emitDelegated(nodeAddr, delegatorAddr common.Address, amount *big.Int) {
+ s.StateDB.AddLog(&types.Log{
+ Address: GovernanceContractAddress,
+ Topics: []common.Hash{events["Delegated"].Id(), nodeAddr.Hash(), delegatorAddr.Hash()},
+ Data: common.BigToHash(amount).Bytes(),
+ })
+}
+
+// event Undelegated(address indexed NodeAddress, address indexed DelegatorAddress);
+func (s *GovernanceStateHelper) emitUndelegated(nodeAddr, delegatorAddr common.Address) {
+ s.StateDB.AddLog(&types.Log{
+ Address: GovernanceContractAddress,
+ Topics: []common.Hash{events["Undelegated"].Id(), nodeAddr.Hash(), delegatorAddr.Hash()},
+ Data: []byte{},
+ })
+}
+
// GovernanceContract represents the governance contract of DEXCON.
type GovernanceContract struct {
evm *EVM
@@ -1498,7 +1875,20 @@ func newGovernanceContract(evm *EVM, contract *Contract) *GovernanceContract {
}
}
-func (g *GovernanceContract) UseGas(gas uint64) ([]byte, error) {
+func (g *GovernanceContract) Address() common.Address {
+ return GovernanceContractAddress
+}
+
+func (g *GovernanceContract) transfer(from, to common.Address, amount *big.Int) bool {
+ // TODO(w): add this to debug trace so it shows up as internal transaction.
+ if g.evm.CanTransfer(g.evm.StateDB, from, amount) {
+ g.evm.Transfer(g.evm.StateDB, from, to, amount)
+ return true
+ }
+ return false
+}
+
+func (g *GovernanceContract) useGas(gas uint64) ([]byte, error) {
if !g.contract.UseGas(gas) {
return nil, ErrOutOfGas
}
@@ -1506,7 +1896,7 @@ func (g *GovernanceContract) UseGas(gas uint64) ([]byte, error) {
}
func (g *GovernanceContract) penalize() ([]byte, error) {
- g.UseGas(g.contract.Gas)
+ g.useGas(g.contract.Gas)
return nil, errExecutionReverted
}
@@ -1519,13 +1909,13 @@ func (g *GovernanceContract) inDKGSet(round *big.Int, nodeID coreTypes.NodeID) b
configRound = new(big.Int).Sub(round, big.NewInt(int64(core.ConfigRoundShift)))
}
- statedb, err := g.evm.Context.StateAtNumber(g.state.RoundHeight(configRound).Uint64())
+ statedb, err := g.evm.StateAtNumber(g.state.RoundHeight(configRound).Uint64())
if err != nil {
panic(err)
}
state := GovernanceStateHelper{statedb}
- for _, x := range state.Nodes() {
+ for _, x := range state.QualifiedNodes() {
mpk, err := ecdsa.NewPublicKeyFromByteSlice(x.PublicKey)
if err != nil {
panic(err)
@@ -1578,7 +1968,7 @@ func (g *GovernanceContract) addDKGComplaint(round *big.Int, comp []byte) ([]byt
g.state.PushDKGComplaint(round, comp)
// Set this to relatively high to prevent spamming
- return g.UseGas(5000000)
+ return g.useGas(5000000)
}
func (g *GovernanceContract) addDKGMasterPublicKey(round *big.Int, mpk []byte) ([]byte, error) {
@@ -1588,7 +1978,7 @@ func (g *GovernanceContract) addDKGMasterPublicKey(round *big.Int, mpk []byte) (
}
caller := g.contract.Caller()
- offset := g.state.Offset(caller)
+ offset := g.state.NodesOffset(caller)
// Can not add dkg mpk if not staked.
if offset.Cmp(big.NewInt(0)) < 0 {
@@ -1612,7 +2002,7 @@ func (g *GovernanceContract) addDKGMasterPublicKey(round *big.Int, mpk []byte) (
g.state.PushDKGMasterPublicKey(round, mpk)
- return g.UseGas(100000)
+ return g.useGas(100000)
}
func (g *GovernanceContract) addDKGFinalize(round *big.Int, finalize []byte) ([]byte, error) {
@@ -1642,16 +2032,48 @@ func (g *GovernanceContract) addDKGFinalize(round *big.Int, finalize []byte) ([]
g.state.IncDKGFinalizedsCount(round)
}
- return g.UseGas(100000)
+ return g.useGas(100000)
}
-func (g *GovernanceContract) updateConfiguration(config *params.DexconConfig) ([]byte, error) {
+func (g *GovernanceContract) delegate(nodeAddr common.Address) ([]byte, error) {
+ offset := g.state.NodesOffset(nodeAddr)
+ if offset.Cmp(big.NewInt(0)) < 0 {
+ return nil, errExecutionReverted
+ }
+
+ caller := g.contract.Caller()
+ value := g.contract.Value()
+
+ // 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)
+
+ // Push delegator record.
+ offset = g.state.LenDelegators(nodeAddr)
+ g.state.PushDelegator(nodeAddr, &delegatorInfo{
+ Owner: caller,
+ Value: value,
+ })
+ 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() {
return nil, errExecutionReverted
}
- g.state.UpdateConfiguration(config)
+ g.state.UpdateConfigurationRaw(cfg)
g.state.emitConfigurationChangedEvent()
return nil, nil
}
@@ -1665,57 +2087,116 @@ func (g *GovernanceContract) stake(
}
caller := g.contract.Caller()
- offset := g.state.Offset(caller)
+ offset := g.state.NodesOffset(caller)
- // Need to stake at least minStake.
- if g.contract.Value().Cmp(g.state.MinStake()) < 0 {
+ // Check if public key is valid.
+ if _, err := crypto.UnmarshalPubkey(publicKey); err != nil {
return g.penalize()
}
// Can not stake if already staked.
if offset.Cmp(big.NewInt(0)) >= 0 {
- return g.penalize()
+ return nil, errExecutionReverted
}
- offset = g.state.NodesLength()
+ offset = g.state.LenNodes()
g.state.PushNode(&nodeInfo{
Owner: caller,
PublicKey: publicKey,
- Staked: g.contract.Value(),
+ Staked: big.NewInt(0),
Name: name,
Email: email,
Location: location,
Url: url,
})
- g.state.PutOffset(caller, offset)
+ g.state.PutNodesOffset(caller, offset)
- return g.UseGas(0)
+ // Delegate fund to itself.
+ if g.contract.Value().Cmp(big.NewInt(0)) > 0 {
+ if ret, err := g.delegate(caller); err != nil {
+ return ret, err
+ }
+ }
+
+ g.state.emitStaked(caller)
+ return g.useGas(100000)
+}
+
+func (g *GovernanceContract) undelegateHelper(nodeAddr, owner common.Address) ([]byte, error) {
+ nodeOffset := g.state.NodesOffset(nodeAddr)
+ if nodeOffset.Cmp(big.NewInt(0)) < 0 {
+ return nil, errExecutionReverted
+ }
+
+ offset := g.state.DelegatorsOffset(nodeAddr, owner)
+ if offset.Cmp(big.NewInt(0)) < 0 {
+ return nil, errExecutionReverted
+ }
+
+ delegator := g.state.Delegator(nodeAddr, offset)
+ 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, owner)
+ g.state.PopLastDelegator(nodeAddr)
+
+ // Subtract from the total staked of node.
+ node := g.state.Node(nodeOffset)
+ node.Staked = new(big.Int).Sub(node.Staked, delegator.Value)
+ g.state.UpdateNode(nodeOffset, node)
+
+ // Return the staked fund.
+ if !g.transfer(GovernanceContractAddress, delegator.Owner, delegator.Value) {
+ return nil, errExecutionReverted
+ }
+
+ g.state.emitUndelegated(nodeAddr, owner)
+ return g.useGas(100000)
+}
+
+func (g *GovernanceContract) undelegate(nodeAddr common.Address) ([]byte, error) {
+ return g.undelegateHelper(nodeAddr, g.contract.Caller())
}
func (g *GovernanceContract) unstake() ([]byte, error) {
caller := g.contract.Caller()
- offset := g.state.Offset(caller)
+ offset := g.state.NodesOffset(caller)
if offset.Cmp(big.NewInt(0)) < 0 {
return nil, errExecutionReverted
}
- node := g.state.Node(offset)
- length := g.state.NodesLength()
+ // 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))
+ }
+
+ length := g.state.LenNodes()
lastIndex := new(big.Int).Sub(length, big.NewInt(1))
// Delete the node.
- if offset != lastIndex {
+ if offset.Cmp(lastIndex) != 0 {
lastNode := g.state.Node(lastIndex)
g.state.UpdateNode(offset, lastNode)
- g.state.PutOffset(lastNode.Owner, offset)
- g.state.DeleteOffset(caller)
+ g.state.PutNodesOffset(lastNode.Owner, offset)
}
+ g.state.DeleteNodesOffset(caller)
+ g.state.PopLastNode()
- // Return the staked fund.
- // TODO(w): add this to debug trace so it shows up as internal transaction.
- g.evm.Transfer(g.evm.StateDB, GovernanceContractAddress, caller, node.Staked)
+ g.state.emitUnstaked(caller)
- return g.UseGas(0)
+ return g.useGas(100000)
}
func (g *GovernanceContract) proposeCRS(nextRound *big.Int, signedCRS []byte) ([]byte, error) {
@@ -1774,11 +2255,11 @@ func (g *GovernanceContract) proposeCRS(nextRound *big.Int, signedCRS []byte) ([
crs := common.BytesToHash(newCRS)
g.state.PushCRS(crs)
- g.state.emitCRSProposed(g.state.LenCRS(), crs)
+ g.state.emitCRSProposed(nextRound, crs)
// To encourage DKG set to propose the correct value, correctly submitting
// this should cause nothing.
- return g.UseGas(0)
+ return g.useGas(0)
}
func (g *GovernanceContract) transferOwnership(newOwner common.Address) ([]byte, error) {
@@ -1793,7 +2274,7 @@ func (g *GovernanceContract) transferOwnership(newOwner common.Address) ([]byte,
func (g *GovernanceContract) snapshotRound(round, height *big.Int) ([]byte, error) {
// Validate if this mapping is correct. Only block proposer need to verify this.
if g.evm.IsBlockProposer() {
- realHeight, ok := g.evm.Context.GetRoundHeight(round.Uint64())
+ realHeight, ok := g.evm.GetRoundHeight(round.Uint64())
if !ok {
return g.penalize()
}