mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-28 17:25:19 +00:00
486 lines
14 KiB
Go
486 lines
14 KiB
Go
package staking_test
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"math/big"
|
|
"time"
|
|
|
|
"cosmossdk.io/math"
|
|
stakingprecompile "github.com/0glabs/0g-chain/precompiles/staking"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/evmos/ethermint/x/evm/statedb"
|
|
)
|
|
|
|
func (s *StakingTestSuite) TestCreateValidator() {
|
|
method := stakingprecompile.StakingFunctionCreateValidator
|
|
description := stakingprecompile.Description{
|
|
Moniker: "test node",
|
|
Identity: "test node identity",
|
|
Website: "http://test.node.com",
|
|
SecurityContact: "test node security contract",
|
|
Details: "test node details",
|
|
}
|
|
commission := stakingprecompile.CommissionRates{
|
|
Rate: math.LegacyOneDec().BigInt(),
|
|
MaxRate: math.LegacyOneDec().BigInt(),
|
|
MaxChangeRate: math.LegacyOneDec().BigInt(),
|
|
}
|
|
minSelfDelegation := big.NewInt(1)
|
|
pubkey := "eh/aR8BGUBIYI/Ust0NVBxZafLDAm7344F9dKzZU+7g="
|
|
value := big.NewInt(100000000)
|
|
|
|
testCases := []struct {
|
|
name string
|
|
malleate func() []byte
|
|
gas uint64
|
|
callerAddress *common.Address
|
|
postCheck func(data []byte)
|
|
expError bool
|
|
errContains string
|
|
}{
|
|
{
|
|
"fail - ErrPubKeyInvalidLength",
|
|
func() []byte {
|
|
input, err := s.abi.Pack(
|
|
method,
|
|
description,
|
|
commission,
|
|
minSelfDelegation,
|
|
s.signerOne.HexAddr,
|
|
value,
|
|
)
|
|
s.Assert().NoError(err)
|
|
return input
|
|
},
|
|
200000,
|
|
nil,
|
|
func([]byte) {},
|
|
true,
|
|
stakingprecompile.ErrPubKeyInvalidLength,
|
|
},
|
|
{
|
|
"success",
|
|
func() []byte {
|
|
input, err := s.abi.Pack(
|
|
method,
|
|
description,
|
|
commission,
|
|
minSelfDelegation,
|
|
pubkey,
|
|
value,
|
|
)
|
|
s.Assert().NoError(err)
|
|
return input
|
|
},
|
|
200000,
|
|
nil,
|
|
func(data []byte) {},
|
|
false,
|
|
"",
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
s.Run(tc.name, func() {
|
|
s.SetupTest()
|
|
|
|
bz, err := s.runTx(tc.malleate(), s.signerOne, 10000000)
|
|
s.stakingKeeper.ApplyAndReturnValidatorSetUpdates(s.Ctx)
|
|
|
|
if tc.expError {
|
|
s.Require().ErrorContains(err, tc.errContains)
|
|
s.Require().Empty(bz)
|
|
} else {
|
|
s.Require().NoError(err)
|
|
// query the validator in the staking keeper
|
|
validator := s.StakingKeeper.Validator(s.Ctx, s.signerOne.ValAddr)
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().NotNil(validator, "expected validator not to be nil")
|
|
tc.postCheck(bz)
|
|
|
|
isBonded := validator.IsBonded()
|
|
s.Require().Equal(true, isBonded, "expected validator bonded to be %t; got %t", true, isBonded)
|
|
|
|
consPubKey, err := validator.ConsPubKey()
|
|
s.Require().NoError(err)
|
|
consPubKeyBase64 := base64.StdEncoding.EncodeToString(consPubKey.Bytes())
|
|
s.Require().Equal(pubkey, consPubKeyBase64, "expected validator pubkey to be %s; got %s", pubkey, consPubKeyBase64)
|
|
|
|
operator := validator.GetOperator()
|
|
s.Require().Equal(s.signerOne.ValAddr, operator, "expected validator operator to be %s; got %s", s.signerOne.ValAddr, operator)
|
|
|
|
commissionRate := validator.GetCommission()
|
|
s.Require().Equal(commission.Rate.String(), commissionRate.BigInt().String(), "expected validator commission rate to be %s; got %s", commission.Rate.String(), commissionRate.String())
|
|
|
|
valMinSelfDelegation := validator.GetMinSelfDelegation()
|
|
s.Require().Equal(minSelfDelegation.String(), valMinSelfDelegation.String(), "expected validator min self delegation to be %s; got %s", minSelfDelegation.String(), valMinSelfDelegation.String())
|
|
|
|
moniker := validator.GetMoniker()
|
|
s.Require().Equal(description.Moniker, moniker, "expected validator moniker to be %s; got %s", description.Moniker, moniker)
|
|
|
|
jailed := validator.IsJailed()
|
|
s.Require().Equal(false, jailed, "expected validator jailed to be %t; got %t", false, jailed)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func (s *StakingTestSuite) TestEditValidator() {
|
|
method := stakingprecompile.StakingFunctionEditValidator
|
|
description := stakingprecompile.Description{
|
|
Moniker: "test node",
|
|
Identity: "test node identity",
|
|
Website: "http://test.node.com",
|
|
SecurityContact: "test node security contract",
|
|
Details: "test node details",
|
|
}
|
|
newRate := math.LegacyOneDec().BigInt()
|
|
newRate.Div(newRate, big.NewInt(2))
|
|
minSelfDelegation := big.NewInt(2)
|
|
|
|
testCases := []struct {
|
|
name string
|
|
malleate func() []byte
|
|
gas uint64
|
|
callerAddress *common.Address
|
|
postCheck func(data []byte)
|
|
expError bool
|
|
errContains string
|
|
}{
|
|
{
|
|
"success",
|
|
func() []byte {
|
|
input, err := s.abi.Pack(
|
|
method,
|
|
description,
|
|
stakingprecompile.NullableUint{
|
|
IsNull: false,
|
|
Value: newRate,
|
|
},
|
|
stakingprecompile.NullableUint{
|
|
IsNull: true,
|
|
Value: math.LegacyOneDec().BigInt(),
|
|
},
|
|
)
|
|
s.Assert().NoError(err)
|
|
return input
|
|
},
|
|
200000,
|
|
nil,
|
|
func(data []byte) {},
|
|
false,
|
|
"",
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
s.Run(tc.name, func() {
|
|
s.SetupTest()
|
|
s.setupValidator(s.signerOne)
|
|
// move block time forward
|
|
s.Ctx = s.Ctx.WithBlockTime(time.Now().Add(time.Hour * 100))
|
|
s.Statedb = statedb.New(s.Ctx, s.EvmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(s.Ctx.HeaderHash().Bytes())))
|
|
|
|
bz, err := s.runTx(tc.malleate(), s.signerOne, 10000000)
|
|
|
|
if tc.expError {
|
|
s.Require().ErrorContains(err, tc.errContains)
|
|
s.Require().Empty(bz)
|
|
} else {
|
|
s.Require().NoError(err)
|
|
// query the validator in the staking keeper
|
|
validator := s.StakingKeeper.Validator(s.Ctx, s.signerOne.ValAddr)
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().NotNil(validator, "expected validator not to be nil")
|
|
tc.postCheck(bz)
|
|
|
|
isBonded := validator.IsBonded()
|
|
s.Require().Equal(true, isBonded, "expected validator bonded to be %t; got %t", false, isBonded)
|
|
|
|
operator := validator.GetOperator()
|
|
s.Require().Equal(s.signerOne.ValAddr, operator, "expected validator operator to be %s; got %s", s.signerOne.ValAddr, operator)
|
|
|
|
commissionRate := validator.GetCommission()
|
|
s.Require().Equal(newRate.String(), commissionRate.BigInt().String(), "expected validator commission rate to be %s; got %s", newRate.String(), commissionRate.String())
|
|
|
|
valMinSelfDelegation := validator.GetMinSelfDelegation()
|
|
s.Require().Equal(big.NewInt(1).String(), valMinSelfDelegation.String(), "expected validator min self delegation to be %s; got %s", minSelfDelegation.String(), valMinSelfDelegation.String())
|
|
|
|
moniker := validator.GetMoniker()
|
|
s.Require().Equal(description.Moniker, moniker, "expected validator moniker to be %s; got %s", description.Moniker, moniker)
|
|
|
|
jailed := validator.IsJailed()
|
|
s.Require().Equal(false, jailed, "expected validator jailed to be %t; got %t", false, jailed)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func (s *StakingTestSuite) TestDelegate() {
|
|
method := stakingprecompile.StakingFunctionDelegate
|
|
|
|
testCases := []struct {
|
|
name string
|
|
malleate func(valAddr string) []byte
|
|
gas uint64
|
|
callerAddress *common.Address
|
|
postCheck func(valAddr sdk.ValAddress)
|
|
expError bool
|
|
errContains string
|
|
}{
|
|
{
|
|
"success",
|
|
func(valAddr string) []byte {
|
|
input, err := s.abi.Pack(
|
|
method,
|
|
valAddr,
|
|
big.NewInt(1000000),
|
|
)
|
|
s.Assert().NoError(err)
|
|
return input
|
|
},
|
|
200000,
|
|
nil,
|
|
func(valAddr sdk.ValAddress) {
|
|
d, found := s.stakingKeeper.GetDelegation(s.Ctx, s.signerOne.AccAddr, valAddr)
|
|
s.Assert().EqualValues(found, true)
|
|
s.Assert().EqualValues(d.ValidatorAddress, valAddr.String())
|
|
s.Assert().EqualValues(d.DelegatorAddress, s.signerOne.AccAddr.String())
|
|
|
|
// jsonData, _ := json.MarshalIndent(d, "", " ")
|
|
// fmt.Printf("delegation: %s\n", string(jsonData))
|
|
},
|
|
false,
|
|
"",
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
s.Run(tc.name, func() {
|
|
s.SetupTest()
|
|
|
|
operatorAddress, err := s.firstBondedValidator()
|
|
s.Require().NoError(err)
|
|
|
|
bz, err := s.runTx(tc.malleate(operatorAddress.String()), s.signerOne, 10000000)
|
|
|
|
if tc.expError {
|
|
s.Require().ErrorContains(err, tc.errContains)
|
|
s.Require().Empty(bz)
|
|
} else {
|
|
s.Require().NoError(err)
|
|
tc.postCheck(operatorAddress)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func (s *StakingTestSuite) TestBeginRedelegate() {
|
|
method := stakingprecompile.StakingFunctionBeginRedelegate
|
|
|
|
testCases := []struct {
|
|
name string
|
|
malleate func(srcAddr, dstAddr string) []byte
|
|
gas uint64
|
|
callerAddress *common.Address
|
|
postCheck func(data []byte, srcAddr, dstAddr sdk.ValAddress)
|
|
expError bool
|
|
errContains string
|
|
}{
|
|
{
|
|
"success",
|
|
func(srcAddr, dstAddr string) []byte {
|
|
input, err := s.abi.Pack(
|
|
method,
|
|
srcAddr,
|
|
dstAddr,
|
|
big.NewInt(1000000),
|
|
)
|
|
s.Assert().NoError(err)
|
|
return input
|
|
},
|
|
200000,
|
|
nil,
|
|
func(data []byte, srcAddr, dstAddr sdk.ValAddress) {
|
|
out, err := s.abi.Methods[method].Outputs.Unpack(data)
|
|
s.Require().NoError(err, "failed to unpack output")
|
|
|
|
d, found := s.stakingKeeper.GetRedelegation(s.Ctx, s.signerOne.AccAddr, srcAddr, dstAddr)
|
|
s.Assert().EqualValues(found, true)
|
|
s.Assert().EqualValues(d.DelegatorAddress, s.signerOne.AccAddr.String())
|
|
s.Assert().EqualValues(d.ValidatorSrcAddress, srcAddr.String())
|
|
s.Assert().EqualValues(d.ValidatorDstAddress, dstAddr.String())
|
|
|
|
completionTime := out[0].(*big.Int)
|
|
params := s.stakingKeeper.GetParams(s.Ctx)
|
|
s.Assert().EqualValues(completionTime.Int64(), s.Ctx.BlockHeader().Time.Add(params.UnbondingTime).UTC().Unix())
|
|
// jsonData, _ := json.MarshalIndent(d, "", " ")
|
|
// fmt.Printf("redelegation: %s\n", string(jsonData))
|
|
},
|
|
false,
|
|
"",
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
s.Run(tc.name, func() {
|
|
s.SetupTest()
|
|
operatorAddress, err := s.firstBondedValidator()
|
|
s.Require().NoError(err)
|
|
|
|
// move block time forward
|
|
s.Ctx = s.Ctx.WithBlockTime(time.Now().Add(time.Hour * 100))
|
|
s.Statedb = statedb.New(s.Ctx, s.EvmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(s.Ctx.HeaderHash().Bytes())))
|
|
|
|
s.setupValidator(s.signerOne)
|
|
|
|
bz, err := s.runTx(tc.malleate(s.signerOne.ValAddr.String(), operatorAddress.String()), s.signerOne, 10000000)
|
|
|
|
if tc.expError {
|
|
s.Require().ErrorContains(err, tc.errContains)
|
|
s.Require().Empty(bz)
|
|
} else {
|
|
s.Require().NoError(err)
|
|
tc.postCheck(bz, s.signerOne.ValAddr, operatorAddress)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func (s *StakingTestSuite) TestUndelegate() {
|
|
method := stakingprecompile.StakingFunctionUndelegate
|
|
|
|
testCases := []struct {
|
|
name string
|
|
malleate func(valAddr string) []byte
|
|
gas uint64
|
|
callerAddress *common.Address
|
|
postCheck func(data []byte, valAddr sdk.ValAddress)
|
|
expError bool
|
|
errContains string
|
|
}{
|
|
{
|
|
"success",
|
|
func(valAddr string) []byte {
|
|
input, err := s.abi.Pack(
|
|
method,
|
|
valAddr,
|
|
big.NewInt(1000000),
|
|
)
|
|
s.Assert().NoError(err)
|
|
return input
|
|
},
|
|
200000,
|
|
nil,
|
|
func(data []byte, valAddr sdk.ValAddress) {
|
|
out, err := s.abi.Methods[method].Outputs.Unpack(data)
|
|
s.Require().NoError(err, "failed to unpack output")
|
|
|
|
d, found := s.stakingKeeper.GetUnbondingDelegation(s.Ctx, s.signerOne.AccAddr, valAddr)
|
|
s.Assert().EqualValues(found, true)
|
|
s.Assert().EqualValues(d.DelegatorAddress, s.signerOne.AccAddr.String())
|
|
s.Assert().EqualValues(d.ValidatorAddress, valAddr.String())
|
|
|
|
completionTime := out[0].(*big.Int)
|
|
params := s.stakingKeeper.GetParams(s.Ctx)
|
|
s.Assert().EqualValues(completionTime.Int64(), s.Ctx.BlockHeader().Time.Add(params.UnbondingTime).UTC().Unix())
|
|
// jsonData, _ := json.MarshalIndent(d, "", " ")
|
|
// fmt.Printf("redelegation: %s\n", string(jsonData))
|
|
},
|
|
false,
|
|
"",
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
s.Run(tc.name, func() {
|
|
s.SetupTest()
|
|
|
|
// move block time forward
|
|
s.Ctx = s.Ctx.WithBlockTime(time.Now().Add(time.Hour * 100))
|
|
s.Statedb = statedb.New(s.Ctx, s.EvmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(s.Ctx.HeaderHash().Bytes())))
|
|
|
|
s.setupValidator(s.signerOne)
|
|
|
|
bz, err := s.runTx(tc.malleate(s.signerOne.ValAddr.String()), s.signerOne, 10000000)
|
|
|
|
if tc.expError {
|
|
s.Require().ErrorContains(err, tc.errContains)
|
|
s.Require().Empty(bz)
|
|
} else {
|
|
s.Require().NoError(err)
|
|
tc.postCheck(bz, s.signerOne.ValAddr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func (s *StakingTestSuite) TestCancelUnbondingDelegation() {
|
|
method := stakingprecompile.StakingFunctionCancelUnbondingDelegation
|
|
|
|
testCases := []struct {
|
|
name string
|
|
malleate func(valAddr string, height *big.Int) []byte
|
|
gas uint64
|
|
callerAddress *common.Address
|
|
postCheck func(valAddr sdk.ValAddress)
|
|
expError bool
|
|
errContains string
|
|
}{
|
|
{
|
|
"success",
|
|
func(valAddr string, height *big.Int) []byte {
|
|
input, err := s.abi.Pack(
|
|
method,
|
|
valAddr,
|
|
big.NewInt(1),
|
|
height,
|
|
)
|
|
s.Assert().NoError(err)
|
|
return input
|
|
},
|
|
200000,
|
|
nil,
|
|
func(valAddr sdk.ValAddress) {
|
|
_, found := s.stakingKeeper.GetUnbondingDelegation(s.Ctx, s.signerOne.AccAddr, valAddr)
|
|
s.Assert().EqualValues(found, false)
|
|
// jsonData, _ := json.MarshalIndent(d, "", " ")
|
|
// fmt.Printf("redelegation: %s\n", string(jsonData))
|
|
},
|
|
false,
|
|
"",
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
s.Run(tc.name, func() {
|
|
s.SetupTest()
|
|
|
|
// move block time forward
|
|
s.Ctx = s.Ctx.WithBlockTime(time.Now().Add(time.Hour * 100))
|
|
s.Statedb = statedb.New(s.Ctx, s.EvmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(s.Ctx.HeaderHash().Bytes())))
|
|
|
|
s.setupValidator(s.signerOne)
|
|
// unbond
|
|
_, err := s.stakingKeeper.Undelegate(s.Ctx, s.signerOne.AccAddr, s.signerOne.ValAddr, sdk.NewDec(1))
|
|
s.Require().NoError(err)
|
|
|
|
u, _ := s.stakingKeeper.GetUnbondingDelegation(s.Ctx, s.signerOne.AccAddr, s.signerOne.ValAddr)
|
|
height := u.Entries[0].CreationHeight
|
|
|
|
bz, err := s.runTx(tc.malleate(s.signerOne.ValAddr.String(), big.NewInt(height)), s.signerOne, 10000000)
|
|
|
|
if tc.expError {
|
|
s.Require().ErrorContains(err, tc.errContains)
|
|
s.Require().Empty(bz)
|
|
} else {
|
|
s.Require().NoError(err)
|
|
tc.postCheck(s.signerOne.ValAddr)
|
|
}
|
|
})
|
|
}
|
|
}
|