2024-10-29 11:29:44 +00:00
package staking_test
import (
"encoding/base64"
"math/big"
2024-11-04 11:01:53 +00:00
"time"
2024-10-29 11:29:44 +00:00
"cosmossdk.io/math"
stakingprecompile "github.com/0glabs/0g-chain/precompiles/staking"
2024-11-04 11:01:53 +00:00
sdk "github.com/cosmos/cosmos-sdk/types"
2024-10-29 11:29:44 +00:00
"github.com/ethereum/go-ethereum/common"
2024-11-04 11:01:53 +00:00
"github.com/evmos/ethermint/x/evm/statedb"
2024-10-29 11:29:44 +00:00
)
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 )
2024-11-04 11:01:53 +00:00
s . stakingKeeper . ApplyAndReturnValidatorSetUpdates ( s . Ctx )
2024-10-29 11:29:44 +00:00
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 ( )
2024-11-04 11:01:53 +00:00
s . Require ( ) . Equal ( true , isBonded , "expected validator bonded to be %t; got %t" , true , isBonded )
2024-10-29 11:29:44 +00:00
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 )
}
} )
}
}
2024-11-04 11:01:53 +00:00
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 )
}
} )
}
}