aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWei-Ning Huang <w@dexon.org>2019-04-01 19:42:50 +0800
committerWei-Ning Huang <w@dexon.org>2019-04-09 21:32:59 +0800
commit1b8bb239546f1703a6a0ada2211cc607b4c55b81 (patch)
tree98d533e989f5a710926d5ab5fa7623d7f8e2a21c
parenta2436b50ae570eb92afd836ca93005b60f6e0e21 (diff)
downloaddexon-1b8bb239546f1703a6a0ada2211cc607b4c55b81.tar.gz
dexon-1b8bb239546f1703a6a0ada2211cc607b4c55b81.tar.zst
dexon-1b8bb239546f1703a6a0ada2211cc607b4c55b81.zip
core: vm: implement node public key replacement (#324)
-rw-r--r--core/vm/oracle_contract_abi.go31
-rw-r--r--core/vm/oracle_contracts.go41
-rw-r--r--core/vm/oracle_contracts_test.go31
3 files changed, 102 insertions, 1 deletions
diff --git a/core/vm/oracle_contract_abi.go b/core/vm/oracle_contract_abi.go
index 4572a74ae..799d0f28f 100644
--- a/core/vm/oracle_contract_abi.go
+++ b/core/vm/oracle_contract_abi.go
@@ -682,6 +682,23 @@ const GovernanceABIJSON = `
},
{
"indexed": false,
+ "name": "PublicKey",
+ "type": "bytes"
+ }
+ ],
+ "name": "NodePublicKeyReplaced",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "NodeAddress",
+ "type": "address"
+ },
+ {
+ "indexed": false,
"name": "Amount",
"type": "uint256"
}
@@ -908,6 +925,20 @@ const GovernanceABIJSON = `
"type": "function"
},
{
+ "constant": false,
+ "inputs": [
+ {
+ "name": "NewPublicKey",
+ "type": "bytes"
+ }
+ ],
+ "name": "replaceNodePublicKey",
+ "outputs": [],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
"constant": true,
"inputs": [],
"name": "nodesLength",
diff --git a/core/vm/oracle_contracts.go b/core/vm/oracle_contracts.go
index 9e148e4e8..0431f3823 100644
--- a/core/vm/oracle_contracts.go
+++ b/core/vm/oracle_contracts.go
@@ -1090,6 +1090,15 @@ func (s *GovernanceState) emitNodeOwnershipTransfered(nodeAddr, newNodeAddr comm
})
}
+// event NodePublicKeyReplaced(address indexed NodeAddress, bytes PublicKey);
+func (s *GovernanceState) emitNodePublicKeyReplaced(nodeAddr common.Address, pk []byte) {
+ s.StateDB.AddLog(&types.Log{
+ Address: GovernanceContractAddress,
+ Topics: []common.Hash{GovernanceABI.Events["NodePublicKeyReplaced"].Id(), nodeAddr.Hash()},
+ Data: pk,
+ })
+}
+
// event Staked(address indexed NodeAddress, uint256 Amount);
func (s *GovernanceState) emitStaked(nodeAddr common.Address, amount *big.Int) {
s.StateDB.AddLog(&types.Log{
@@ -2415,6 +2424,12 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re
return nil, errExecutionReverted
}
return res, nil
+ case "replaceNodePublicKey":
+ var pk []byte
+ if err := method.Inputs.Unpack(&pk, arguments); err != nil {
+ return nil, errExecutionReverted
+ }
+ return g.replaceNodePublicKey(pk)
case "roundHeight":
round := new(big.Int)
if err := method.Inputs.Unpack(&round, arguments); err != nil {
@@ -2481,6 +2496,32 @@ func (g *GovernanceContract) transferNodeOwnership(newOwner common.Address) ([]b
return nil, nil
}
+func (g *GovernanceContract) replaceNodePublicKey(newPublicKey []byte) ([]byte, error) {
+ caller := g.contract.Caller()
+
+ offset := g.state.NodesOffsetByAddress(caller)
+ if offset.Cmp(big.NewInt(0)) < 0 {
+ return nil, errExecutionReverted
+ }
+
+ node := g.state.Node(offset)
+
+ _, err := publicKeyToNodeKeyAddress(newPublicKey)
+ if err != nil {
+ return nil, errExecutionReverted
+ }
+
+ g.state.PutNodeOffsets(node, big.NewInt(0))
+
+ node.PublicKey = newPublicKey
+ g.state.PutNodeOffsets(node, offset)
+ g.state.UpdateNode(offset, node)
+
+ g.state.emitNodePublicKeyReplaced(caller, newPublicKey)
+
+ return nil, nil
+}
+
func PackProposeCRS(round uint64, signedCRS []byte) ([]byte, error) {
method := GovernanceABI.Name2Method["proposeCRS"]
res, err := method.Inputs.Pack(big.NewInt(int64(round)), signedCRS)
diff --git a/core/vm/oracle_contracts_test.go b/core/vm/oracle_contracts_test.go
index af80a7132..ae7755a06 100644
--- a/core/vm/oracle_contracts_test.go
+++ b/core/vm/oracle_contracts_test.go
@@ -301,7 +301,7 @@ func (g *OracleContractsTestSuite) TestTransferNodeOwnership() {
g.Require().Equal(offset.Uint64(), g.s.NodesOffsetByAddress(newAddr).Uint64())
g.Require().Equal(offset.Uint64(), g.s.NodesOffsetByNodeKeyAddress(newNodeKeyAddr).Uint64())
- // Call with owner.
+ // New node for duplication test.
privKey2, addr2 := newPrefundAccount(g.stateDB)
pk2 := crypto.FromECDSAPub(&privKey2.PublicKey)
input, err = GovernanceABI.ABI.Pack("register", pk2, "Test2", "test1@dexon.org", "Taipei", "https://dexon.org")
@@ -316,6 +316,35 @@ func (g *OracleContractsTestSuite) TestTransferNodeOwnership() {
g.Require().Error(err)
}
+func (g *OracleContractsTestSuite) TestReplaceNodePublicKey() {
+ privKey, addr := newPrefundAccount(g.stateDB)
+ pk := crypto.FromECDSAPub(&privKey.PublicKey)
+
+ amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6))
+ input, err := GovernanceABI.ABI.Pack("register", pk, "Test1", "test1@dexon.org", "Taipei", "https://dexon.org")
+ g.Require().NoError(err)
+ _, err = g.call(GovernanceContractAddress, addr, input, amount)
+ g.Require().NoError(err)
+
+ offset := g.s.NodesOffsetByAddress(addr)
+
+ privKey2, addr2 := newPrefundAccount(g.stateDB)
+ pk2 := crypto.FromECDSAPub(&privKey2.PublicKey)
+
+ input, err = GovernanceABI.ABI.Pack("replaceNodePublicKey", pk2)
+ g.Require().NoError(err)
+
+ // Call with non-owner.
+ _, noneOwner := newPrefundAccount(g.stateDB)
+ _, err = g.call(GovernanceContractAddress, noneOwner, input, big.NewInt(0))
+ g.Require().Error(err)
+
+ // Call with owner.
+ _, err = g.call(GovernanceContractAddress, addr, input, big.NewInt(0))
+ g.Require().NoError(err)
+ g.Require().Equal(offset.Uint64(), g.s.NodesOffsetByNodeKeyAddress(addr2).Uint64())
+}
+
func (g *OracleContractsTestSuite) TestStakingMechanism() {
privKey, addr := newPrefundAccount(g.stateDB)
pk := crypto.FromECDSAPub(&privKey.PublicKey)