Skip to content

Commit

Permalink
Add test for mint
Browse files Browse the repository at this point in the history
  • Loading branch information
p-offtermatt committed Jul 19, 2024
1 parent f44dcdf commit 22852ce
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 4 deletions.
13 changes: 11 additions & 2 deletions docs/docs/adrs/adr-017-allowing-inactive-validators.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,17 @@ Checked as part of the e2e test `inactive-vals-topN`.

To compute the inflation rate, only the active validators should be considered.

We can check this by querying the inflation rate from the mint module twice:
Once with all validators active, and once with a lot of stake inactive.
We can check this by querying the inflation rate change over subsequent blocks.

We start a provider chain with these arguments
* 3 validators with powers alice=290, bob=280, charlie=270
* either 1 or 3 active validators
* a bonded goal of 300 tokens (this is given in percent, but we simplify here)

If we have 3 validators active, then the inflation rate should *decrease* between blocks, because the bonded goal is exceeded as all validators are bonded.
If we have only 1 validator active, then the inflation rate should *increase* between blocks, because the bonded goal is not met.

Checked as part of the e2e tests `inactive-vals-mint` (scenario with 1 active val) and `mint-basecase` (scenario with 3 active vals).

### Scenarios 8: Inactive validators can validate on consumer chains

Expand Down
33 changes: 33 additions & 0 deletions tests/e2e/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ const (
InactiveProviderValsTestCfg TestConfigType = "inactive-provider-vals"
GovTestCfg TestConfigType = "gov"
InactiveValsGovTestCfg TestConfigType = "inactive-vals-gov"
InactiveValsMintTestCfg TestConfigType = "inactive-vals-mint"
MintTestCfg TestConfigType = "mint"
)

type TestConfig struct {
Expand Down Expand Up @@ -189,6 +191,10 @@ func GetTestConfig(cfgType TestConfigType, providerVersion, consumerVersion stri
testCfg = GovTestConfig()
case InactiveValsGovTestCfg:
testCfg = InactiveValsGovTestConfig()
case InactiveValsMintTestCfg:
testCfg = InactiveValsMintTestConfig()
case MintTestCfg:
testCfg = MintTestConfig()
default:
panic(fmt.Sprintf("Invalid test config: %s", cfgType))
}
Expand Down Expand Up @@ -630,6 +636,33 @@ func InactiveValsGovTestConfig() TestConfig {
return cfg
}

func MintTestConfig() TestConfig {
cfg := GovTestConfig()
AdjustMint(cfg)

return cfg
}

func InactiveValsMintTestConfig() TestConfig {
cfg := InactiveValsGovTestConfig()
AdjustMint(cfg)

return cfg
}

// AdjustMint adjusts the mint parameters to have a very low goal bonded amount
// and a high inflation rate change
func AdjustMint(cfg TestConfig) {
proviConfig := cfg.chainConfigs[ChainID("provi")]
// total supply is 30000000000stake; we want to set the mint bonded goal to
// a small fraction of that
proviConfig.GenesisChanges += "| .app_state.mint.params.goal_bonded = \"0.001\"" +
"| .app_state.mint.params.inflation_rate_change = \"1\"" +
"| .app_state.mint.params.inflation_max = \"0.5\"" +
"| .app_state.mint.params.inflation_min = \"0.1\""
cfg.chainConfigs[ChainID("provi")] = proviConfig
}

func MultiConsumerTestConfig() TestConfig {
tr := TestConfig{
name: string(MulticonsumerTestCfg),
Expand Down
14 changes: 14 additions & 0 deletions tests/e2e/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,18 @@ var stepChoices = map[string]StepChoice{
description: "checks that the min stake parameter for consumer chains is respected",
testConfig: GovTestCfg, // see above: we reuse the GovTestCfg for convenience
},
"inactive-vals-mint": {
name: "inactive-vals-mint",
steps: stepsInactiveValsMint(),
description: "test minting with inactive validators",
testConfig: InactiveValsMintTestCfg,
},
"mint-basecase": {
name: "mint-basecase",
steps: stepsMintBasecase(),
description: "test minting without inactive validators as a sanity check",
testConfig: MintTestCfg,
},
}

func getTestCaseUsageString() string {
Expand Down Expand Up @@ -330,6 +342,8 @@ func getTestCases(selectedPredefinedTests, selectedTestFiles TestSet, providerVe
"partial-set-security-validators-allowlisted", "partial-set-security-validators-denylisted",
"partial-set-security-modification-proposal",
"active-set-changes", "inactive-vals-topN",
"inactive-provider-validators-on-consumer", "inactive-provider-validators-governance",
"max-rank", "min-stake", "inactive-vals-mint",
}
if includeMultiConsumer != nil && *includeMultiConsumer {
selectedPredefinedTests = append(selectedPredefinedTests, "multiconsumer")
Expand Down
44 changes: 44 additions & 0 deletions tests/e2e/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,29 @@ func (tr Chain) GetChainState(chain ChainID, modelState ChainState) ChainState {
chainState.HasToValidate = &hasToValidate
}

if modelState.InflationRateChange != nil {
// get the inflation rate now
inflationRateNow := tr.target.GetInflationRate(chain)

// wait a block
tr.waitBlocks(chain, 1, 10*time.Second)

// get the new inflation rate
inflationRateAfter := tr.target.GetInflationRate(chain)

// calculate the change
inflationRateChange := inflationRateAfter - inflationRateNow
var inflationRateChangeDirection int
if inflationRateChange > 0 {
inflationRateChangeDirection = 1
} else if inflationRateChange < 0 {
inflationRateChangeDirection = -1
} else {
inflationRateChangeDirection = 0
}
chainState.InflationRateChange = &inflationRateChangeDirection
}

if modelState.ConsumerPendingPacketQueueSize != nil {
pendingPacketQueueSize := tr.target.GetPendingPacketQueueSize(chain)
chainState.ConsumerPendingPacketQueueSize = &pendingPacketQueueSize
Expand Down Expand Up @@ -302,6 +325,10 @@ func uintPtr(i uint) *uint {
return &i
}

func intPtr(i int) *int {
return &i
}

type Commands struct {
containerConfig ContainerConfig // FIXME only needed for 'Now' time tracking
validatorConfigs map[ValidatorID]ValidatorConfig
Expand Down Expand Up @@ -867,6 +894,23 @@ func (tr Commands) GetHasToValidate(
return chains
}

func (tr Commands) GetInflationRate(
chain ChainID,
) float64 {
binaryName := tr.chainConfigs[chain].BinaryName
bz, err := tr.target.ExecCommand(binaryName,
"query", "mint", "inflation",
`--node`, tr.GetQueryNode(chain),
`-o`, `json`,
).CombinedOutput()
if err != nil {
log.Fatal(err, "\n", string(bz))
}

inflationRate := gjson.Get(string(bz), "inflation").Float()
return inflationRate
}

func (tr Commands) GetTrustedHeight(
chain ChainID,
clientID string,
Expand Down
88 changes: 88 additions & 0 deletions tests/e2e/steps_inactive_vals.go
Original file line number Diff line number Diff line change
Expand Up @@ -976,3 +976,91 @@ func stepsInactiveValsWithTopN() []Step {
},
}
}

func stepsInactiveValsMint() []Step {
// total supply is 30000000000, bonded goal ratio makes it so we want 30000000 tokens bonded
return []Step{
{
Action: StartChainAction{
Chain: ChainID("provi"),
Validators: []StartChainValidator{
{Id: ValidatorID("alice"), Stake: 27000000, Allocation: 10000000000},
{Id: ValidatorID("bob"), Stake: 28000000, Allocation: 10000000000},
{Id: ValidatorID("carol"), Stake: 29000000, Allocation: 10000000000},
},
},
State: State{
ChainID("provi"): ChainState{
ValPowers: &map[ValidatorID]uint{
ValidatorID("alice"): 0,
ValidatorID("bob"): 0,
ValidatorID("carol"): 29, // other validators are not in power since only 1 can be active
},
InflationRateChange: intPtr(1), // inflation rate goes up because less than the goal is bonded, since only carol is active
},
},
},
{
Action: DelegateTokensAction{
Chain: ChainID("provi"),
From: ValidatorID("carol"),
To: ValidatorID("carol"),
Amount: 50000000,
},
State: State{
ChainID("provi"): ChainState{
ValPowers: &map[ValidatorID]uint{
ValidatorID("alice"): 0,
ValidatorID("bob"): 0,
ValidatorID("carol"): 79,
},
InflationRateChange: intPtr(-1), // inflation rate goes down now, because carol has more bonded than the goal
},
},
},
}
}

func stepsMintBasecase() []Step {
// total supply is 30000000000, bonded goal ratio makes it so we want 30000000 tokens bonded
return []Step{
{
Action: StartChainAction{
Chain: ChainID("provi"),
Validators: []StartChainValidator{
{Id: ValidatorID("alice"), Stake: 27000000, Allocation: 10000000000},
{Id: ValidatorID("bob"), Stake: 28000000, Allocation: 10000000000},
{Id: ValidatorID("carol"), Stake: 29000000, Allocation: 10000000000},
},
},
State: State{
ChainID("provi"): ChainState{
ValPowers: &map[ValidatorID]uint{
ValidatorID("alice"): 27,
ValidatorID("bob"): 28,
ValidatorID("carol"): 29,
},
InflationRateChange: intPtr(-1), // inflation rate goes down because more than the goal is bonded
},
},
},
{
Action: DelegateTokensAction{
Chain: ChainID("provi"),
From: ValidatorID("carol"),
To: ValidatorID("carol"),
Amount: 50000000,
},
State: State{
ChainID("provi"): ChainState{
ValPowers: &map[ValidatorID]uint{
ValidatorID("alice"): 28,
ValidatorID("bob"): 29,
ValidatorID("carol"): 79,
},
InflationRateChange: intPtr(-1), // inflation rate *still* goes down
},
},
},
}
}
3 changes: 2 additions & 1 deletion tests/e2e/testlib/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type ChainCommands interface {
GetValPower(chain ChainID, validator ValidatorID) uint
GetValStakedTokens(chain ChainID, validatorAddress string) uint
GetQueryNodeIP(chain ChainID) string
GetInflationRate(chain ChainID) float64
}

// TODO: replace ExecutionTarget with new TargetDriver interface
Expand Down Expand Up @@ -153,7 +154,6 @@ type ProposalAndType struct {
RawProposal json.RawMessage
Type string
}

type ChainState struct {
ValBalances *map[ValidatorID]uint
Proposals *map[uint]Proposal
Expand All @@ -170,6 +170,7 @@ type ChainState struct {
RegisteredConsumerRewardDenoms *[]string
ClientsFrozenHeights *map[string]clienttypes.Height
HasToValidate *map[ValidatorID][]ChainID // only relevant to provider chain
InflationRateChange *int // whether the inflation rate between two blocks changes negatively (any negative number), is equal (0), or changes positively (any positive number)
}

// custom marshal and unmarshal functions for the chainstate that convert proposals to/from the auxiliary type with type info
Expand Down
20 changes: 19 additions & 1 deletion tests/e2e/v4/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ func (tr Commands) GetBalance(chain ChainID, validator ValidatorID) uint {

// interchain-securityd query gov proposals
func (tr Commands) GetProposal(chain ChainID, proposal uint) Proposal {
var noProposalRegex = regexp.MustCompile(`doesn't exist: key not found`)
noProposalRegex := regexp.MustCompile(`doesn't exist: key not found`)

binaryName := tr.ChainConfigs[chain].BinaryName
bz, err := tr.Target.ExecCommand(binaryName,
Expand Down Expand Up @@ -411,6 +411,7 @@ func (tr Commands) GetConsumerChains(chain ChainID) map[ChainID]bool {

return chains
}

func (tr Commands) GetConsumerAddress(consumerChain ChainID, validator ValidatorID) string {
binaryName := tr.ChainConfigs[ChainID("provi")].BinaryName
cmd := tr.Target.ExecCommand(binaryName,
Expand Down Expand Up @@ -656,3 +657,20 @@ func (tr Commands) GetHasToValidate(validator ValidatorID) []ChainID {
func uintPtr(i uint) *uint {
return &i
}

func (tr Commands) GetInflationRate(
chain ChainID,
) float64 {
binaryName := tr.ChainConfigs[chain].BinaryName
bz, err := tr.Target.ExecCommand(binaryName,
"query", "mint", "inflation",
`--node`, tr.GetQueryNode(chain),
`-o`, `json`,
).CombinedOutput()
if err != nil {
log.Fatal(err, "\n", string(bz))
}

inflationRate := gjson.Get(string(bz), "inflation").Float()
return inflationRate
}

0 comments on commit 22852ce

Please sign in to comment.