Add edit validator;delegate;redelegate;undelegate msgs

pull/1680/head
Rongjian Lan 5 years ago
parent 8aa1e10e99
commit 741a101d4f
  1. 7
      internal/common/address.go
  2. 7
      internal/common/hash.go
  3. 2
      staking/types/commission.go
  4. 195
      staking/types/messages.go
  5. 217
      staking/types/messages_test.go

@ -1,6 +1,7 @@
package common
import (
"bytes"
"database/sql/driver"
"encoding/hex"
"fmt"
@ -49,6 +50,12 @@ func IsBech32Address(s string) bool {
return true
}
// IsEmpty gets whether the address contains all 0 bytes
func (a Address) IsEmpty() bool {
empty := Address{}
return bytes.Compare(a[:], empty[:]) == 0
}
// Bytes gets the string representation of the underlying address.
func (a Address) Bytes() []byte { return a[:] }

@ -1,6 +1,7 @@
package common
import (
"bytes"
"database/sql/driver"
"encoding/hex"
"fmt"
@ -34,6 +35,12 @@ func BytesToHash(b []byte) Hash {
return h
}
// IsEmpty gets whether the hash contains all 0 bytes
func (h Hash) IsEmpty() bool {
empty := Hash{}
return bytes.Compare(h[:], empty[:]) == 0
}
// BigToHash sets byte representation of b to hash.
// If b is larger than len(h), b will be cropped from the left.
func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) }

@ -8,7 +8,7 @@ type (
// Commission defines a commission parameters for a given validator.
Commission struct {
CommissionRates `json:"commission_rates" yaml:"commission_rates"`
UpdateHeight big.Int `json:"update_time" yaml:"update_time"` // the block height the commission rate was last changed
UpdateHeight *big.Int `json:"update_time" yaml:"update_time"` // the block height the commission rate was last changed
}
// CommissionRates defines the initial commission rates to be used for creating a

@ -1,10 +1,14 @@
package types
import (
"bytes"
"encoding/json"
"math/big"
"github.com/harmony-one/bls/ffi/go/bls"
"github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/shard"
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
)
// StakingMessage must fulfill these interfaces
@ -18,16 +22,189 @@ type StakingMessage interface {
// MsgCreateValidator - struct for creating a new validator
type MsgCreateValidator struct {
Description Description `json:"description" yaml:"description"`
Commission CommissionRates `json:"commission" yaml:"commission"`
MinSelfDelegation big.Int `json:"min_self_delegation" yaml:"min_self_delegation"`
Address common.Address `json:"validator_address" yaml:"validator_address"`
ValidatingPubKey bls.PublicKey `json:"validating_pub_key" yaml:"validating_pub_key"`
Amount big.Int `json:"amount" yaml:"amount"`
Description Description `json:"description" yaml:"description"`
Commission CommissionRates `json:"commission" yaml:"commission"`
MinSelfDelegation *big.Int `json:"min_self_delegation" yaml:"min_self_delegation"`
StakingAddress common.Address `json:"staking_address" yaml:"staking_address"`
ValidatingPubKey shard.BlsPublicKey `json:"validating_pub_key" yaml:"validating_pub_key"`
Amount *big.Int `json:"amount" yaml:"amount"`
}
// msgCreateValidatorJSON - struct for creating a new validator for JSON
type msgCreateValidatorJSON struct {
Description Description `json:"description" yaml:"description"`
Commission CommissionRates `json:"commission" yaml:"commission"`
MinSelfDelegation *big.Int `json:"min_self_delegation" yaml:"min_self_delegation"`
StakingAddress common.Address `json:"staking_address" yaml:"staking_address"`
ValidatingPubKey shard.BlsPublicKey `json:"validating_pub_key" yaml:"validating_pub_key"`
Amount *big.Int `json:"amount" yaml:"amount"`
}
// NewMsgCreateValidator creates a new validator
func NewMsgCreateValidator(
description Description, commission CommissionRates, minSelfDelegation *big.Int, stakingAddress common.Address, validatingPubKey shard.BlsPublicKey, amount *big.Int) MsgCreateValidator {
return MsgCreateValidator{
Description: description,
Commission: commission,
MinSelfDelegation: minSelfDelegation,
StakingAddress: stakingAddress,
ValidatingPubKey: validatingPubKey,
Amount: amount,
}
}
// Type ...
func (msg MsgCreateValidator) Type() string { return "create_validator" }
// Signer ...
func (msg MsgCreateValidator) Signer() common.Address { return msg.Address }
func (msg MsgCreateValidator) Signer() common.Address { return msg.StakingAddress }
// MarshalJSON implements the json.Marshaler interface to provide custom JSON
// serialization of the MsgCreateValidator type.
func (msg MsgCreateValidator) MarshalJSON() ([]byte, error) {
return json.Marshal(msgCreateValidatorJSON{
Description: msg.Description,
Commission: msg.Commission,
MinSelfDelegation: msg.MinSelfDelegation,
StakingAddress: msg.StakingAddress,
ValidatingPubKey: msg.ValidatingPubKey,
Amount: msg.Amount,
})
}
// UnmarshalJSON implements the json.Unmarshaler interface to provide custom
// JSON deserialization of the MsgCreateValidator type.
func (msg *MsgCreateValidator) UnmarshalJSON(bz []byte) error {
var msgCreateValJSON msgCreateValidatorJSON
if err := json.Unmarshal(bz, &msgCreateValJSON); err != nil {
return err
}
msg.Description = msgCreateValJSON.Description
msg.Commission = msgCreateValJSON.Commission
msg.MinSelfDelegation = msgCreateValJSON.MinSelfDelegation
msg.StakingAddress = msgCreateValJSON.StakingAddress
msg.ValidatingPubKey = msgCreateValJSON.ValidatingPubKey
msg.Amount = msgCreateValJSON.Amount
return nil
}
// ValidateBasic quick validity check
func (msg MsgCreateValidator) ValidateBasic() error {
// note that unmarshaling from bech32 ensures either empty or valid
if msg.StakingAddress.Big().Uint64() == 0 {
return errors.New("[CreateValidator] address is empty")
}
emptyKey := shard.BlsPublicKey{}
if bytes.Compare(msg.ValidatingPubKey[:], emptyKey[:]) == 0 {
return errors.New("[CreateValidator] invalid BLS public key")
}
if msg.Description == (Description{}) {
return errors.New("[CreateValidator] description must be included")
}
if msg.Commission == (CommissionRates{}) {
return errors.New("[CreateValidator] commission must be included")
}
if msg.Amount.Cmp(msg.MinSelfDelegation) > 0 {
return errors.New("[CreateValidator] stake amount must be >= MinSelfDelegation")
}
return nil
}
// MsgEditValidator - struct for editing a validator
type MsgEditValidator struct {
Description
StakingAddress common.Address `json:"staking_address" yaml:"staking_address"`
CommissionRate Dec `json:"commission_rate" yaml:"commission_rate"`
MinSelfDelegation *big.Int `json:"min_self_delegation" yaml:"min_self_delegation"`
}
// MsgEditValidatorJSON - struct for editing a validator for JSON
type MsgEditValidatorJSON struct {
Description
StakingAddress common.Address `json:"staking_address" yaml:"staking_address"`
// TODO: allow update of bls public key
CommissionRate Dec `json:"commission_rate" yaml:"commission_rate"`
MinSelfDelegation *big.Int `json:"min_self_delegation" yaml:"min_self_delegation"`
}
// NewMsgEditValidator creates a new MsgEditValidator.
func NewMsgEditValidator(
description Description, stakingAddress common.Address, commissionRate Dec, minSelfDelegation *big.Int) MsgEditValidator {
return MsgEditValidator{
Description: description,
StakingAddress: stakingAddress,
CommissionRate: commissionRate,
MinSelfDelegation: minSelfDelegation,
}
}
// Type ...
func (msg MsgEditValidator) Type() string { return "edit_validator" }
// Signer ...
func (msg MsgEditValidator) Signer() common.Address { return msg.StakingAddress }
// MsgDelegate - struct for bonding transactions
type MsgDelegate struct {
DelegatorAddress common.Address `json:"delegator_address" yaml:"delegator_address"`
ValidatorAddress common.Address `json:"validator_address" yaml:"validator_address"`
Amount *big.Int `json:"amount" yaml:"amount"`
}
// NewMsgDelegate creates a new MsgDelegate.
func NewMsgDelegate(
validatorAddress common.Address, delegatorAddress common.Address, amount *big.Int) MsgDelegate {
return MsgDelegate{
DelegatorAddress: delegatorAddress,
ValidatorAddress: validatorAddress,
Amount: amount,
}
}
// Type ...
func (msg MsgDelegate) Type() string { return "delegate" }
// Signer ...
func (msg MsgDelegate) Signer() common.Address { return msg.DelegatorAddress }
// MsgRedelegate - struct for re-bonding transactions
type MsgRedelegate struct {
DelegatorAddress common.Address `json:"delegator_address" yaml:"delegator_address"`
ValidatorSrcAddress common.Address `json:"validator_src_address" yaml:"validator_src_address"`
ValidatorDstAddress common.Address `json:"validator_dst_address" yaml:"validator_dst_address"`
Amount *big.Int `json:"amount" yaml:"amount"`
}
// NewMsgRedelegate creates a new MsgRedelegate.
func NewMsgRedelegate(delAddr, valSrcAddr, valDstAddr common.Address, amount *big.Int) MsgRedelegate {
return MsgRedelegate{
DelegatorAddress: delAddr,
ValidatorSrcAddress: valSrcAddr,
ValidatorDstAddress: valDstAddr,
Amount: amount,
}
}
// MsgUndelegate - struct for unbonding transactions
type MsgUndelegate struct {
DelegatorAddress common.Address `json:"delegator_address" yaml:"delegator_address"`
ValidatorAddress common.Address `json:"validator_address" yaml:"validator_address"`
Amount *big.Int `json:"amount" yaml:"amount"`
}
// NewMsgUndelegate creates a new MsgUndelegate.
func NewMsgUndelegate(delAddr common.Address, valAddr common.Address, amount *big.Int) MsgUndelegate {
return MsgUndelegate{
DelegatorAddress: delAddr,
ValidatorAddress: valAddr,
Amount: amount,
}
}

@ -0,0 +1,217 @@
package types
import (
"github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/shard"
"math/big"
"reflect"
"testing"
)
var (
minSelfDelegation = big.NewInt(1000)
stakeAmount = big.NewInt(2000)
delegateAmount = big.NewInt(500)
validatorAddress = common.MustBech32ToAddress("one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy")
validatorAddress2 = common.MustBech32ToAddress("one1d2rngmem4x2c6zxsjjz29dlah0jzkr0k2n88wc")
delegatorAddress = common.MustBech32ToAddress("one16qsd5ant9v94jrs89mruzx62h7ekcfxmduh2rx")
blsPubKey = bls.RandPrivateKey().GetPublicKey()
)
func TestMsgCreateValidatorRLP(t *testing.T) {
commissionRate := NewDecWithPrec(1, 2) // 10%
maxRate := NewDecWithPrec(2, 2) // 20%
maxChangeRate := NewDecWithPrec(1, 3) // 1%
blsPublickey := shard.BlsPublicKey{}
blsPublickey.FromLibBLSPublicKey(blsPubKey)
msgCreateValidator := NewMsgCreateValidator(Description{
Name: "validator 1",
Identity: "1",
Website: "harmony.one",
SecurityContact: "11.111.1111",
Details: "the best validator ever",
}, CommissionRates{
Rate: commissionRate,
MaxRate: maxRate,
MaxChangeRate: maxChangeRate,
}, minSelfDelegation, validatorAddress, blsPublickey, stakeAmount)
rlpBytes, err := rlp.EncodeToBytes(msgCreateValidator)
if err != nil {
t.Error("failed to rlp encode 'create validator' message")
}
decodedMsg := &MsgCreateValidator{}
err = rlp.DecodeBytes(rlpBytes, decodedMsg)
if err != nil {
t.Error("failed to rlp decode 'create validator' message")
}
if !decodedMsg.Commission.Rate.Equal(msgCreateValidator.Commission.Rate) {
t.Error("Commission rate does not match")
}
if !decodedMsg.Commission.MaxRate.Equal(msgCreateValidator.Commission.MaxRate) {
t.Error("MaxRate does not match")
}
if !decodedMsg.Commission.MaxChangeRate.Equal(msgCreateValidator.Commission.MaxChangeRate) {
t.Error("MaxChangeRate does not match")
}
if !reflect.DeepEqual(decodedMsg.Description, msgCreateValidator.Description) {
t.Error("Description does not match")
}
if decodedMsg.MinSelfDelegation.Cmp(msgCreateValidator.MinSelfDelegation) != 0 {
t.Error("MinSelfDelegation does not match")
}
if decodedMsg.StakingAddress.Hex() != msgCreateValidator.StakingAddress.Hex() {
t.Error("StakingAddress does not match")
}
if shard.CompareBlsPublicKey(decodedMsg.ValidatingPubKey, msgCreateValidator.ValidatingPubKey) != 0 {
t.Error("ValidatingPubKey does not match")
}
if decodedMsg.Amount.Cmp(msgCreateValidator.Amount) != 0 {
t.Error("Amount does not match")
}
}
func TestMsgEditValidatorRLP(t *testing.T) {
commissionRate := NewDecWithPrec(1, 2) // 10%
blsPublickey := shard.BlsPublicKey{}
blsPublickey.FromLibBLSPublicKey(blsPubKey)
msgEditValidator := NewMsgEditValidator(Description{
Name: "validator 1",
Identity: "1",
Website: "harmony.one",
SecurityContact: "11.111.1111",
Details: "the best validator ever",
}, validatorAddress, commissionRate, minSelfDelegation)
rlpBytes, err := rlp.EncodeToBytes(msgEditValidator)
if err != nil {
t.Error("failed to rlp encode 'create validator' message")
}
decodedMsg := &MsgEditValidator{}
err = rlp.DecodeBytes(rlpBytes, decodedMsg)
if err != nil {
t.Error("failed to rlp decode 'create validator' message")
}
if !reflect.DeepEqual(decodedMsg.Description, msgEditValidator.Description) {
t.Error("Description does not match")
}
if decodedMsg.StakingAddress.Hex() != msgEditValidator.StakingAddress.Hex() {
t.Error("StakingAddress does not match")
}
if !decodedMsg.CommissionRate.Equal(msgEditValidator.CommissionRate) {
t.Error("Commission rate does not match")
}
if decodedMsg.MinSelfDelegation.Cmp(msgEditValidator.MinSelfDelegation) != 0 {
t.Error("MinSelfDelegation does not match")
}
}
func TestMsgDelegateRLP(t *testing.T) {
msgDelegate := NewMsgDelegate(delegatorAddress, validatorAddress, delegateAmount)
rlpBytes, err := rlp.EncodeToBytes(msgDelegate)
if err != nil {
t.Error("failed to rlp encode 'create validator' message")
}
decodedMsg := &MsgDelegate{}
err = rlp.DecodeBytes(rlpBytes, decodedMsg)
if err != nil {
t.Error("failed to rlp decode 'create validator' message")
}
if decodedMsg.DelegatorAddress.Hex() != msgDelegate.DelegatorAddress.Hex() {
t.Error("DelegatorAddress does not match")
}
if decodedMsg.ValidatorAddress.Hex() != msgDelegate.ValidatorAddress.Hex() {
t.Error("ValidatorAddress does not match")
}
if decodedMsg.Amount.Cmp(msgDelegate.Amount) != 0 {
t.Error("Amount does not match")
}
}
func TestMsgRedelegateRLP(t *testing.T) {
msgRedelegate := NewMsgRedelegate(delegatorAddress, validatorAddress, validatorAddress2, delegateAmount)
rlpBytes, err := rlp.EncodeToBytes(msgRedelegate)
if err != nil {
t.Error("failed to rlp encode 'create validator' message")
}
decodedMsg := &MsgRedelegate{}
err = rlp.DecodeBytes(rlpBytes, decodedMsg)
if err != nil {
t.Error("failed to rlp decode 'create validator' message")
}
if decodedMsg.DelegatorAddress.Hex() != msgRedelegate.DelegatorAddress.Hex() {
t.Error("DelegatorAddress does not match")
}
if decodedMsg.ValidatorSrcAddress.Hex() != msgRedelegate.ValidatorSrcAddress.Hex() {
t.Error("ValidatorSrcAddress does not match")
}
if decodedMsg.ValidatorDstAddress.Hex() != msgRedelegate.ValidatorDstAddress.Hex() {
t.Error("ValidatorDstAddress does not match")
}
if decodedMsg.Amount.Cmp(msgRedelegate.Amount) != 0 {
t.Error("Amount does not match")
}
}
func TestMsgUndelegateRLP(t *testing.T) {
msgUndelegate := NewMsgUndelegate(delegatorAddress, validatorAddress, delegateAmount)
rlpBytes, err := rlp.EncodeToBytes(msgUndelegate)
if err != nil {
t.Error("failed to rlp encode 'create validator' message")
}
decodedMsg := &MsgUndelegate{}
err = rlp.DecodeBytes(rlpBytes, decodedMsg)
if err != nil {
t.Error("failed to rlp decode 'create validator' message")
}
if decodedMsg.DelegatorAddress.Hex() != msgUndelegate.DelegatorAddress.Hex() {
t.Error("DelegatorAddress does not match")
}
if decodedMsg.ValidatorAddress.Hex() != msgUndelegate.ValidatorAddress.Hex() {
t.Error("ValidatorAddress does not match")
}
if decodedMsg.Amount.Cmp(msgUndelegate.Amount) != 0 {
t.Error("Amount does not match")
}
}
Loading…
Cancel
Save