diff options
-rw-r--r-- | core/vm/oracle_contract_abi.go | 31 | ||||
-rw-r--r-- | core/vm/oracle_contracts.go | 41 | ||||
-rw-r--r-- | core/vm/oracle_contracts_test.go | 31 |
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 ba1f6aa52..2293cdd42 100644 --- a/core/vm/oracle_contracts.go +++ b/core/vm/oracle_contracts.go @@ -1088,6 +1088,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{ @@ -2413,6 +2422,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 { @@ -2479,6 +2494,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 6a3534ce5..6985eb2b9 100644 --- a/core/vm/oracle_contracts_test.go +++ b/core/vm/oracle_contracts_test.go @@ -300,7 +300,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") @@ -315,6 +315,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) |