From da84451ec092cdf31018ae1ebdac945ed74c17d7 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Tue, 3 Sep 2024 15:29:26 -0500 Subject: [PATCH 01/57] audit NewIntegrationApp usages --- tests/integration/gov/keeper/tally_test.go | 868 ++++++++++++++++----- tests/integration/v2-audit.md | 31 + 2 files changed, 721 insertions(+), 178 deletions(-) create mode 100644 tests/integration/v2-audit.md diff --git a/tests/integration/gov/keeper/tally_test.go b/tests/integration/gov/keeper/tally_test.go index f2b952076285..965b0ec29216 100644 --- a/tests/integration/gov/keeper/tally_test.go +++ b/tests/integration/gov/keeper/tally_test.go @@ -17,20 +17,26 @@ func TestTallyNoOneVotes(t *testing.T) { t.Parallel() f := initFixture(t) - ctx := f.ctx - createValidators(t, f, []int64{5, 5, 5}) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"), v1.ProposalType_PROPOSAL_TYPE_STANDARD) + proposal, err := f.govKeeper.SubmitProposal( + f.ctx, + tp, + "", + "test", + "description", + sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"), + v1.ProposalType_PROPOSAL_TYPE_STANDARD, + ) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) assert.NilError(t, err) - proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) + proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) assert.Assert(t, passes == false) assert.Assert(t, burnDeposits == false) @@ -42,25 +48,43 @@ func TestTallyNoQuorum(t *testing.T) { f := initFixture(t) - ctx := f.ctx - createValidators(t, f, []int64{2, 5, 0}) - addrs := simtestutil.AddTestAddrsIncremental(f.bankKeeper, f.stakingKeeper, ctx, 1, math.NewInt(10000000)) + addrs := simtestutil.AddTestAddrsIncremental( + f.bankKeeper, + f.stakingKeeper, + f.ctx, + 1, + math.NewInt(10000000), + ) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", addrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) + proposal, err := f.govKeeper.SubmitProposal( + f.ctx, + tp, + "", + "test", + "description", + addrs[0], + v1.ProposalType_PROPOSAL_TYPE_STANDARD, + ) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) assert.NilError(t, err) - err = f.govKeeper.AddVote(ctx, proposalID, addrs[0], v1.NewNonSplitVoteOption(v1.OptionYes), "") + err = f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[0], + v1.NewNonSplitVoteOption(v1.OptionYes), + "", + ) assert.NilError(t, err) - proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) + proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, _, _ := f.govKeeper.Tally(ctx, proposal) + passes, burnDeposits, _, _ := f.govKeeper.Tally(f.ctx, proposal) assert.Assert(t, passes == false) assert.Assert(t, burnDeposits == false) } @@ -70,24 +94,57 @@ func TestTallyOnlyValidatorsAllYes(t *testing.T) { f := initFixture(t) - ctx := f.ctx - addrs, _ := createValidators(t, f, []int64{5, 5, 5}) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", addrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) + proposal, err := f.govKeeper.SubmitProposal( + f.ctx, + tp, + "", + "test", + "description", + addrs[0], + v1.ProposalType_PROPOSAL_TYPE_STANDARD, + ) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[0], v1.NewNonSplitVoteOption(v1.OptionYes), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[1], v1.NewNonSplitVoteOption(v1.OptionYes), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[2], v1.NewNonSplitVoteOption(v1.OptionYes), "")) - - proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[0], + v1.NewNonSplitVoteOption(v1.OptionYes), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[1], + v1.NewNonSplitVoteOption(v1.OptionYes), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[2], + v1.NewNonSplitVoteOption(v1.OptionYes), + "", + ), + ) + + proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) assert.Assert(t, passes) assert.Assert(t, burnDeposits == false) @@ -99,23 +156,47 @@ func TestTallyOnlyValidators51No(t *testing.T) { f := initFixture(t) - ctx := f.ctx - valAccAddrs, _ := createValidators(t, f, []int64{5, 6, 0}) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", valAccAddrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) + proposal, err := f.govKeeper.SubmitProposal( + f.ctx, + tp, + "", + "test", + "description", + valAccAddrs[0], + v1.ProposalType_PROPOSAL_TYPE_STANDARD, + ) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[0], v1.NewNonSplitVoteOption(v1.OptionYes), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[1], v1.NewNonSplitVoteOption(v1.OptionNo), "")) - - proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + valAccAddrs[0], + v1.NewNonSplitVoteOption(v1.OptionYes), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + valAccAddrs[1], + v1.NewNonSplitVoteOption(v1.OptionNo), + "", + ), + ) + + proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, _, _ := f.govKeeper.Tally(ctx, proposal) + passes, burnDeposits, _, _ := f.govKeeper.Tally(f.ctx, proposal) assert.Assert(t, passes == false) assert.Assert(t, burnDeposits == false) @@ -126,23 +207,47 @@ func TestTallyOnlyValidators51Yes(t *testing.T) { f := initFixture(t) - ctx := f.ctx - valAccAddrs, _ := createValidators(t, f, []int64{5, 6, 0}) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", valAccAddrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) + proposal, err := f.govKeeper.SubmitProposal( + f.ctx, + tp, + "", + "test", + "description", + valAccAddrs[0], + v1.ProposalType_PROPOSAL_TYPE_STANDARD, + ) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[0], v1.NewNonSplitVoteOption(v1.OptionNo), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[1], v1.NewNonSplitVoteOption(v1.OptionYes), "")) - - proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + valAccAddrs[0], + v1.NewNonSplitVoteOption(v1.OptionNo), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + valAccAddrs[1], + v1.NewNonSplitVoteOption(v1.OptionYes), + "", + ), + ) + + proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) assert.Assert(t, passes) assert.Assert(t, burnDeposits == false) @@ -154,24 +259,57 @@ func TestTallyOnlyValidatorsVetoed(t *testing.T) { f := initFixture(t) - ctx := f.ctx - valAccAddrs, _ := createValidators(t, f, []int64{6, 6, 7}) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", valAccAddrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) + proposal, err := f.govKeeper.SubmitProposal( + f.ctx, + tp, + "", + "test", + "description", + valAccAddrs[0], + v1.ProposalType_PROPOSAL_TYPE_STANDARD, + ) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[0], v1.NewNonSplitVoteOption(v1.OptionYes), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[1], v1.NewNonSplitVoteOption(v1.OptionYes), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[2], v1.NewNonSplitVoteOption(v1.OptionNoWithVeto), "")) - - proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + valAccAddrs[0], + v1.NewNonSplitVoteOption(v1.OptionYes), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + valAccAddrs[1], + v1.NewNonSplitVoteOption(v1.OptionYes), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + valAccAddrs[2], + v1.NewNonSplitVoteOption(v1.OptionNoWithVeto), + "", + ), + ) + + proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) assert.Assert(t, passes == false) assert.Assert(t, burnDeposits) @@ -183,24 +321,57 @@ func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) { f := initFixture(t) - ctx := f.ctx - valAccAddrs, _ := createValidators(t, f, []int64{6, 6, 7}) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", valAccAddrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) + proposal, err := f.govKeeper.SubmitProposal( + f.ctx, + tp, + "", + "test", + "description", + valAccAddrs[0], + v1.ProposalType_PROPOSAL_TYPE_STANDARD, + ) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[0], v1.NewNonSplitVoteOption(v1.OptionAbstain), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[1], v1.NewNonSplitVoteOption(v1.OptionNo), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[2], v1.NewNonSplitVoteOption(v1.OptionYes), "")) - - proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + valAccAddrs[0], + v1.NewNonSplitVoteOption(v1.OptionAbstain), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + valAccAddrs[1], + v1.NewNonSplitVoteOption(v1.OptionNo), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + valAccAddrs[2], + v1.NewNonSplitVoteOption(v1.OptionYes), + "", + ), + ) + + proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) assert.Assert(t, passes) assert.Assert(t, burnDeposits == false) @@ -212,24 +383,57 @@ func TestTallyOnlyValidatorsAbstainFails(t *testing.T) { f := initFixture(t) - ctx := f.ctx - valAccAddrs, _ := createValidators(t, f, []int64{6, 6, 7}) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", valAccAddrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) + proposal, err := f.govKeeper.SubmitProposal( + f.ctx, + tp, + "", + "test", + "description", + valAccAddrs[0], + v1.ProposalType_PROPOSAL_TYPE_STANDARD, + ) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[0], v1.NewNonSplitVoteOption(v1.OptionAbstain), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[1], v1.NewNonSplitVoteOption(v1.OptionYes), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[2], v1.NewNonSplitVoteOption(v1.OptionNo), "")) - - proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + valAccAddrs[0], + v1.NewNonSplitVoteOption(v1.OptionAbstain), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + valAccAddrs[1], + v1.NewNonSplitVoteOption(v1.OptionYes), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + valAccAddrs[2], + v1.NewNonSplitVoteOption(v1.OptionNo), + "", + ), + ) + + proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) assert.Assert(t, passes == false) assert.Assert(t, burnDeposits == false) @@ -241,24 +445,48 @@ func TestTallyOnlyValidatorsNonVoter(t *testing.T) { f := initFixture(t) - ctx := f.ctx - valAccAddrs, _ := createValidators(t, f, []int64{5, 6, 7}) valAccAddr1, valAccAddr2 := valAccAddrs[0], valAccAddrs[1] tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", valAccAddrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) + proposal, err := f.govKeeper.SubmitProposal( + f.ctx, + tp, + "", + "test", + "description", + valAccAddrs[0], + v1.ProposalType_PROPOSAL_TYPE_STANDARD, + ) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddr1, v1.NewNonSplitVoteOption(v1.OptionYes), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddr2, v1.NewNonSplitVoteOption(v1.OptionNo), "")) - - proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + valAccAddr1, + v1.NewNonSplitVoteOption(v1.OptionYes), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + valAccAddr2, + v1.NewNonSplitVoteOption(v1.OptionNo), + "", + ), + ) + + proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) assert.Assert(t, passes == false) assert.Assert(t, burnDeposits == false) @@ -270,34 +498,83 @@ func TestTallyDelgatorOverride(t *testing.T) { f := initFixture(t) - ctx := f.ctx - addrs, valAddrs := createValidators(t, f, []int64{5, 6, 7}) - delTokens := f.stakingKeeper.TokensFromConsensusPower(ctx, 30) - val1, found := f.stakingKeeper.GetValidator(ctx, valAddrs[0]) + delTokens := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 30) + val1, found := f.stakingKeeper.GetValidator(f.ctx, valAddrs[0]) assert.Assert(t, found) - _, err := f.stakingKeeper.Delegate(ctx, addrs[4], delTokens, stakingtypes.Unbonded, val1, true) + _, err := f.stakingKeeper.Delegate( + f.ctx, + addrs[4], + delTokens, + stakingtypes.Unbonded, + val1, + true, + ) assert.NilError(t, err) - _, err = f.stakingKeeper.EndBlocker(ctx) + _, err = f.stakingKeeper.EndBlocker(f.ctx) assert.NilError(t, err) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", addrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) + proposal, err := f.govKeeper.SubmitProposal( + f.ctx, + tp, + "", + "test", + "description", + addrs[0], + v1.ProposalType_PROPOSAL_TYPE_STANDARD, + ) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[1], v1.NewNonSplitVoteOption(v1.OptionYes), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[2], v1.NewNonSplitVoteOption(v1.OptionYes), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[3], v1.NewNonSplitVoteOption(v1.OptionYes), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[4], v1.NewNonSplitVoteOption(v1.OptionNo), "")) - - proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[1], + v1.NewNonSplitVoteOption(v1.OptionYes), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[2], + v1.NewNonSplitVoteOption(v1.OptionYes), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[3], + v1.NewNonSplitVoteOption(v1.OptionYes), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[4], + v1.NewNonSplitVoteOption(v1.OptionNo), + "", + ), + ) + + proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) assert.Assert(t, passes == false) assert.Assert(t, burnDeposits == false) @@ -309,33 +586,73 @@ func TestTallyDelgatorInherit(t *testing.T) { f := initFixture(t) - ctx := f.ctx - addrs, vals := createValidators(t, f, []int64{5, 6, 7}) - delTokens := f.stakingKeeper.TokensFromConsensusPower(ctx, 30) - val3, found := f.stakingKeeper.GetValidator(ctx, vals[2]) + delTokens := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 30) + val3, found := f.stakingKeeper.GetValidator(f.ctx, vals[2]) assert.Assert(t, found) - _, err := f.stakingKeeper.Delegate(ctx, addrs[3], delTokens, stakingtypes.Unbonded, val3, true) + _, err := f.stakingKeeper.Delegate( + f.ctx, + addrs[3], + delTokens, + stakingtypes.Unbonded, + val3, + true, + ) assert.NilError(t, err) - _, err = f.stakingKeeper.EndBlocker(ctx) + _, err = f.stakingKeeper.EndBlocker(f.ctx) assert.NilError(t, err) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", addrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) + proposal, err := f.govKeeper.SubmitProposal( + f.ctx, + tp, + "", + "test", + "description", + addrs[0], + v1.ProposalType_PROPOSAL_TYPE_STANDARD, + ) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[0], v1.NewNonSplitVoteOption(v1.OptionNo), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[1], v1.NewNonSplitVoteOption(v1.OptionNo), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[2], v1.NewNonSplitVoteOption(v1.OptionYes), "")) - - proposal, err = f.govKeeper.Proposals.Get(ctx, proposalID) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[0], + v1.NewNonSplitVoteOption(v1.OptionNo), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[1], + v1.NewNonSplitVoteOption(v1.OptionNo), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[2], + v1.NewNonSplitVoteOption(v1.OptionYes), + "", + ), + ) + + proposal, err = f.govKeeper.Proposals.Get(f.ctx, proposalID) assert.NilError(t, err) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) assert.Assert(t, passes) assert.Assert(t, burnDeposits == false) @@ -347,37 +664,93 @@ func TestTallyDelgatorMultipleOverride(t *testing.T) { f := initFixture(t) - ctx := f.ctx - addrs, vals := createValidators(t, f, []int64{5, 6, 7}) - delTokens := f.stakingKeeper.TokensFromConsensusPower(ctx, 10) - val1, found := f.stakingKeeper.GetValidator(ctx, vals[0]) + delTokens := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 10) + val1, found := f.stakingKeeper.GetValidator(f.ctx, vals[0]) assert.Assert(t, found) - val2, found := f.stakingKeeper.GetValidator(ctx, vals[1]) + val2, found := f.stakingKeeper.GetValidator(f.ctx, vals[1]) assert.Assert(t, found) - _, err := f.stakingKeeper.Delegate(ctx, addrs[3], delTokens, stakingtypes.Unbonded, val1, true) + _, err := f.stakingKeeper.Delegate( + f.ctx, + addrs[3], + delTokens, + stakingtypes.Unbonded, + val1, + true, + ) assert.NilError(t, err) - _, err = f.stakingKeeper.Delegate(ctx, addrs[3], delTokens, stakingtypes.Unbonded, val2, true) + _, err = f.stakingKeeper.Delegate( + f.ctx, + addrs[3], + delTokens, + stakingtypes.Unbonded, + val2, + true, + ) assert.NilError(t, err) - _, err = f.stakingKeeper.EndBlocker(ctx) + _, err = f.stakingKeeper.EndBlocker(f.ctx) assert.NilError(t, err) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", addrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) + proposal, err := f.govKeeper.SubmitProposal( + f.ctx, + tp, + "", + "test", + "description", + addrs[0], + v1.ProposalType_PROPOSAL_TYPE_STANDARD, + ) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[0], v1.NewNonSplitVoteOption(v1.OptionYes), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[1], v1.NewNonSplitVoteOption(v1.OptionYes), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[2], v1.NewNonSplitVoteOption(v1.OptionYes), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[3], v1.NewNonSplitVoteOption(v1.OptionNo), "")) - - proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[0], + v1.NewNonSplitVoteOption(v1.OptionYes), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[1], + v1.NewNonSplitVoteOption(v1.OptionYes), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[2], + v1.NewNonSplitVoteOption(v1.OptionYes), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[3], + v1.NewNonSplitVoteOption(v1.OptionNo), + "", + ), + ) + + proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) assert.Assert(t, passes == false) assert.Assert(t, burnDeposits == false) @@ -389,39 +762,86 @@ func TestTallyDelgatorMultipleInherit(t *testing.T) { f := initFixture(t) - ctx := f.ctx - createValidators(t, f, []int64{25, 6, 7}) addrs, vals := createValidators(t, f, []int64{5, 6, 7}) - delTokens := f.stakingKeeper.TokensFromConsensusPower(ctx, 10) - val2, found := f.stakingKeeper.GetValidator(ctx, vals[1]) + delTokens := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 10) + val2, found := f.stakingKeeper.GetValidator(f.ctx, vals[1]) assert.Assert(t, found) - val3, found := f.stakingKeeper.GetValidator(ctx, vals[2]) + val3, found := f.stakingKeeper.GetValidator(f.ctx, vals[2]) assert.Assert(t, found) - _, err := f.stakingKeeper.Delegate(ctx, addrs[3], delTokens, stakingtypes.Unbonded, val2, true) + _, err := f.stakingKeeper.Delegate( + f.ctx, + addrs[3], + delTokens, + stakingtypes.Unbonded, + val2, + true, + ) assert.NilError(t, err) - _, err = f.stakingKeeper.Delegate(ctx, addrs[3], delTokens, stakingtypes.Unbonded, val3, true) + _, err = f.stakingKeeper.Delegate( + f.ctx, + addrs[3], + delTokens, + stakingtypes.Unbonded, + val3, + true, + ) assert.NilError(t, err) - _, err = f.stakingKeeper.EndBlocker(ctx) + _, err = f.stakingKeeper.EndBlocker(f.ctx) assert.NilError(t, err) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", addrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) + proposal, err := f.govKeeper.SubmitProposal( + f.ctx, + tp, + "", + "test", + "description", + addrs[0], + v1.ProposalType_PROPOSAL_TYPE_STANDARD, + ) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[0], v1.NewNonSplitVoteOption(v1.OptionYes), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[1], v1.NewNonSplitVoteOption(v1.OptionNo), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[2], v1.NewNonSplitVoteOption(v1.OptionNo), "")) - - proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[0], + v1.NewNonSplitVoteOption(v1.OptionYes), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[1], + v1.NewNonSplitVoteOption(v1.OptionNo), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[2], + v1.NewNonSplitVoteOption(v1.OptionNo), + "", + ), + ) + + proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) assert.Assert(t, passes == false) assert.Assert(t, burnDeposits == false) @@ -433,41 +853,87 @@ func TestTallyJailedValidator(t *testing.T) { f := initFixture(t) - ctx := f.ctx - addrs, valAddrs := createValidators(t, f, []int64{25, 6, 7}) - delTokens := f.stakingKeeper.TokensFromConsensusPower(ctx, 10) - val2, found := f.stakingKeeper.GetValidator(ctx, valAddrs[1]) + delTokens := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 10) + val2, found := f.stakingKeeper.GetValidator(f.ctx, valAddrs[1]) assert.Assert(t, found) - val3, found := f.stakingKeeper.GetValidator(ctx, valAddrs[2]) + val3, found := f.stakingKeeper.GetValidator(f.ctx, valAddrs[2]) assert.Assert(t, found) - _, err := f.stakingKeeper.Delegate(ctx, addrs[3], delTokens, stakingtypes.Unbonded, val2, true) + _, err := f.stakingKeeper.Delegate( + f.ctx, + addrs[3], + delTokens, + stakingtypes.Unbonded, + val2, + true, + ) assert.NilError(t, err) - _, err = f.stakingKeeper.Delegate(ctx, addrs[3], delTokens, stakingtypes.Unbonded, val3, true) + _, err = f.stakingKeeper.Delegate( + f.ctx, + addrs[3], + delTokens, + stakingtypes.Unbonded, + val3, + true, + ) assert.NilError(t, err) - _, err = f.stakingKeeper.EndBlocker(ctx) + _, err = f.stakingKeeper.EndBlocker(f.ctx) assert.NilError(t, err) consAddr, err := val2.GetConsAddr() assert.NilError(t, err) - assert.NilError(t, f.stakingKeeper.Jail(ctx, sdk.ConsAddress(consAddr))) + assert.NilError(t, f.stakingKeeper.Jail(f.ctx, sdk.ConsAddress(consAddr))) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", addrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) + proposal, err := f.govKeeper.SubmitProposal( + f.ctx, + tp, + "", + "test", + "description", + addrs[0], + v1.ProposalType_PROPOSAL_TYPE_STANDARD, + ) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[0], v1.NewNonSplitVoteOption(v1.OptionYes), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[1], v1.NewNonSplitVoteOption(v1.OptionNo), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[2], v1.NewNonSplitVoteOption(v1.OptionNo), "")) - - proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[0], + v1.NewNonSplitVoteOption(v1.OptionYes), + "", + )) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[1], + v1.NewNonSplitVoteOption(v1.OptionNo), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[2], + v1.NewNonSplitVoteOption(v1.OptionNo), + "", + ), + ) + + proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) assert.Assert(t, passes) assert.Assert(t, burnDeposits == false) @@ -479,40 +945,86 @@ func TestTallyValidatorMultipleDelegations(t *testing.T) { f := initFixture(t) - ctx := f.ctx - addrs, valAddrs := createValidators(t, f, []int64{10, 10, 10}) - delTokens := f.stakingKeeper.TokensFromConsensusPower(ctx, 10) - val2, found := f.stakingKeeper.GetValidator(ctx, valAddrs[1]) + delTokens := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 10) + val2, found := f.stakingKeeper.GetValidator(f.ctx, valAddrs[1]) assert.Assert(t, found) - _, err := f.stakingKeeper.Delegate(ctx, addrs[0], delTokens, stakingtypes.Unbonded, val2, true) + _, err := f.stakingKeeper.Delegate( + f.ctx, + addrs[0], + delTokens, + stakingtypes.Unbonded, + val2, + true, + ) assert.NilError(t, err) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", addrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) + proposal, err := f.govKeeper.SubmitProposal( + f.ctx, + tp, + "", + "test", + "description", + addrs[0], + v1.ProposalType_PROPOSAL_TYPE_STANDARD, + ) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[0], v1.NewNonSplitVoteOption(v1.OptionYes), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[1], v1.NewNonSplitVoteOption(v1.OptionNo), "")) - assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[2], v1.NewNonSplitVoteOption(v1.OptionYes), "")) - - proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[0], + v1.NewNonSplitVoteOption(v1.OptionYes), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[1], + v1.NewNonSplitVoteOption(v1.OptionNo), + "", + ), + ) + assert.NilError( + t, + f.govKeeper.AddVote( + f.ctx, + proposalID, + addrs[2], + v1.NewNonSplitVoteOption(v1.OptionYes), + "", + ), + ) + + proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) assert.Assert(t, passes) assert.Assert(t, burnDeposits == false) - expectedYes := f.stakingKeeper.TokensFromConsensusPower(ctx, 30) - expectedAbstain := f.stakingKeeper.TokensFromConsensusPower(ctx, 0) - expectedNo := f.stakingKeeper.TokensFromConsensusPower(ctx, 10) - expectedNoWithVeto := f.stakingKeeper.TokensFromConsensusPower(ctx, 0) - expectedTallyResult := v1.NewTallyResult(expectedYes, expectedAbstain, expectedNo, expectedNoWithVeto, math.ZeroInt()) + expectedYes := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 30) + expectedAbstain := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 0) + expectedNo := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 10) + expectedNoWithVeto := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 0) + expectedTallyResult := v1.NewTallyResult( + expectedYes, + expectedAbstain, + expectedNo, + expectedNoWithVeto, + math.ZeroInt(), + ) assert.Assert(t, tallyResults.Equals(expectedTallyResult)) } diff --git a/tests/integration/v2-audit.md b/tests/integration/v2-audit.md new file mode 100644 index 000000000000..009e70a41f69 --- /dev/null +++ b/tests/integration/v2-audit.md @@ -0,0 +1,31 @@ +# server v2 integration tests + +## audit usages of [NewIntegrationApp](../../testutil/integration/router.go#L46) + +All modules: + +* create and register query and message servers. +* call `App.QueryHelper` in setup, and may call in test. +* make use of `sdk.Context`. a `context.Context` could be substituted except +where otherwise noted. + +* [x/auth](./auth/keeper/msg_server_test.go#L122) + * calls `App.RunMsg` in test + * calls `sdk.Context` `GasMeter()` through [testdata.DeterministicIterations](../../testutil/testdata/grpc_query.go#L73) +* [x/bank](./bank/keeper/deterministic_test.go#L122) + * calls `sdk.Context` `GasMeter()` through [testdata.DeterministicIterations](../../testutil/testdata/grpc_query.go#L73) +* [x/distribution](./distribution/keeper/msg_server_test.go#L170) + * calls `App.RunMsg` in test + * calls `BaseApp.LastBlockHeight()`. delegates to store/v1 meta info store. + * calls `sdk.Context.CometInfo()`. can be replaced with `CometInfoService` +* [x/evidence](./evidence//keeper/infraction_test.go#L164) + * calls `BaseApp.StoreConsenusParams`, `BaseApp.GetConsensusParams` in test. + * mutates `sdk.Context` with `WithIsCheckTx`, `WithBlockHeight`, `WithHeaderInfo` + * calls `sdk.Context` `GetBlockHeight()` +* [x/gov](./gov/keeper/keeper_test.go#L150) +* x/slashing + * calls `App.RunMsg` in test + * calls `sdk.Context` `BlockHeight()` + * mutates `sdk.Context` with `WithBlockHeight`, `WithHeaderInfo` +* x/staking + * calls `sdk.Context` `GasMeter()` through [testdata.DeterministicIterations](../../testutil/testdata/grpc_query.go#L73) From eb347f626fd6fec000c3b907e2b768510d41b885 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Tue, 3 Sep 2024 15:30:47 -0500 Subject: [PATCH 02/57] Update v2-audit.md --- tests/integration/v2-audit.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/integration/v2-audit.md b/tests/integration/v2-audit.md index 009e70a41f69..81ae7891caf2 100644 --- a/tests/integration/v2-audit.md +++ b/tests/integration/v2-audit.md @@ -3,10 +3,9 @@ ## audit usages of [NewIntegrationApp](../../testutil/integration/router.go#L46) All modules: - -* create and register query and message servers. -* call `App.QueryHelper` in setup, and may call in test. -* make use of `sdk.Context`. a `context.Context` could be substituted except +- create and register query and message servers. +- call `App.QueryHelper` in setup, and may call in test. +- make use of `sdk.Context`. a `context.Context` could be substituted except where otherwise noted. * [x/auth](./auth/keeper/msg_server_test.go#L122) From 2e9835cd7234e80d9cddca15ecc237a7586bd7b9 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Fri, 6 Sep 2024 12:23:16 -0500 Subject: [PATCH 03/57] very basic port --- server/v2/appmanager/appmanager.go | 102 +++++-- tests/integration/v2-audit.md | 18 +- tests/integration/v2/app.go | 55 ++++ tests/integration/v2/app_helpers.go | 415 ++++++++++++++++++++++++++++ 4 files changed, 562 insertions(+), 28 deletions(-) create mode 100644 tests/integration/v2/app.go create mode 100644 tests/integration/v2/app_helpers.go diff --git a/server/v2/appmanager/appmanager.go b/server/v2/appmanager/appmanager.go index 023f76bd2067..70b3eaed634c 100644 --- a/server/v2/appmanager/appmanager.go +++ b/server/v2/appmanager/appmanager.go @@ -41,7 +41,7 @@ func (a AppManager[T]) InitGenesis( ctx context.Context, blockRequest *server.BlockRequest[T], initGenesisJSON []byte, - txDecoder transaction.Codec[T], + txCodec transaction.Codec[T], ) (*server.BlockResponse, corestore.WriterMap, error) { v, zeroState, err := a.db.StateLatest() if err != nil { @@ -52,43 +52,71 @@ func (a AppManager[T]) InitGenesis( } var genTxs []T - genesisState, err := a.stf.RunWithCtx(ctx, zeroState, func(ctx context.Context) error { - return a.initGenesis(ctx, bytes.NewBuffer(initGenesisJSON), func(jsonTx json.RawMessage) error { - genTx, err := txDecoder.DecodeJSON(jsonTx) - if err != nil { - return fmt.Errorf("failed to decode genesis transaction: %w", err) - } - genTxs = append(genTxs, genTx) - return nil - }) - }) + genesisState, err := a.stf.RunWithCtx( + ctx, + zeroState, + func(ctx context.Context) error { + return a.initGenesis( + ctx, + bytes.NewBuffer(initGenesisJSON), + func(jsonTx json.RawMessage) error { + genTx, err := txCodec.DecodeJSON(jsonTx) + if err != nil { + return fmt.Errorf( + "failed to decode genesis transaction: %w", + err, + ) + } + genTxs = append(genTxs, genTx) + return nil + }, + ) + }, + ) if err != nil { return nil, nil, fmt.Errorf("failed to import genesis state: %w", err) } // run block blockRequest.Txs = genTxs - blockResponse, blockZeroState, err := a.stf.DeliverBlock(ctx, blockRequest, genesisState) + blockResponse, blockZeroState, err := a.stf.DeliverBlock( + ctx, + blockRequest, + genesisState, + ) if err != nil { - return blockResponse, nil, fmt.Errorf("failed to deliver block %d: %w", blockRequest.Height, err) + return blockResponse, nil, fmt.Errorf( + "failed to deliver block %d: %w", + blockRequest.Height, + err, + ) } // after executing block 0, we extract the changes and apply them to the genesis state. stateChanges, err := blockZeroState.GetStateChanges() if err != nil { - return nil, nil, fmt.Errorf("failed to get block zero state changes: %w", err) + return nil, nil, fmt.Errorf( + "failed to get block zero state changes: %w", + err, + ) } err = genesisState.ApplyStateChanges(stateChanges) if err != nil { - return nil, nil, fmt.Errorf("failed to apply block zero state changes to genesis state: %w", err) + return nil, nil, fmt.Errorf( + "failed to apply block zero state changes to genesis state: %w", + err, + ) } return blockResponse, genesisState, err } // ExportGenesis exports the genesis state of the application. -func (a AppManager[T]) ExportGenesis(ctx context.Context, version uint64) ([]byte, error) { +func (a AppManager[T]) ExportGenesis( + ctx context.Context, + version uint64, +) ([]byte, error) { zeroState, err := a.db.StateAt(version) if err != nil { return nil, fmt.Errorf("unable to get latest state: %w", err) @@ -120,11 +148,19 @@ func (a AppManager[T]) DeliverBlock( ) (*server.BlockResponse, corestore.WriterMap, error) { latestVersion, currentState, err := a.db.StateLatest() if err != nil { - return nil, nil, fmt.Errorf("unable to create new state for height %d: %w", block.Height, err) + return nil, nil, fmt.Errorf( + "unable to create new state for height %d: %w", + block.Height, + err, + ) } if latestVersion+1 != block.Height { - return nil, nil, fmt.Errorf("invalid DeliverBlock height wanted %d, got %d", latestVersion+1, block.Height) + return nil, nil, fmt.Errorf( + "invalid DeliverBlock height wanted %d, got %d", + latestVersion+1, + block.Height, + ) } blockResponse, newState, err := a.stf.DeliverBlock(ctx, block, currentState) @@ -138,27 +174,47 @@ func (a AppManager[T]) DeliverBlock( // ValidateTx will validate the tx against the latest storage state. This means that // only the stateful validation will be run, not the execution portion of the tx. // If full execution is needed, Simulate must be used. -func (a AppManager[T]) ValidateTx(ctx context.Context, tx T) (server.TxResult, error) { +func (a AppManager[T]) ValidateTx( + ctx context.Context, + tx T, +) (server.TxResult, error) { _, latestState, err := a.db.StateLatest() if err != nil { return server.TxResult{}, err } - return a.stf.ValidateTx(ctx, latestState, a.config.ValidateTxGasLimit, tx), nil + return a.stf.ValidateTx( + ctx, + latestState, + a.config.ValidateTxGasLimit, + tx, + ), nil } // Simulate runs validation and execution flow of a Tx. -func (a AppManager[T]) Simulate(ctx context.Context, tx T) (server.TxResult, corestore.WriterMap, error) { +func (a AppManager[T]) Simulate( + ctx context.Context, + tx T, +) (server.TxResult, corestore.WriterMap, error) { _, state, err := a.db.StateLatest() if err != nil { return server.TxResult{}, nil, err } - result, cs := a.stf.Simulate(ctx, state, a.config.SimulationGasLimit, tx) // TODO: check if this is done in the antehandler + result, cs := a.stf.Simulate( + ctx, + state, + a.config.SimulationGasLimit, + tx, + ) // TODO: check if this is done in the antehandler return result, cs, nil } // Query queries the application at the provided version. // CONTRACT: Version must always be provided, if 0, get latest -func (a AppManager[T]) Query(ctx context.Context, version uint64, request transaction.Msg) (transaction.Msg, error) { +func (a AppManager[T]) Query( + ctx context.Context, + version uint64, + request transaction.Msg, +) (transaction.Msg, error) { // if version is provided attempt to do a height query. if version != 0 { queryState, err := a.db.StateAt(version) diff --git a/tests/integration/v2-audit.md b/tests/integration/v2-audit.md index 81ae7891caf2..8613bc0868c4 100644 --- a/tests/integration/v2-audit.md +++ b/tests/integration/v2-audit.md @@ -2,12 +2,11 @@ ## audit usages of [NewIntegrationApp](../../testutil/integration/router.go#L46) -All modules: -- create and register query and message servers. -- call `App.QueryHelper` in setup, and may call in test. -- make use of `sdk.Context`. a `context.Context` could be substituted except -where otherwise noted. +* x/* + * create and register query and message servers + * call `App.QueryHelper` in setup, and may call in test + * make use of `sdk.Context`. a `context.Context` could be substituted except where otherwise noted * [x/auth](./auth/keeper/msg_server_test.go#L122) * calls `App.RunMsg` in test * calls `sdk.Context` `GasMeter()` through [testdata.DeterministicIterations](../../testutil/testdata/grpc_query.go#L73) @@ -28,3 +27,12 @@ where otherwise noted. * mutates `sdk.Context` with `WithBlockHeight`, `WithHeaderInfo` * x/staking * calls `sdk.Context` `GasMeter()` through [testdata.DeterministicIterations](../../testutil/testdata/grpc_query.go#L73) + +## poc notes + +testutil/integration can (and should) be moved to tests/integration. + +## simulations + +In addition to `NewIntegrationApp` many modules also make use of [testutil/sims.SetupWithConfiguration](../../testutil/sims/app_helpers.go#L145) to create a `runtime.App` for simulation testing. For example +[createTestSuite in bank](bank/app_test.go#L81) diff --git a/tests/integration/v2/app.go b/tests/integration/v2/app.go new file mode 100644 index 000000000000..251280afb6b2 --- /dev/null +++ b/tests/integration/v2/app.go @@ -0,0 +1,55 @@ +package integration + +import ( + "fmt" + + runtimev2 "cosmossdk.io/api/cosmos/app/runtime/v2" + "cosmossdk.io/core/address" + "cosmossdk.io/core/appmodule" + "cosmossdk.io/core/transaction" + "cosmossdk.io/log" + "cosmossdk.io/runtime/v2" + + "github.com/cosmos/cosmos-sdk/codec" +) + +func NewIntegrationApp( + logger log.Logger, + addressCodec address.Codec, + validatorCodec address.ValidatorAddressCodec, + modules map[string]appmodule.AppModule, +) { + interfaceRegistry, _, err := codec.ProvideInterfaceRegistry( + addressCodec, + validatorCodec, + nil, + ) + if err != nil { + panic(err) + } + + legacyAmino := codec.ProvideLegacyAmino() + appBuilder, routerBuilder, _, _, _ := runtime.ProvideAppBuilder[transaction.Tx]( + interfaceRegistry, + legacyAmino, + ) + mm := runtime.NewModuleManager[transaction.Tx]( + logger, + &runtimev2.Module{}, + modules, + ) + // appBuilder.RegisterModules(mm) + fmt.Printf("appBuilder: %v\nrouterBuilder: %v\nmodule manager: %v", + appBuilder, + routerBuilder, + mm) + app, err := appBuilder.Build() + if err != nil { + panic(err) + } + fmt.Printf("appBuilder: %v\nrouterBuilder: %v\nmodule manager: %v\napp: %v", + appBuilder, + routerBuilder, + mm, + app) +} diff --git a/tests/integration/v2/app_helpers.go b/tests/integration/v2/app_helpers.go new file mode 100644 index 000000000000..8f48451dec4a --- /dev/null +++ b/tests/integration/v2/app_helpers.go @@ -0,0 +1,415 @@ +// this file is a port of testutil/sims/app_helpers.go from v1 to v2 architecture +package integration + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "time" + + cmtproto "github.com/cometbft/cometbft/api/cometbft/types/v1" + cmtjson "github.com/cometbft/cometbft/libs/json" + cmttypes "github.com/cometbft/cometbft/types" + dbm "github.com/cosmos/cosmos-db" + + corecontext "cosmossdk.io/core/context" + "cosmossdk.io/core/server" + corestore "cosmossdk.io/core/store" + "cosmossdk.io/core/transaction" + "cosmossdk.io/depinject" + sdkmath "cosmossdk.io/math" + "cosmossdk.io/runtime/v2" + "cosmossdk.io/x/auth/tx" + authtypes "cosmossdk.io/x/auth/types" + banktypes "cosmossdk.io/x/bank/types" + consensustypes "cosmossdk.io/x/consensus/types" + stakingtypes "cosmossdk.io/x/staking/types" + + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/cosmos/cosmos-sdk/testutil/mock" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const DefaultGenTxGas = 10000000 + +type stateMachineTx = transaction.Tx + +// DefaultConsensusParams defines the default CometBFT consensus params used in +// SimApp testing. +var DefaultConsensusParams = &cmtproto.ConsensusParams{ + Version: &cmtproto.VersionParams{ + App: 1, + }, + Block: &cmtproto.BlockParams{ + MaxBytes: 200000, + MaxGas: 100_000_000, + }, + Evidence: &cmtproto.EvidenceParams{ + MaxAgeNumBlocks: 302400, + MaxAgeDuration: 504 * time.Hour, // 3 weeks is the max duration + MaxBytes: 10000, + }, + Validator: &cmtproto.ValidatorParams{ + PubKeyTypes: []string{ + cmttypes.ABCIPubKeyTypeEd25519, + cmttypes.ABCIPubKeyTypeSecp256k1, + }, + }, +} + +// CreateRandomValidatorSet creates a validator set with one random validator +func CreateRandomValidatorSet() (*cmttypes.ValidatorSet, error) { + privVal := mock.NewPV() + pubKey, err := privVal.GetPubKey() + if err != nil { + return nil, fmt.Errorf("failed to get pub key: %w", err) + } + + // create validator set with single validator + validator := cmttypes.NewValidator(pubKey, 1) + + return cmttypes.NewValidatorSet([]*cmttypes.Validator{validator}), nil +} + +type GenesisAccount struct { + authtypes.GenesisAccount + Coins sdk.Coins +} + +// StartupConfig defines the startup configuration new a test application. +// +// ValidatorSet defines a custom validator set to be validating the app. +// BaseAppOption defines the additional operations that must be run on baseapp before app start. +// AtGenesis defines if the app started should already have produced block or not. +type StartupConfig struct { + ValidatorSet func() (*cmttypes.ValidatorSet, error) + AppOption runtime.AppBuilderOption[stateMachineTx] + AtGenesis bool + GenesisAccounts []GenesisAccount + DB corestore.KVStoreWithBatch +} + +func DefaultStartUpConfig() StartupConfig { + priv := secp256k1.GenPrivKey() + ba := authtypes.NewBaseAccount( + priv.PubKey().Address().Bytes(), + priv.PubKey(), + 0, + 0, + ) + ga := GenesisAccount{ + ba, + sdk.NewCoins( + sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100000000000000)), + ), + } + return StartupConfig{ + ValidatorSet: CreateRandomValidatorSet, + AtGenesis: false, + GenesisAccounts: []GenesisAccount{ga}, + DB: dbm.NewMemDB(), + } +} + +// Setup initializes a new runtime.App and can inject values into extraOutputs. +// It uses SetupWithConfiguration under the hood. +func Setup( + appConfig depinject.Config, + extraOutputs ...interface{}, +) (*runtime.App[stateMachineTx], error) { + return SetupWithConfiguration( + appConfig, + DefaultStartUpConfig(), + extraOutputs...) +} + +// SetupAtGenesis initializes a new runtime.App at genesis and can inject values into extraOutputs. +// It uses SetupWithConfiguration under the hood. +func SetupAtGenesis( + appConfig depinject.Config, + extraOutputs ...interface{}, +) (*runtime.App[transaction.Tx], error) { + cfg := DefaultStartUpConfig() + cfg.AtGenesis = true + return SetupWithConfiguration(appConfig, cfg, extraOutputs...) +} + +// SetupWithConfiguration initializes a new runtime.App. A Nop logger is set in runtime.App. +// appConfig defines the application configuration (f.e. app_config.go). +// extraOutputs defines the extra outputs to be assigned by the dependency injector (depinject). +func SetupWithConfiguration( + appConfig depinject.Config, + startupConfig StartupConfig, + extraOutputs ...interface{}, +) (*runtime.App[stateMachineTx], error) { + // create the app with depinject + var ( + app *runtime.App[stateMachineTx] + appBuilder *runtime.AppBuilder[stateMachineTx] + txConfigOptions tx.ConfigOptions + codec codec.Codec + err error + ) + + if err := depinject.Inject( + appConfig, + append(extraOutputs, &appBuilder, &codec, &txConfigOptions)...); err != nil { + return nil, fmt.Errorf("failed to inject dependencies: %w", err) + } + + app, err = appBuilder.Build(startupConfig.AppOption) + if err != nil { + return nil, fmt.Errorf("failed to build app: %w", err) + } + if err := app.LoadLatest(); err != nil { + return nil, fmt.Errorf("failed to load app: %w", err) + } + + // create validator set + valSet, err := startupConfig.ValidatorSet() + if err != nil { + return nil, errors.New("failed to create validator set") + } + + var ( + balances []banktypes.Balance + genAccounts []authtypes.GenesisAccount + ) + for _, ga := range startupConfig.GenesisAccounts { + genAccounts = append(genAccounts, ga.GenesisAccount) + balances = append( + balances, + banktypes.Balance{ + Address: ga.GenesisAccount.GetAddress().String(), + Coins: ga.Coins, + }, + ) + } + + genesisState, err := genesisStateWithValSet( + codec, + app.DefaultGenesis(), + valSet, + genAccounts, + balances...) + if err != nil { + return nil, fmt.Errorf("failed to create genesis state: %w", err) + } + + // init chain must be called to stop deliverState from being nil + stateBytes, err := cmtjson.MarshalIndent(genesisState, "", " ") + if err != nil { + return nil, fmt.Errorf( + "failed to marshal default genesis state: %w", + err, + ) + } + + ctx := context.WithValue( + context.Background(), + corecontext.InitInfoKey, + &consensustypes.MsgUpdateParams{ + Authority: "consensus", + Block: DefaultConsensusParams.Block, + Evidence: DefaultConsensusParams.Evidence, + Validator: DefaultConsensusParams.Validator, + Abci: DefaultConsensusParams.Abci, + Synchrony: DefaultConsensusParams.Synchrony, + Feature: DefaultConsensusParams.Feature, + }, + ) + + _, _, err = app.InitGenesis( + ctx, + &server.BlockRequest[stateMachineTx]{}, + stateBytes, + &genericTxDecoder{txConfigOptions}, + ) + if err != nil { + return nil, fmt.Errorf("failed to init genesis: %w", err) + } + + // commit genesis changes + // not sure if this is needed yet + // if !startupConfig.AtGenesis { + // _, err = app.FinalizeBlock(&abci.FinalizeBlockRequest{ + // Height: app.LastBlockHeight() + 1, + // NextValidatorsHash: valSet.Hash(), + // }) + // if err != nil { + // return nil, fmt.Errorf("failed to finalize block: %w", err) + // } + // } + + return app, nil +} + +// genesisStateWithValSet returns a new genesis state with the validator set +func genesisStateWithValSet( + codec codec.Codec, + genesisState map[string]json.RawMessage, + valSet *cmttypes.ValidatorSet, + genAccs []authtypes.GenesisAccount, + balances ...banktypes.Balance, +) (map[string]json.RawMessage, error) { + // set genesis accounts + authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs) + genesisState[authtypes.ModuleName] = codec.MustMarshalJSON(authGenesis) + + validators := make([]stakingtypes.Validator, 0, len(valSet.Validators)) + delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators)) + + bondAmt := sdk.DefaultPowerReduction + + for _, val := range valSet.Validators { + pk, err := cryptocodec.FromCmtPubKeyInterface(val.PubKey) + if err != nil { + return nil, fmt.Errorf("failed to convert pubkey: %w", err) + } + + pkAny, err := codectypes.NewAnyWithValue(pk) + if err != nil { + return nil, fmt.Errorf("failed to create new any: %w", err) + } + + validator := stakingtypes.Validator{ + OperatorAddress: sdk.ValAddress(val.Address).String(), + ConsensusPubkey: pkAny, + Jailed: false, + Status: stakingtypes.Bonded, + Tokens: bondAmt, + DelegatorShares: sdkmath.LegacyOneDec(), + Description: stakingtypes.Description{}, + UnbondingHeight: int64(0), + UnbondingTime: time.Unix(0, 0).UTC(), + Commission: stakingtypes.NewCommission( + sdkmath.LegacyZeroDec(), + sdkmath.LegacyZeroDec(), + sdkmath.LegacyZeroDec(), + ), + MinSelfDelegation: sdkmath.ZeroInt(), + } + validators = append(validators, validator) + delegations = append( + delegations, + stakingtypes.NewDelegation( + genAccs[0].GetAddress().String(), + sdk.ValAddress(val.Address).String(), + sdkmath.LegacyOneDec(), + ), + ) + + } + + // set validators and delegations + stakingGenesis := stakingtypes.NewGenesisState( + stakingtypes.DefaultParams(), + validators, + delegations, + ) + genesisState[stakingtypes.ModuleName] = codec.MustMarshalJSON( + stakingGenesis, + ) + + totalSupply := sdk.NewCoins() + for _, b := range balances { + // add genesis acc tokens to total supply + totalSupply = totalSupply.Add(b.Coins...) + } + + for range delegations { + // add delegated tokens to total supply + totalSupply = totalSupply.Add( + sdk.NewCoin(sdk.DefaultBondDenom, bondAmt), + ) + } + + // add bonded amount to bonded pool module account + balances = append(balances, banktypes.Balance{ + Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName). + String(), + Coins: sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, bondAmt)}, + }) + + // update total supply + bankGenesis := banktypes.NewGenesisState( + banktypes.DefaultGenesisState().Params, + balances, + totalSupply, + []banktypes.Metadata{}, + []banktypes.SendEnabled{}, + ) + genesisState[banktypes.ModuleName] = codec.MustMarshalJSON(bankGenesis) + + return genesisState, nil +} + +type genericTxDecoder struct { + tx.ConfigOptions +} + +// Decode implements transaction.Codec. +func (t *genericTxDecoder) Decode(bz []byte) (stateMachineTx, error) { + var out stateMachineTx + tx, err := t.ProtoDecoder(bz) + if err != nil { + return out, err + } + + var ok bool + out, ok = tx.(stateMachineTx) + if !ok { + return out, errors.New("unexpected Tx type") + } + + return out, nil +} + +// DecodeJSON implements transaction.Codec. +func (t *genericTxDecoder) DecodeJSON(bz []byte) (stateMachineTx, error) { + var out stateMachineTx + tx, err := t.JSONDecoder(bz) + if err != nil { + return out, err + } + + var ok bool + out, ok = tx.(stateMachineTx) + if !ok { + return out, errors.New("unexpected Tx type") + } + + return out, nil +} + +// EmptyAppOptions is a stub implementing AppOptions +type EmptyAppOptions struct{} + +// Get implements AppOptions +func (ao EmptyAppOptions) Get(o string) interface{} { + return nil +} + +// AppOptionsMap is a stub implementing AppOptions which can get data from a map +type AppOptionsMap map[string]interface{} + +func (m AppOptionsMap) Get(key string) interface{} { + v, ok := m[key] + if !ok { + return interface{}(nil) + } + + return v +} + +func NewAppOptionsWithFlagHome(homePath string) servertypes.AppOptions { + return AppOptionsMap{ + flags.FlagHome: homePath, + } +} From 14686bae02bf10e15e52a37c1acbb2c9b8a54a1a Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Fri, 6 Sep 2024 12:28:46 -0500 Subject: [PATCH 04/57] merge fix --- tests/integration/v2/app_helpers.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/integration/v2/app_helpers.go b/tests/integration/v2/app_helpers.go index 8f48451dec4a..38c2dd9b92e4 100644 --- a/tests/integration/v2/app_helpers.go +++ b/tests/integration/v2/app_helpers.go @@ -20,8 +20,6 @@ import ( "cosmossdk.io/depinject" sdkmath "cosmossdk.io/math" "cosmossdk.io/runtime/v2" - "cosmossdk.io/x/auth/tx" - authtypes "cosmossdk.io/x/auth/types" banktypes "cosmossdk.io/x/bank/types" consensustypes "cosmossdk.io/x/consensus/types" stakingtypes "cosmossdk.io/x/staking/types" @@ -34,6 +32,8 @@ import ( servertypes "github.com/cosmos/cosmos-sdk/server/types" "github.com/cosmos/cosmos-sdk/testutil/mock" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/tx" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) const DefaultGenTxGas = 10000000 @@ -213,7 +213,7 @@ func SetupWithConfiguration( ctx := context.WithValue( context.Background(), - corecontext.InitInfoKey, + corecontext.CometParamsInitInfoKey, &consensustypes.MsgUpdateParams{ Authority: "consensus", Block: DefaultConsensusParams.Block, From 74358ca731d0caf9b15cc063c68cb2758b5d05b2 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 9 Sep 2024 21:07:30 -0500 Subject: [PATCH 05/57] basic construction seems to be working --- codec/depinject.go | 7 +++ core/server/config.go | 6 +++ runtime/v2/builder.go | 21 ++++---- runtime/v2/module.go | 8 ++-- simapp/v2/app_di.go | 17 +++++++ store/v2/db/db.go | 1 - tests/integration/bank/app_test.go | 44 ++++++++++------- tests/integration/v2/app_helpers.go | 51 +++++++++++++++++--- testutil/configurator/configurator.go | 69 +++++++++++++++++++++++++++ 9 files changed, 186 insertions(+), 38 deletions(-) create mode 100644 core/server/config.go diff --git a/codec/depinject.go b/codec/depinject.go index c685a3763e15..d172a5813d9a 100644 --- a/codec/depinject.go +++ b/codec/depinject.go @@ -16,6 +16,13 @@ import ( "github.com/cosmos/cosmos-sdk/codec/types" ) +var DefaultProviders = depinject.Provide( + ProvideInterfaceRegistry, + ProvideLegacyAmino, + ProvideProtoCodec, + ProvideAddressCodec, +) + func ProvideInterfaceRegistry( addressCodec address.Codec, validatorAddressCodec address.ValidatorAddressCodec, diff --git a/core/server/config.go b/core/server/config.go new file mode 100644 index 000000000000..4c3150de5666 --- /dev/null +++ b/core/server/config.go @@ -0,0 +1,6 @@ +package server + +type DynamicConfig interface { + GetString(string) string + UnmarshalSub(string, any) (bool, error) +} diff --git a/runtime/v2/builder.go b/runtime/v2/builder.go index 33e4f46bb77a..538ba32e15d9 100644 --- a/runtime/v2/builder.go +++ b/runtime/v2/builder.go @@ -7,10 +7,9 @@ import ( "io" "path/filepath" - "github.com/spf13/viper" - "cosmossdk.io/core/appmodule" appmodulev2 "cosmossdk.io/core/appmodule/v2" + "cosmossdk.io/core/server" "cosmossdk.io/core/store" "cosmossdk.io/core/transaction" "cosmossdk.io/server/v2/appmanager" @@ -20,13 +19,18 @@ import ( rootstore "cosmossdk.io/store/v2/root" ) +type configProvider interface { + GetString(string) string + UnmarshalSub(string, any) (bool, error) +} + // AppBuilder is a type that is injected into a container by the runtime/v2 module // (as *AppBuilder) which can be used to create an app which is compatible with // the existing app.go initialization conventions. type AppBuilder[T transaction.Tx] struct { app *App[T] storeOptions *rootstore.FactoryOptions - viper *viper.Viper + config server.DynamicConfig // the following fields are used to overwrite the default branch func(state store.ReaderMap) store.WriterMap @@ -125,14 +129,13 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { a.app.stf = stf storeOpts := rootstore.DefaultStoreOptions() - if s := a.viper.Sub("store.options"); s != nil { - if err := s.Unmarshal(&storeOpts); err != nil { - return nil, fmt.Errorf("failed to unmarshal store options: %w", err) - } + ok, err := a.config.UnmarshalSub("store.options", &storeOpts) + if ok && err != nil { + return nil, fmt.Errorf("failed to unmarshal store options: %w", err) } - home := a.viper.GetString(FlagHome) - scRawDb, err := db.NewDB(db.DBType(a.viper.GetString("store.app-db-backend")), "application", filepath.Join(home, "data"), nil) + home := a.config.GetString(FlagHome) + scRawDb, err := db.NewDB(db.DBType(a.config.GetString("store.app-db-backend")), "application", filepath.Join(home, "data"), nil) if err != nil { panic(err) } diff --git a/runtime/v2/module.go b/runtime/v2/module.go index 1cda0a577fd4..3a9aafe3f06d 100644 --- a/runtime/v2/module.go +++ b/runtime/v2/module.go @@ -6,7 +6,6 @@ import ( "slices" "github.com/cosmos/gogoproto/proto" - "github.com/spf13/viper" "google.golang.org/grpc" "google.golang.org/protobuf/reflect/protodesc" "google.golang.org/protobuf/reflect/protoregistry" @@ -18,6 +17,7 @@ import ( appmodulev2 "cosmossdk.io/core/appmodule/v2" "cosmossdk.io/core/comet" "cosmossdk.io/core/registry" + "cosmossdk.io/core/server" "cosmossdk.io/core/store" "cosmossdk.io/core/transaction" "cosmossdk.io/depinject" @@ -145,7 +145,7 @@ type AppInputs struct { InterfaceRegistrar registry.InterfaceRegistrar LegacyAmino registry.AminoRegistrar Logger log.Logger - Viper *viper.Viper `optional:"true"` // can be nil in client wiring + DynamicConfig server.DynamicConfig `optional:"true"` // can be nil in client wiring } func SetupAppBuilder(inputs AppInputs) { @@ -156,8 +156,8 @@ func SetupAppBuilder(inputs AppInputs) { app.moduleManager.RegisterInterfaces(inputs.InterfaceRegistrar) app.moduleManager.RegisterLegacyAminoCodec(inputs.LegacyAmino) - if inputs.Viper != nil { - inputs.AppBuilder.viper = inputs.Viper + if inputs.DynamicConfig != nil { + inputs.AppBuilder.config = inputs.DynamicConfig } } diff --git a/simapp/v2/app_di.go b/simapp/v2/app_di.go index 3d780f7cc601..2afaf060066a 100644 --- a/simapp/v2/app_di.go +++ b/simapp/v2/app_di.go @@ -151,6 +151,9 @@ func NewSimApp[T transaction.Tx]( codec.ProvideAddressCodec, codec.ProvideProtoCodec, codec.ProvideLegacyAmino, + func() server.DynamicConfig { + return &viperWrapper{viper} + }, ), depinject.Invoke( std.RegisterInterfaces, @@ -235,3 +238,17 @@ func (app *SimApp[T]) GetConsensusAuthority() string { func (app *SimApp[T]) GetStore() any { return app.App.GetStore() } + +var _ server.DynamicConfig = &viperWrapper{} + +type viperWrapper struct { + *viper.Viper +} + +func (v *viperWrapper) UnmarshalSub(key string, cfg any) (bool, error) { + s := v.Viper.Sub(key) + if s == nil { + return false, nil + } + return true, s.Unmarshal(cfg) +} diff --git a/store/v2/db/db.go b/store/v2/db/db.go index a8c741e45424..6dcd800f18dd 100644 --- a/store/v2/db/db.go +++ b/store/v2/db/db.go @@ -22,7 +22,6 @@ func NewDB(dbType DBType, name, dataDir string, opts store.DBOptions) (corestore switch dbType { case DBTypeGoLevelDB: return NewGoLevelDB(name, dataDir, opts) - case DBTypePebbleDB: return NewPebbleDB(name, dataDir) } diff --git a/tests/integration/bank/app_test.go b/tests/integration/bank/app_test.go index 6db4b4a0ff70..e0e2a81a134e 100644 --- a/tests/integration/bank/app_test.go +++ b/tests/integration/bank/app_test.go @@ -8,9 +8,11 @@ import ( "github.com/stretchr/testify/require" "cosmossdk.io/core/header" + "cosmossdk.io/core/transaction" "cosmossdk.io/depinject" "cosmossdk.io/log" sdkmath "cosmossdk.io/math" + runtimev2 "cosmossdk.io/runtime/v2" _ "cosmossdk.io/x/accounts" bankkeeper "cosmossdk.io/x/bank/keeper" "cosmossdk.io/x/bank/testutil" @@ -29,6 +31,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/runtime" + integrationv2 "github.com/cosmos/cosmos-sdk/tests/integration/v2" "github.com/cosmos/cosmos-sdk/testutil/configurator" simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" @@ -75,6 +78,7 @@ type suite struct { AccountKeeper types.AccountKeeper DistributionKeeper distrkeeper.Keeper App *runtime.App + Appv2 *runtimev2.App[transaction.Tx] TxConfig client.TxConfig } @@ -89,27 +93,31 @@ func createTestSuite(t *testing.T, genesisAccounts []authtypes.GenesisAccount) s startupCfg := simtestutil.DefaultStartUpConfig() startupCfg.GenesisAccounts = genAccounts - - app, err := simtestutil.SetupWithConfiguration( - depinject.Configs( - configurator.NewAppConfig( - configurator.AccountsModule(), - configurator.AuthModule(), - configurator.StakingModule(), - configurator.TxModule(), - configurator.ConsensusModule(), - configurator.BankModule(), - configurator.GovModule(), - configurator.DistributionModule(), - configurator.ProtocolPoolModule(), - ), - depinject.Supply(log.NewNopLogger()), - ), + moduleConfigs := []configurator.ModuleOption{ + configurator.AccountsModule(), + configurator.AuthModule(), + configurator.StakingModule(), + configurator.TxModule(), + configurator.ConsensusModule(), + configurator.BankModule(), + configurator.GovModule(), + configurator.DistributionModule(), + configurator.ProtocolPoolModule(), + } + var err error + res.App, err = simtestutil.SetupWithConfiguration( + depinject.Configs(configurator.NewAppConfig(moduleConfigs...), depinject.Supply(log.NewNopLogger())), startupCfg, &res.BankKeeper, &res.AccountKeeper, &res.DistributionKeeper, &res.TxConfig) + require.NoError(t, err) - res.App = app - + v2StartupCfg := integrationv2.DefaultStartUpConfig() + v2StartupCfg.HomeDir = t.TempDir() + res.Appv2, err = integrationv2.SetupWithConfiguration( + depinject.Configs(configurator.NewAppV2Config(moduleConfigs...), depinject.Supply(log.NewNopLogger())), + v2StartupCfg, + &res.BankKeeper, &res.AccountKeeper, &res.DistributionKeeper, &res.TxConfig) require.NoError(t, err) + return res } diff --git a/tests/integration/v2/app_helpers.go b/tests/integration/v2/app_helpers.go index 38c2dd9b92e4..24a72abcdc06 100644 --- a/tests/integration/v2/app_helpers.go +++ b/tests/integration/v2/app_helpers.go @@ -3,6 +3,7 @@ package integration import ( "context" + "crypto/sha256" "encoding/json" "errors" "fmt" @@ -30,6 +31,7 @@ import ( cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/cosmos/cosmos-sdk/std" "github.com/cosmos/cosmos-sdk/testutil/mock" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/tx" @@ -93,6 +95,7 @@ type StartupConfig struct { AtGenesis bool GenesisAccounts []GenesisAccount DB corestore.KVStoreWithBatch + HomeDir string } func DefaultStartUpConfig() StartupConfig { @@ -140,6 +143,27 @@ func SetupAtGenesis( return SetupWithConfiguration(appConfig, cfg, extraOutputs...) } +var _ server.DynamicConfig = &dynamicConfigImpl{} + +type dynamicConfigImpl struct { + homeDir string +} + +func (d *dynamicConfigImpl) GetString(key string) string { + switch key { + case runtime.FlagHome: + return d.homeDir + case "store.app-db-backend": + return "goleveldb" + default: + panic(fmt.Sprintf("unknown key: %s", key)) + } +} + +func (d *dynamicConfigImpl) UnmarshalSub(string, any) (bool, error) { + return false, nil +} + // SetupWithConfiguration initializes a new runtime.App. A Nop logger is set in runtime.App. // appConfig defines the application configuration (f.e. app_config.go). // extraOutputs defines the extra outputs to be assigned by the dependency injector (depinject). @@ -153,17 +177,24 @@ func SetupWithConfiguration( app *runtime.App[stateMachineTx] appBuilder *runtime.AppBuilder[stateMachineTx] txConfigOptions tx.ConfigOptions - codec codec.Codec + cdc codec.Codec err error ) if err := depinject.Inject( - appConfig, - append(extraOutputs, &appBuilder, &codec, &txConfigOptions)...); err != nil { + depinject.Configs( + appConfig, + codec.DefaultProviders, + depinject.Supply(&dynamicConfigImpl{startupConfig.HomeDir}), + depinject.Invoke( + std.RegisterInterfaces, + ), + ), + append(extraOutputs, &appBuilder, &cdc, &txConfigOptions)...); err != nil { return nil, fmt.Errorf("failed to inject dependencies: %w", err) } - app, err = appBuilder.Build(startupConfig.AppOption) + app, err = appBuilder.Build() if err != nil { return nil, fmt.Errorf("failed to build app: %w", err) } @@ -193,7 +224,7 @@ func SetupWithConfiguration( } genesisState, err := genesisStateWithValSet( - codec, + cdc, app.DefaultGenesis(), valSet, genAccounts, @@ -225,9 +256,17 @@ func SetupWithConfiguration( }, ) + emptyHash := sha256.Sum256(nil) _, _, err = app.InitGenesis( ctx, - &server.BlockRequest[stateMachineTx]{}, + &server.BlockRequest[stateMachineTx]{ + Height: 1, + Time: time.Now(), + Hash: emptyHash[:], + ChainId: "test-chain", + AppHash: emptyHash[:], + IsGenesis: true, + }, stateBytes, &genericTxDecoder{txConfigOptions}, ) diff --git a/testutil/configurator/configurator.go b/testutil/configurator/configurator.go index 91c93ba2d5b0..be348183966b 100644 --- a/testutil/configurator/configurator.go +++ b/testutil/configurator/configurator.go @@ -3,6 +3,7 @@ package configurator import ( accountsmodulev1 "cosmossdk.io/api/cosmos/accounts/module/v1" runtimev1alpha1 "cosmossdk.io/api/cosmos/app/runtime/v1alpha1" + runtimev2 "cosmossdk.io/api/cosmos/app/runtime/v2" appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1" authmodulev1 "cosmossdk.io/api/cosmos/auth/module/v1" authzmodulev1 "cosmossdk.io/api/cosmos/authz/module/v1" @@ -426,3 +427,71 @@ func NewAppConfig(opts ...ModuleOption) depinject.Config { return appconfig.Compose(&appv1alpha1.Config{Modules: modules}) } + +func NewAppV2Config(opts ...ModuleOption) depinject.Config { + cfg := defaultConfig() + for _, opt := range opts { + opt(cfg) + } + + preBlockers := make([]string, 0) + beginBlockers := make([]string, 0) + endBlockers := make([]string, 0) + initGenesis := make([]string, 0) + overrides := make([]*runtimev2.StoreKeyConfig, 0) + + for _, s := range cfg.PreBlockersOrder { + if _, ok := cfg.ModuleConfigs[s]; ok { + preBlockers = append(preBlockers, s) + } + } + + for _, s := range cfg.BeginBlockersOrder { + if _, ok := cfg.ModuleConfigs[s]; ok { + beginBlockers = append(beginBlockers, s) + } + } + + for _, s := range cfg.EndBlockersOrder { + if _, ok := cfg.ModuleConfigs[s]; ok { + endBlockers = append(endBlockers, s) + } + } + + for _, s := range cfg.InitGenesisOrder { + if _, ok := cfg.ModuleConfigs[s]; ok { + initGenesis = append(initGenesis, s) + } + } + + if _, ok := cfg.ModuleConfigs[testutil.AuthModuleName]; ok { + overrides = append(overrides, &runtimev2.StoreKeyConfig{ModuleName: testutil.AuthModuleName, KvStoreKey: "acc"}) + } + + runtimeConfig := &runtimev2.Module{ + AppName: "TestApp", + PreBlockers: preBlockers, + BeginBlockers: beginBlockers, + EndBlockers: endBlockers, + OverrideStoreKeys: overrides, + GasConfig: &runtimev2.GasConfig{ + ValidateTxGasLimit: 100_000, + QueryGasLimit: 100_000, + SimulationGasLimit: 100_000, + }, + } + if cfg.setInitGenesis { + runtimeConfig.InitGenesis = initGenesis + } + + modules := []*appv1alpha1.ModuleConfig{{ + Name: "runtime", + Config: appconfig.WrapAny(runtimeConfig), + }} + + for _, m := range cfg.ModuleConfigs { + modules = append(modules, m) + } + + return appconfig.Compose(&appv1alpha1.Config{Modules: modules}) +} From ba91038a328f092897293564a4acaf33cb137683 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Tue, 10 Sep 2024 09:24:31 -0500 Subject: [PATCH 06/57] refactor: remove viper as a direct dependency --- core/server/config.go | 6 ++++++ go.mod | 1 + go.sum | 2 -- runtime/v2/builder.go | 21 ++++++++++++--------- runtime/v2/go.mod | 15 +-------------- runtime/v2/go.sum | 35 ----------------------------------- runtime/v2/module.go | 8 ++++---- simapp/v2/app_di.go | 16 +++++++++++++++- simapp/v2/go.mod | 1 + x/auth/tx/config/depinject.go | 8 ++++---- 10 files changed, 44 insertions(+), 69 deletions(-) create mode 100644 core/server/config.go diff --git a/core/server/config.go b/core/server/config.go new file mode 100644 index 000000000000..4c3150de5666 --- /dev/null +++ b/core/server/config.go @@ -0,0 +1,6 @@ +package server + +type DynamicConfig interface { + GetString(string) string + UnmarshalSub(string, any) (bool, error) +} diff --git a/go.mod b/go.mod index b4af001f234e..0906eecab9ec 100644 --- a/go.mod +++ b/go.mod @@ -186,6 +186,7 @@ require ( replace ( cosmossdk.io/api => ./api cosmossdk.io/collections => ./collections + cosmossdk.io/core => ./core cosmossdk.io/core/testing => ./core/testing cosmossdk.io/store => ./store cosmossdk.io/x/bank => ./x/bank diff --git a/go.sum b/go.sum index f0812105d45b..6a656b750879 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,6 @@ buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88e buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88ef6483f90f.2/go.mod h1:HqcXMSa5qnNuakaMUo+hWhF51mKbcrZxGl9Vp5EeJXc= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cosmossdk.io/core v1.0.0-alpha.1 h1:iElkDJhxmy51aLMSLMZcfsqcv4QG4/1UHbHiW8Llw6k= -cosmossdk.io/core v1.0.0-alpha.1/go.mod h1:abgLjeFLhtuKIYZWSPlVUgQBrKObO7ULV35KYfexE90= cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050= cosmossdk.io/depinject v1.0.0/go.mod h1:zxK/h3HgHoA/eJVtiSsoaRaRA2D5U4cJ5thIG4ssbB8= cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= diff --git a/runtime/v2/builder.go b/runtime/v2/builder.go index 33e4f46bb77a..538ba32e15d9 100644 --- a/runtime/v2/builder.go +++ b/runtime/v2/builder.go @@ -7,10 +7,9 @@ import ( "io" "path/filepath" - "github.com/spf13/viper" - "cosmossdk.io/core/appmodule" appmodulev2 "cosmossdk.io/core/appmodule/v2" + "cosmossdk.io/core/server" "cosmossdk.io/core/store" "cosmossdk.io/core/transaction" "cosmossdk.io/server/v2/appmanager" @@ -20,13 +19,18 @@ import ( rootstore "cosmossdk.io/store/v2/root" ) +type configProvider interface { + GetString(string) string + UnmarshalSub(string, any) (bool, error) +} + // AppBuilder is a type that is injected into a container by the runtime/v2 module // (as *AppBuilder) which can be used to create an app which is compatible with // the existing app.go initialization conventions. type AppBuilder[T transaction.Tx] struct { app *App[T] storeOptions *rootstore.FactoryOptions - viper *viper.Viper + config server.DynamicConfig // the following fields are used to overwrite the default branch func(state store.ReaderMap) store.WriterMap @@ -125,14 +129,13 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { a.app.stf = stf storeOpts := rootstore.DefaultStoreOptions() - if s := a.viper.Sub("store.options"); s != nil { - if err := s.Unmarshal(&storeOpts); err != nil { - return nil, fmt.Errorf("failed to unmarshal store options: %w", err) - } + ok, err := a.config.UnmarshalSub("store.options", &storeOpts) + if ok && err != nil { + return nil, fmt.Errorf("failed to unmarshal store options: %w", err) } - home := a.viper.GetString(FlagHome) - scRawDb, err := db.NewDB(db.DBType(a.viper.GetString("store.app-db-backend")), "application", filepath.Join(home, "data"), nil) + home := a.config.GetString(FlagHome) + scRawDb, err := db.NewDB(db.DBType(a.config.GetString("store.app-db-backend")), "application", filepath.Join(home, "data"), nil) if err != nil { panic(err) } diff --git a/runtime/v2/go.mod b/runtime/v2/go.mod index e898e3c0035e..51ec7919d1c1 100644 --- a/runtime/v2/go.mod +++ b/runtime/v2/go.mod @@ -5,6 +5,7 @@ go 1.23 // server v2 integration replace ( cosmossdk.io/api => ../../api + cosmossdk.io/core => ../../core cosmossdk.io/core/testing => ../../core/testing cosmossdk.io/server/v2/appmanager => ../../server/v2/appmanager cosmossdk.io/server/v2/stf => ../../server/v2/stf @@ -22,7 +23,6 @@ require ( cosmossdk.io/store/v2 v2.0.0-00010101000000-000000000000 cosmossdk.io/x/tx v0.13.3 github.com/cosmos/gogoproto v1.7.0 - github.com/spf13/viper v1.19.0 google.golang.org/grpc v1.66.1 google.golang.org/protobuf v1.34.2 ) @@ -45,7 +45,6 @@ require ( github.com/cosmos/ics23/go v0.11.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/dot v1.6.2 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/getsentry/sentry-go v0.27.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/snappy v0.0.4 // indirect @@ -54,19 +53,15 @@ require ( github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-metrics v0.5.3 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/linxGnu/grocksdb v1.8.14 // indirect - github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-sqlite3 v1.14.22 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/onsi/gomega v1.28.1 // indirect - github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.20.3 // indirect @@ -75,18 +70,11 @@ require ( github.com/prometheus/procfs v0.15.1 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/rs/zerolog v1.33.0 // indirect - github.com/sagikazarmark/locafero v0.4.0 // indirect - github.com/sagikazarmark/slog-shim v0.1.0 // indirect - github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.7.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/testify v1.9.0 // indirect - github.com/subosito/gotenv v1.6.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tendermint/go-amino v0.16.0 // indirect github.com/tidwall/btree v1.7.0 // indirect - go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.27.0 // indirect golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect golang.org/x/net v0.29.0 // indirect @@ -95,7 +83,6 @@ require ( golang.org/x/text v0.18.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect - gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/runtime/v2/go.sum b/runtime/v2/go.sum index 17b285973436..7ef0e6524b68 100644 --- a/runtime/v2/go.sum +++ b/runtime/v2/go.sum @@ -2,8 +2,6 @@ buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.34.2-20240701160653-fed buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.34.2-20240701160653-fedbb9acfd2f.2/go.mod h1:1+3gJj2NvZ1mTLAtHu+lMhOjGgQPiCKCeo+9MBww0Eo= buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88ef6483f90f.2 h1:b7EEYTUHmWSBEyISHlHvXbJPqtKiHRuUignL1tsHnNQ= buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88ef6483f90f.2/go.mod h1:HqcXMSa5qnNuakaMUo+hWhF51mKbcrZxGl9Vp5EeJXc= -cosmossdk.io/core v1.0.0-alpha.1 h1:iElkDJhxmy51aLMSLMZcfsqcv4QG4/1UHbHiW8Llw6k= -cosmossdk.io/core v1.0.0-alpha.1/go.mod h1:abgLjeFLhtuKIYZWSPlVUgQBrKObO7ULV35KYfexE90= cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050= cosmossdk.io/depinject v1.0.0/go.mod h1:zxK/h3HgHoA/eJVtiSsoaRaRA2D5U4cJ5thIG4ssbB8= cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5 h1:IQNdY2kB+k+1OM2DvqFG1+UgeU1JzZrWtwuWzI3ZfwA= @@ -123,8 +121,6 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -145,8 +141,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/linxGnu/grocksdb v1.8.14 h1:HTgyYalNwBSG/1qCQUIott44wU5b2Y9Kr3z7SK5OfGQ= github.com/linxGnu/grocksdb v1.8.14/go.mod h1:QYiYypR2d4v63Wj1adOOfzglnoII0gLj3PNh4fZkcFA= -github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= -github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -156,8 +150,6 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -182,8 +174,6 @@ github.com/onsi/gomega v1.28.1 h1:MijcGUbfYuznzK/5R4CPNoUP/9Xvuo20sXfEm6XxoTA= github.com/onsi/gomega v1.28.1/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= -github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -219,39 +209,19 @@ github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99 github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= -github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= -github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= -github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= -github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= -github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= -github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= -github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= -github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= -github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= @@ -263,8 +233,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -363,8 +331,6 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -373,7 +339,6 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= diff --git a/runtime/v2/module.go b/runtime/v2/module.go index 1cda0a577fd4..3a9aafe3f06d 100644 --- a/runtime/v2/module.go +++ b/runtime/v2/module.go @@ -6,7 +6,6 @@ import ( "slices" "github.com/cosmos/gogoproto/proto" - "github.com/spf13/viper" "google.golang.org/grpc" "google.golang.org/protobuf/reflect/protodesc" "google.golang.org/protobuf/reflect/protoregistry" @@ -18,6 +17,7 @@ import ( appmodulev2 "cosmossdk.io/core/appmodule/v2" "cosmossdk.io/core/comet" "cosmossdk.io/core/registry" + "cosmossdk.io/core/server" "cosmossdk.io/core/store" "cosmossdk.io/core/transaction" "cosmossdk.io/depinject" @@ -145,7 +145,7 @@ type AppInputs struct { InterfaceRegistrar registry.InterfaceRegistrar LegacyAmino registry.AminoRegistrar Logger log.Logger - Viper *viper.Viper `optional:"true"` // can be nil in client wiring + DynamicConfig server.DynamicConfig `optional:"true"` // can be nil in client wiring } func SetupAppBuilder(inputs AppInputs) { @@ -156,8 +156,8 @@ func SetupAppBuilder(inputs AppInputs) { app.moduleManager.RegisterInterfaces(inputs.InterfaceRegistrar) app.moduleManager.RegisterLegacyAminoCodec(inputs.LegacyAmino) - if inputs.Viper != nil { - inputs.AppBuilder.viper = inputs.Viper + if inputs.DynamicConfig != nil { + inputs.AppBuilder.config = inputs.DynamicConfig } } diff --git a/simapp/v2/app_di.go b/simapp/v2/app_di.go index 3d780f7cc601..27e7559ae9a3 100644 --- a/simapp/v2/app_di.go +++ b/simapp/v2/app_di.go @@ -104,7 +104,7 @@ func NewSimApp[T transaction.Tx]( AppConfig(), depinject.Supply( logger, - viper, + &viperWrapper{viper}, // DynamicConfig // ADVANCED CONFIGURATION @@ -235,3 +235,17 @@ func (app *SimApp[T]) GetConsensusAuthority() string { func (app *SimApp[T]) GetStore() any { return app.App.GetStore() } + +var _ server.DynamicConfig = &viperWrapper{} + +type viperWrapper struct { + *viper.Viper +} + +func (v *viperWrapper) UnmarshalSub(key string, cfg any) (bool, error) { + s := v.Viper.Sub(key) + if s == nil { + return false, nil + } + return true, s.Unmarshal(cfg) +} diff --git a/simapp/v2/go.mod b/simapp/v2/go.mod index ab2e5368aae6..cb2fb4f72522 100644 --- a/simapp/v2/go.mod +++ b/simapp/v2/go.mod @@ -288,6 +288,7 @@ replace ( replace ( cosmossdk.io/api => ../../api cosmossdk.io/core/testing => ../../core/testing + cosmossdk.io/core => ../../core cosmossdk.io/runtime/v2 => ../../runtime/v2 cosmossdk.io/server/v2 => ../../server/v2 cosmossdk.io/server/v2/appmanager => ../../server/v2/appmanager diff --git a/x/auth/tx/config/depinject.go b/x/auth/tx/config/depinject.go index 7bd438c6767d..d9d58bb225c2 100644 --- a/x/auth/tx/config/depinject.go +++ b/x/auth/tx/config/depinject.go @@ -6,7 +6,6 @@ import ( "fmt" gogoproto "github.com/cosmos/gogoproto/proto" - "github.com/spf13/viper" "google.golang.org/grpc" "google.golang.org/grpc/codes" grpcstatus "google.golang.org/grpc/status" @@ -16,6 +15,7 @@ import ( txconfigv1 "cosmossdk.io/api/cosmos/tx/config/v1" "cosmossdk.io/core/address" appmodulev2 "cosmossdk.io/core/appmodule/v2" + "cosmossdk.io/core/server" "cosmossdk.io/core/transaction" "cosmossdk.io/depinject" "cosmossdk.io/depinject/appconfig" @@ -65,7 +65,7 @@ type ModuleInputs struct { ExtraTxValidators []appmodulev2.TxValidator[transaction.Tx] `optional:"true"` UnorderedTxManager *unorderedtx.Manager `optional:"true"` TxFeeChecker ante.TxFeeChecker `optional:"true"` - Viper *viper.Viper `optional:"true"` // server v2 + DynamicConfig server.DynamicConfig `optional:"true"` } type ModuleOutputs struct { @@ -125,8 +125,8 @@ func ProvideModule(in ModuleInputs) ModuleOutputs { feeTxValidator *ante.DeductFeeDecorator unorderedTxValidator *ante.UnorderedTxDecorator ) - if in.AccountKeeper != nil && in.BankKeeper != nil && in.Viper != nil { - minGasPricesStr := in.Viper.GetString(flagMinGasPricesV2) + if in.AccountKeeper != nil && in.BankKeeper != nil && in.DynamicConfig != nil { + minGasPricesStr := in.DynamicConfig.GetString(flagMinGasPricesV2) minGasPrices, err = sdk.ParseDecCoins(minGasPricesStr) if err != nil { panic(fmt.Sprintf("invalid minimum gas prices: %v", err)) From c4d08343a46d2c11536f4d5baa3904119e0f704e Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Tue, 10 Sep 2024 09:28:39 -0500 Subject: [PATCH 07/57] remove unused interface --- runtime/v2/builder.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/runtime/v2/builder.go b/runtime/v2/builder.go index 538ba32e15d9..ab940c79e731 100644 --- a/runtime/v2/builder.go +++ b/runtime/v2/builder.go @@ -19,11 +19,6 @@ import ( rootstore "cosmossdk.io/store/v2/root" ) -type configProvider interface { - GetString(string) string - UnmarshalSub(string, any) (bool, error) -} - // AppBuilder is a type that is injected into a container by the runtime/v2 module // (as *AppBuilder) which can be used to create an app which is compatible with // the existing app.go initialization conventions. From a080b2ed98a10eb2f83370a5a6a8c232d30f0967 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Wed, 11 Sep 2024 10:34:17 -0500 Subject: [PATCH 08/57] not sure how this ended up so big --- core/server/config.go | 2 +- runtime/v2/builder.go | 37 ++++++++------ simapp/simd/cmd/testnet_test.go | 6 ++- simapp/v2/app_di.go | 32 +++++------- simapp/v2/simdv2/cmd/commands.go | 49 ++++++++++--------- .../integration/genutil}/export_test.go | 2 +- .../integration/genutil}/genaccount_test.go | 34 ++++++++++--- .../integration/genutil}/init_test.go | 20 ++++---- testutil/network/util.go | 8 ++- .../x/genutil/helper.go | 2 +- x/genutil/v2/cli/commands.go | 7 ++- x/genutil/v2/cli/export.go | 10 ++-- x/genutil/v2/types.go | 3 -- x/upgrade/depinject.go | 13 ++--- x/upgrade/go.mod | 1 + 15 files changed, 128 insertions(+), 98 deletions(-) rename {x/genutil/client/cli => tests/integration/genutil}/export_test.go (99%) rename {x/genutil/client/cli => tests/integration/genutil}/genaccount_test.go (90%) rename {x/genutil/client/cli => tests/integration/genutil}/init_test.go (94%) rename x/genutil/client/testutil/helpers.go => testutil/x/genutil/helper.go (99%) diff --git a/core/server/config.go b/core/server/config.go index 4c3150de5666..bac396651ce6 100644 --- a/core/server/config.go +++ b/core/server/config.go @@ -1,6 +1,6 @@ package server type DynamicConfig interface { + Get(string) any GetString(string) string - UnmarshalSub(string, any) (bool, error) } diff --git a/runtime/v2/builder.go b/runtime/v2/builder.go index ab940c79e731..115eda507b52 100644 --- a/runtime/v2/builder.go +++ b/runtime/v2/builder.go @@ -24,8 +24,8 @@ import ( // the existing app.go initialization conventions. type AppBuilder[T transaction.Tx] struct { app *App[T] - storeOptions *rootstore.FactoryOptions config server.DynamicConfig + storeOptions rootstore.Options // the following fields are used to overwrite the default branch func(state store.ReaderMap) store.WriterMap @@ -72,9 +72,6 @@ func (a *AppBuilder[T]) RegisterModules(modules map[string]appmodulev2.AppModule // To be used in combination of RegisterModules. func (a *AppBuilder[T]) RegisterStores(keys ...string) { a.app.storeKeys = append(a.app.storeKeys, keys...) - if a.storeOptions != nil { - a.storeOptions.StoreKeys = append(a.storeOptions.StoreKeys, keys...) - } } // Build builds an *App instance. @@ -123,28 +120,26 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { } a.app.stf = stf - storeOpts := rootstore.DefaultStoreOptions() - ok, err := a.config.UnmarshalSub("store.options", &storeOpts) - if ok && err != nil { - return nil, fmt.Errorf("failed to unmarshal store options: %w", err) - } - home := a.config.GetString(FlagHome) - scRawDb, err := db.NewDB(db.DBType(a.config.GetString("store.app-db-backend")), "application", filepath.Join(home, "data"), nil) + scRawDb, err := db.NewDB( + db.DBType(a.config.GetString("store.app-db-backend")), + "application", + filepath.Join(home, "data"), + nil, + ) if err != nil { panic(err) } - storeOptions := &rootstore.FactoryOptions{ + factoryOptions := &rootstore.FactoryOptions{ Logger: a.app.logger, RootDir: home, - Options: storeOpts, + Options: a.storeOptions, StoreKeys: append(a.app.storeKeys, "stf"), SCRawDB: scRawDb, } - a.storeOptions = storeOptions - rs, err := rootstore.CreateRootStore(a.storeOptions) + rs, err := rootstore.CreateRootStore(factoryOptions) if err != nil { return nil, fmt.Errorf("failed to create root store: %w", err) } @@ -207,7 +202,11 @@ func AppBuilderWithBranch[T transaction.Tx](branch func(state store.ReaderMap) s // AppBuilderWithTxValidator sets the tx validator for the app. // It overrides all default tx validators defined by modules. -func AppBuilderWithTxValidator[T transaction.Tx](txValidators func(ctx context.Context, tx T) error) AppBuilderOption[T] { +func AppBuilderWithTxValidator[T transaction.Tx]( + txValidators func( + ctx context.Context, tx T, + ) error, +) AppBuilderOption[T] { return func(a *AppBuilder[T]) { a.txValidator = txValidators } @@ -226,3 +225,9 @@ func AppBuilderWithPostTxExec[T transaction.Tx]( a.postTxExec = postTxExec } } + +func AppBuilderWithStoreOptions[T transaction.Tx](opts rootstore.Options) AppBuilderOption[T] { + return func(a *AppBuilder[T]) { + a.storeOptions = opts + } +} diff --git a/simapp/simd/cmd/testnet_test.go b/simapp/simd/cmd/testnet_test.go index 2e2653c20e4b..f60a56596c27 100644 --- a/simapp/simd/cmd/testnet_test.go +++ b/simapp/simd/cmd/testnet_test.go @@ -18,10 +18,10 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil" "github.com/cosmos/cosmos-sdk/testutil/configurator" + genutiltest "github.com/cosmos/cosmos-sdk/testutil/x/genutil" "github.com/cosmos/cosmos-sdk/types/module" moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" "github.com/cosmos/cosmos-sdk/x/auth" - genutiltest "github.com/cosmos/cosmos-sdk/x/genutil/client/testutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" ) @@ -72,7 +72,9 @@ func Test_TestnetCmd(t *testing.T) { ctx = context.WithValue(ctx, corectx.LoggerContextKey, logger) ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx) cmd := testnetInitFilesCmd(moduleManager) - cmd.SetArgs([]string{fmt.Sprintf("--%s=test", flags.FlagKeyringBackend), fmt.Sprintf("--output-dir=%s", home)}) + cmd.SetArgs( + []string{fmt.Sprintf("--%s=test", flags.FlagKeyringBackend), fmt.Sprintf("--output-dir=%s", home)}, + ) err = cmd.ExecuteContext(ctx) require.NoError(t, err) diff --git a/simapp/v2/app_di.go b/simapp/v2/app_di.go index 27e7559ae9a3..441e44eaa7ac 100644 --- a/simapp/v2/app_di.go +++ b/simapp/v2/app_di.go @@ -1,6 +1,7 @@ package simapp import ( + "cosmossdk.io/store/v2/root" _ "embed" "github.com/spf13/viper" @@ -96,15 +97,17 @@ func NewSimApp[T transaction.Tx]( viper *viper.Viper, ) *SimApp[T] { var ( - app = &SimApp[T]{} - appBuilder *runtime.AppBuilder[T] + app = &SimApp[T]{} + appBuilder *runtime.AppBuilder[T] + err error + storeOptions = root.DefaultStoreOptions() // merge the AppConfig and other configuration in one config appConfig = depinject.Configs( AppConfig(), depinject.Supply( logger, - &viperWrapper{viper}, // DynamicConfig + viper, // ADVANCED CONFIGURATION @@ -187,8 +190,13 @@ func NewSimApp[T transaction.Tx]( panic(err) } - var err error - app.App, err = appBuilder.Build() + if sub := viper.Sub("store.options"); sub != nil { + err = sub.Unmarshal(&storeOptions) + if err != nil { + panic(err) + } + } + app.App, err = appBuilder.Build(runtime.AppBuilderWithStoreOptions[T](storeOptions)) if err != nil { panic(err) } @@ -235,17 +243,3 @@ func (app *SimApp[T]) GetConsensusAuthority() string { func (app *SimApp[T]) GetStore() any { return app.App.GetStore() } - -var _ server.DynamicConfig = &viperWrapper{} - -type viperWrapper struct { - *viper.Viper -} - -func (v *viperWrapper) UnmarshalSub(key string, cfg any) (bool, error) { - s := v.Viper.Sub(key) - if s == nil { - return false, nil - } - return true, s.Unmarshal(cfg) -} diff --git a/simapp/v2/simdv2/cmd/commands.go b/simapp/v2/simdv2/cmd/commands.go index eaa3483d4ea1..7023987db604 100644 --- a/simapp/v2/simdv2/cmd/commands.go +++ b/simapp/v2/simdv2/cmd/commands.go @@ -56,14 +56,15 @@ func initRootCmd[T transaction.Tx]( NewTestnetCmd(moduleManager), ) - logger, err := serverv2.NewLogger(viper.New(), rootCmd.OutOrStdout()) + viper := serverv2.GetViperFromCmd(rootCmd) + logger, err := serverv2.NewLogger(viper, rootCmd.OutOrStdout()) if err != nil { panic(fmt.Sprintf("failed to create logger: %v", err)) } // add keybase, auxiliary RPC, query, genesis, and tx child commands rootCmd.AddCommand( - genesisCommand(moduleManager, appExport[T]), + genesisCommand(moduleManager, newAppExporter[T](logger, viper)), queryCommand(), txCommand(), keys.Commands(), @@ -90,7 +91,11 @@ func genesisCommand[T transaction.Tx]( appExport genutilv2.AppExporter, cmds ...*cobra.Command, ) *cobra.Command { - cmd := v2.Commands(moduleManager.Modules()[genutiltypes.ModuleName].(genutil.AppModule), moduleManager, appExport) + cmd := v2.Commands( + moduleManager.Modules()[genutiltypes.ModuleName].(genutil.AppModule), + moduleManager, + appExport, + ) for _, subCmd := range cmds { cmd.AddCommand(subCmd) @@ -141,29 +146,25 @@ func txCommand() *cobra.Command { return cmd } -// appExport creates a new simapp (optionally at a given height) and exports state. -func appExport[T transaction.Tx]( - logger log.Logger, - height int64, - jailAllowedAddrs []string, - viper *viper.Viper, -) (genutilv2.ExportedApp, error) { - // overwrite the FlagInvCheckPeriod - viper.Set(server.FlagInvCheckPeriod, 1) - viper.Set(serverv2.FlagHome, simapp.DefaultNodeHome) - - var simApp *simapp.SimApp[T] - if height != -1 { - simApp = simapp.NewSimApp[T](logger, viper) - - if err := simApp.LoadHeight(uint64(height)); err != nil { - return genutilv2.ExportedApp{}, err +func newAppExporter[T transaction.Tx](logger log.Logger, viper *viper.Viper) genutilv2.AppExporter { + return func(height int64, jailAllowedAddrs []string) (genutilv2.ExportedApp, error) { + // overwrite the FlagInvCheckPeriod + viper.Set(server.FlagInvCheckPeriod, 1) + viper.Set(serverv2.FlagHome, simapp.DefaultNodeHome) + + var simApp *simapp.SimApp[T] + if height != -1 { + simApp = simapp.NewSimApp[T](logger, viper) + + if err := simApp.LoadHeight(uint64(height)); err != nil { + return genutilv2.ExportedApp{}, err + } + } else { + simApp = simapp.NewSimApp[T](logger, viper) } - } else { - simApp = simapp.NewSimApp[T](logger, viper) - } - return simApp.ExportAppStateAndValidators(jailAllowedAddrs) + return simApp.ExportAppStateAndValidators(jailAllowedAddrs) + } } var _ transaction.Codec[transaction.Tx] = &genericTxDecoder[transaction.Tx]{} diff --git a/x/genutil/client/cli/export_test.go b/tests/integration/genutil/export_test.go similarity index 99% rename from x/genutil/client/cli/export_test.go rename to tests/integration/genutil/export_test.go index 270fa98bfaed..e583aa59e970 100644 --- a/x/genutil/client/cli/export_test.go +++ b/tests/integration/genutil/export_test.go @@ -1,4 +1,4 @@ -package cli_test +package genutil import ( "context" diff --git a/x/genutil/client/cli/genaccount_test.go b/tests/integration/genutil/genaccount_test.go similarity index 90% rename from x/genutil/client/cli/genaccount_test.go rename to tests/integration/genutil/genaccount_test.go index c75894f3a2fc..739adda97d2b 100644 --- a/x/genutil/client/cli/genaccount_test.go +++ b/tests/integration/genutil/genaccount_test.go @@ -1,4 +1,4 @@ -package cli_test +package genutil import ( "context" @@ -19,12 +19,12 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/testutil/testdata" + genutilhelpers "github.com/cosmos/cosmos-sdk/testutil/x/genutil" sdk "github.com/cosmos/cosmos-sdk/types" moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/genutil" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" - genutiltest "github.com/cosmos/cosmos-sdk/x/genutil/client/testutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" ) @@ -78,10 +78,13 @@ func TestAddGenesisAccountCmd(t *testing.T) { logger := log.NewNopLogger() v := viper.New() - encodingConfig := moduletestutil.MakeTestEncodingConfig(codectestutil.CodecOptions{}, auth.AppModule{}) + encodingConfig := moduletestutil.MakeTestEncodingConfig( + codectestutil.CodecOptions{}, + auth.AppModule{}, + ) appCodec := encodingConfig.Codec txConfig := encodingConfig.TxConfig - err = genutiltest.ExecInitCmd(testMbm, home, appCodec) + err = genutilhelpers.ExecInitCmd(testMbm, home, appCodec) require.NoError(t, err) err := writeAndTrackDefaultConfig(v, home) @@ -93,7 +96,13 @@ func TestAddGenesisAccountCmd(t *testing.T) { path := hd.CreateHDPath(118, 0, 0).String() kr, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendMemory, home, nil, appCodec) require.NoError(t, err) - _, _, err = kr.NewMnemonic(tc.addr, keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1) + _, _, err = kr.NewMnemonic( + tc.addr, + keyring.English, + path, + keyring.DefaultBIP39Passphrase, + hd.Secp256k1, + ) require.NoError(t, err) clientCtx = clientCtx.WithKeyring(kr) } @@ -214,10 +223,13 @@ func TestBulkAddGenesisAccountCmd(t *testing.T) { logger := log.NewNopLogger() v := viper.New() - encodingConfig := moduletestutil.MakeTestEncodingConfig(codectestutil.CodecOptions{}, auth.AppModule{}) + encodingConfig := moduletestutil.MakeTestEncodingConfig( + codectestutil.CodecOptions{}, + auth.AppModule{}, + ) appCodec := encodingConfig.Codec txConfig := encodingConfig.TxConfig - err = genutiltest.ExecInitCmd(testMbm, home, appCodec) + err = genutilhelpers.ExecInitCmd(testMbm, home, appCodec) require.NoError(t, err) err = writeAndTrackDefaultConfig(v, home) @@ -269,7 +281,13 @@ func TestBulkAddGenesisAccountCmd(t *testing.T) { require.EqualValues(t, len(tc.expected), len(bankState.Balances)) for _, acc := range bankState.Balances { - require.True(t, tc.expected[acc.Address].Equal(acc.Coins), "expected: %v, got: %v", tc.expected[acc.Address], acc.Coins) + require.True( + t, + tc.expected[acc.Address].Equal(acc.Coins), + "expected: %v, got: %v", + tc.expected[acc.Address], + acc.Coins, + ) } expectedSupply := sdk.NewCoins() diff --git a/x/genutil/client/cli/init_test.go b/tests/integration/genutil/init_test.go similarity index 94% rename from x/genutil/client/cli/init_test.go rename to tests/integration/genutil/init_test.go index 7dfa70b688d0..9116db0ce8fe 100644 --- a/x/genutil/client/cli/init_test.go +++ b/tests/integration/genutil/init_test.go @@ -1,4 +1,4 @@ -package cli_test +package genutil import ( "bytes" @@ -28,11 +28,11 @@ import ( "github.com/cosmos/cosmos-sdk/server/mock" "github.com/cosmos/cosmos-sdk/testutil" "github.com/cosmos/cosmos-sdk/testutil/network" + genutilhelpers "github.com/cosmos/cosmos-sdk/testutil/x/genutil" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/genutil" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" - genutiltest "github.com/cosmos/cosmos-sdk/x/genutil/client/testutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" ) @@ -125,7 +125,9 @@ func TestInitRecover(t *testing.T) { }) // use valid mnemonic and complete recovery key generation successfully - mockIn.Reset("decide praise business actor peasant farm drastic weather extend front hurt later song give verb rhythm worry fun pond reform school tumble august one\n") + mockIn.Reset( + "decide praise business actor peasant farm drastic weather extend front hurt later song give verb rhythm worry fun pond reform school tumble august one\n", + ) require.NoError(t, cmd.ExecuteContext(ctx)) } @@ -213,7 +215,7 @@ func TestStartStandAlone(t *testing.T) { logger := log.NewNopLogger() interfaceRegistry := types.NewInterfaceRegistry() marshaler := codec.NewProtoCodec(interfaceRegistry) - err := genutiltest.ExecInitCmd(testMbm, home, marshaler) + err := genutilhelpers.ExecInitCmd(testMbm, home, marshaler) require.NoError(t, err) app, err := mock.NewApp(home, logger) @@ -241,7 +243,7 @@ func TestStartStandAlone(t *testing.T) { func TestInitNodeValidatorFiles(t *testing.T) { home := t.TempDir() - cfg, err := genutiltest.CreateDefaultCometConfig(home) + cfg, err := genutilhelpers.CreateDefaultCometConfig(home) require.NoError(t, err) nodeID, valPubKey, err := genutil.InitializeNodeValidatorFiles(cfg, ed25519.KeyType) @@ -303,7 +305,7 @@ func TestInitWithHeight(t *testing.T) { home := t.TempDir() logger := log.NewNopLogger() viper := viper.New() - cfg, err := genutiltest.CreateDefaultCometConfig(home) + cfg, err := genutilhelpers.CreateDefaultCometConfig(home) require.NoError(t, err) err = writeAndTrackDefaultConfig(viper, home) @@ -340,7 +342,7 @@ func TestInitWithNegativeHeight(t *testing.T) { home := t.TempDir() logger := log.NewNopLogger() viper := viper.New() - cfg, err := genutiltest.CreateDefaultCometConfig(home) + cfg, err := genutilhelpers.CreateDefaultCometConfig(home) require.NoError(t, err) err = writeAndTrackDefaultConfig(viper, home) @@ -385,9 +387,9 @@ func makeCodec() codec.Codec { } func writeAndTrackDefaultConfig(v *viper.Viper, home string) error { - cfg, err := genutiltest.CreateDefaultCometConfig(home) + cfg, err := genutilhelpers.CreateDefaultCometConfig(home) if err != nil { return err } - return genutiltest.WriteAndTrackCometConfig(v, home, cfg) + return genutilhelpers.WriteAndTrackCometConfig(v, home, cfg) } diff --git a/testutil/network/util.go b/testutil/network/util.go index cc2297f77fcd..08ee1b0c5d99 100644 --- a/testutil/network/util.go +++ b/testutil/network/util.go @@ -23,6 +23,7 @@ import ( banktypes "cosmossdk.io/x/bank/types" "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/server/api" servergrpc "github.com/cosmos/cosmos-sdk/server/grpc" @@ -30,7 +31,6 @@ import ( "github.com/cosmos/cosmos-sdk/testutil" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/genutil" - genutiltest "github.com/cosmos/cosmos-sdk/x/genutil/client/testutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" ) @@ -180,7 +180,11 @@ func collectGenFiles(cfg Config, vals []*Validator, cmtConfigs []*cmtcfg.Config, } v := vals[i].GetViper() - err = genutiltest.TrackCometConfig(v, nodeDir) + v.Set(flags.FlagHome, nodeDir) + v.SetConfigType("toml") + v.SetConfigName("config") + v.AddConfigPath(filepath.Join(nodeDir, "config")) + err = v.ReadInConfig() if err != nil { return err } diff --git a/x/genutil/client/testutil/helpers.go b/testutil/x/genutil/helper.go similarity index 99% rename from x/genutil/client/testutil/helpers.go rename to testutil/x/genutil/helper.go index 459f325bc755..a6eae578d0f0 100644 --- a/x/genutil/client/testutil/helpers.go +++ b/testutil/x/genutil/helper.go @@ -1,4 +1,4 @@ -package testutil +package genutil import ( "context" diff --git a/x/genutil/v2/cli/commands.go b/x/genutil/v2/cli/commands.go index 515bf329a52a..7b871ec074a4 100644 --- a/x/genutil/v2/cli/commands.go +++ b/x/genutil/v2/cli/commands.go @@ -26,7 +26,12 @@ func Commands(genutilModule genutil.AppModule, genMM genesisMM, appExport v2.App // CommandsWithCustomMigrationMap adds core sdk's sub-commands into genesis command with custom migration map. // This custom migration map can be used by the application to add its own migration map. -func CommandsWithCustomMigrationMap(genutilModule genutil.AppModule, genMM genesisMM, appExport v2.AppExporter, migrationMap genutiltypes.MigrationMap) *cobra.Command { +func CommandsWithCustomMigrationMap( + genutilModule genutil.AppModule, + genMM genesisMM, + appExport v2.AppExporter, + migrationMap genutiltypes.MigrationMap, +) *cobra.Command { cmd := &cobra.Command{ Use: "genesis", Short: "Application's genesis-related subcommands", diff --git a/x/genutil/v2/cli/export.go b/x/genutil/v2/cli/export.go index c19a02f870e3..80ad95157f50 100644 --- a/x/genutil/v2/cli/export.go +++ b/x/genutil/v2/cli/export.go @@ -29,8 +29,6 @@ func ExportCmd(appExporter v2.AppExporter) *cobra.Command { Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { config := client.GetConfigFromCmd(cmd) - viper := client.GetViperFromCmd(cmd) - logger := client.GetLoggerFromCmd(cmd) if _, err := os.Stat(config.GenesisFile()); os.IsNotExist(err) { return err @@ -62,7 +60,7 @@ func ExportCmd(appExporter v2.AppExporter) *cobra.Command { jailAllowedAddrs, _ := cmd.Flags().GetStringSlice(flagJailAllowedAddrs) outputDocument, _ := cmd.Flags().GetString(flags.FlagOutputDocument) - exported, err := appExporter(logger, height, jailAllowedAddrs, viper) + exported, err := appExporter(height, jailAllowedAddrs) if err != nil { return fmt.Errorf("error exporting state: %w", err) } @@ -99,8 +97,10 @@ func ExportCmd(appExporter v2.AppExporter) *cobra.Command { } cmd.Flags().Int64(flagHeight, -1, "Export state from a particular height (-1 means latest height)") - cmd.Flags().StringSlice(flagJailAllowedAddrs, []string{}, "Comma-separated list of operator addresses of jailed validators to unjail") - cmd.Flags().String(flags.FlagOutputDocument, "", "Exported state is written to the given file instead of STDOUT") + cmd.Flags(). + StringSlice(flagJailAllowedAddrs, []string{}, "Comma-separated list of operator addresses of jailed validators to unjail") + cmd.Flags(). + String(flags.FlagOutputDocument, "", "Exported state is written to the given file instead of STDOUT") return cmd } diff --git a/x/genutil/v2/types.go b/x/genutil/v2/types.go index 1b94c8bbc9be..18e0ab35e2bd 100644 --- a/x/genutil/v2/types.go +++ b/x/genutil/v2/types.go @@ -3,8 +3,6 @@ package v2 import ( "encoding/json" - "github.com/spf13/viper" - "cosmossdk.io/log" ) @@ -14,7 +12,6 @@ type AppExporter func( logger log.Logger, height int64, jailAllowedAddrs []string, - viper *viper.Viper, ) (ExportedApp, error) // ExportedApp represents an exported app state, along with diff --git a/x/upgrade/depinject.go b/x/upgrade/depinject.go index bc36da63285a..2f9b438213aa 100644 --- a/x/upgrade/depinject.go +++ b/x/upgrade/depinject.go @@ -2,12 +2,12 @@ package upgrade import ( "github.com/spf13/cast" - "github.com/spf13/viper" modulev1 "cosmossdk.io/api/cosmos/upgrade/module/v1" "cosmossdk.io/core/address" "cosmossdk.io/core/appmodule" coreserver "cosmossdk.io/core/server" + serverv2 "cosmossdk.io/core/server" "cosmossdk.io/depinject" "cosmossdk.io/depinject/appconfig" "cosmossdk.io/x/upgrade/keeper" @@ -42,8 +42,8 @@ type ModuleInputs struct { AddressCodec address.Codec AppVersionModifier coreserver.VersionModifier - AppOpts servertypes.AppOptions `optional:"true"` // server v0 - Viper *viper.Viper `optional:"true"` // server v2 + AppOpts servertypes.AppOptions `optional:"true"` // server v0 + DynamicConfig serverv2.DynamicConfig `optional:"true"` // server v2 } type ModuleOutputs struct { @@ -59,12 +59,13 @@ func ProvideModule(in ModuleInputs) ModuleOutputs { skipUpgradeHeights = make(map[int64]bool) ) - if in.Viper != nil { // viper takes precedence over app options - for _, h := range in.Viper.GetIntSlice(server.FlagUnsafeSkipUpgrades) { + if in.DynamicConfig != nil { // v2 takes precedence over v1 app options + skipUpgrades := cast.ToIntSlice(in.DynamicConfig.Get(server.FlagUnsafeSkipUpgrades)) + for _, h := range skipUpgrades { skipUpgradeHeights[int64(h)] = true } - homePath = in.Viper.GetString(flags.FlagHome) + homePath = in.DynamicConfig.GetString(flags.FlagHome) } else if in.AppOpts != nil { for _, h := range cast.ToIntSlice(in.AppOpts.Get(server.FlagUnsafeSkipUpgrades)) { skipUpgradeHeights[int64(h)] = true diff --git a/x/upgrade/go.mod b/x/upgrade/go.mod index 36306eef520d..c8ba2ea80817 100644 --- a/x/upgrade/go.mod +++ b/x/upgrade/go.mod @@ -204,6 +204,7 @@ replace github.com/cosmos/cosmos-sdk => ../../. replace ( cosmossdk.io/api => ../../api + cosmossdk.io/core => ../../core cosmossdk.io/core/testing => ../../core/testing cosmossdk.io/store => ../../store cosmossdk.io/x/bank => ../bank From f09a8fec26e216bd1d2ce6b45b69a30a18cff08c Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Wed, 11 Sep 2024 11:01:44 -0500 Subject: [PATCH 09/57] clean up --- simapp/v2/simdv2/cmd/commands.go | 62 ++++++++++++++++++++------------ simapp/v2/simdv2/cmd/root_di.go | 2 +- x/genutil/v2/cli/export.go | 2 +- x/genutil/v2/types.go | 5 ++- 4 files changed, 43 insertions(+), 28 deletions(-) diff --git a/simapp/v2/simdv2/cmd/commands.go b/simapp/v2/simdv2/cmd/commands.go index 7023987db604..2e315c64a186 100644 --- a/simapp/v2/simdv2/cmd/commands.go +++ b/simapp/v2/simdv2/cmd/commands.go @@ -1,6 +1,7 @@ package cmd import ( + "context" "errors" "fmt" @@ -8,6 +9,7 @@ import ( "github.com/spf13/viper" "cosmossdk.io/client/v2/offchain" + corectx "cosmossdk.io/core/context" "cosmossdk.io/core/transaction" "cosmossdk.io/log" runtimev2 "cosmossdk.io/runtime/v2" @@ -56,15 +58,14 @@ func initRootCmd[T transaction.Tx]( NewTestnetCmd(moduleManager), ) - viper := serverv2.GetViperFromCmd(rootCmd) - logger, err := serverv2.NewLogger(viper, rootCmd.OutOrStdout()) + logger, err := serverv2.NewLogger(viper.New(), rootCmd.OutOrStdout()) if err != nil { panic(fmt.Sprintf("failed to create logger: %v", err)) } // add keybase, auxiliary RPC, query, genesis, and tx child commands rootCmd.AddCommand( - genesisCommand(moduleManager, newAppExporter[T](logger, viper)), + genesisCommand(moduleManager), queryCommand(), txCommand(), keys.Commands(), @@ -85,16 +86,15 @@ func initRootCmd[T transaction.Tx]( } } -// genesisCommand builds genesis-related `simd genesis` command. Users may provide application specific commands as a parameter +// genesisCommand builds genesis-related `simd genesis` command. func genesisCommand[T transaction.Tx]( moduleManager *runtimev2.MM[T], - appExport genutilv2.AppExporter, cmds ...*cobra.Command, ) *cobra.Command { cmd := v2.Commands( moduleManager.Modules()[genutiltypes.ModuleName].(genutil.AppModule), moduleManager, - appExport, + appExport[T], ) for _, subCmd := range cmds { @@ -146,25 +146,41 @@ func txCommand() *cobra.Command { return cmd } -func newAppExporter[T transaction.Tx](logger log.Logger, viper *viper.Viper) genutilv2.AppExporter { - return func(height int64, jailAllowedAddrs []string) (genutilv2.ExportedApp, error) { - // overwrite the FlagInvCheckPeriod - viper.Set(server.FlagInvCheckPeriod, 1) - viper.Set(serverv2.FlagHome, simapp.DefaultNodeHome) - - var simApp *simapp.SimApp[T] - if height != -1 { - simApp = simapp.NewSimApp[T](logger, viper) - - if err := simApp.LoadHeight(uint64(height)); err != nil { - return genutilv2.ExportedApp{}, err - } - } else { - simApp = simapp.NewSimApp[T](logger, viper) - } +// appExport creates a new simapp (optionally at a given height) and exports state. +func appExport[T transaction.Tx]( + ctx context.Context, + height int64, + jailAllowedAddrs []string, +) (genutilv2.ExportedApp, error) { + value := ctx.Value(corectx.ViperContextKey) + viper, ok := value.(*viper.Viper) + if !ok { + return genutilv2.ExportedApp{}, + fmt.Errorf("incorrect viper type %T: expected *viper.Viper in context", value) + } + value = ctx.Value(corectx.LoggerContextKey) + logger, ok := value.(log.Logger) + if !ok { + return genutilv2.ExportedApp{}, + fmt.Errorf("incorrect logger type %T: expected log.Logger in context", value) + } - return simApp.ExportAppStateAndValidators(jailAllowedAddrs) + // overwrite the FlagInvCheckPeriod + viper.Set(server.FlagInvCheckPeriod, 1) + viper.Set(serverv2.FlagHome, simapp.DefaultNodeHome) + + var simApp *simapp.SimApp[T] + if height != -1 { + simApp = simapp.NewSimApp[T](logger, viper) + + if err := simApp.LoadHeight(uint64(height)); err != nil { + return genutilv2.ExportedApp{}, err + } + } else { + simApp = simapp.NewSimApp[T](logger, viper) } + + return simApp.ExportAppStateAndValidators(jailAllowedAddrs) } var _ transaction.Codec[transaction.Tx] = &genericTxDecoder[transaction.Tx]{} diff --git a/simapp/v2/simdv2/cmd/root_di.go b/simapp/v2/simdv2/cmd/root_di.go index 9653106d36c1..fd5b62b9384b 100644 --- a/simapp/v2/simdv2/cmd/root_di.go +++ b/simapp/v2/simdv2/cmd/root_di.go @@ -82,7 +82,7 @@ func NewRootCmd[T transaction.Tx]() *cobra.Command { }, } - initRootCmd[T](rootCmd, clientCtx.TxConfig, moduleManager) + initRootCmd(rootCmd, clientCtx.TxConfig, moduleManager) nodeCmds := nodeservice.NewNodeCommands() autoCliOpts.ModuleOptions = make(map[string]*autocliv1.ModuleOptions) diff --git a/x/genutil/v2/cli/export.go b/x/genutil/v2/cli/export.go index 80ad95157f50..318ad58d8a47 100644 --- a/x/genutil/v2/cli/export.go +++ b/x/genutil/v2/cli/export.go @@ -60,7 +60,7 @@ func ExportCmd(appExporter v2.AppExporter) *cobra.Command { jailAllowedAddrs, _ := cmd.Flags().GetStringSlice(flagJailAllowedAddrs) outputDocument, _ := cmd.Flags().GetString(flags.FlagOutputDocument) - exported, err := appExporter(height, jailAllowedAddrs) + exported, err := appExporter(cmd.Context(), height, jailAllowedAddrs) if err != nil { return fmt.Errorf("error exporting state: %w", err) } diff --git a/x/genutil/v2/types.go b/x/genutil/v2/types.go index 18e0ab35e2bd..3199a5a5afb4 100644 --- a/x/genutil/v2/types.go +++ b/x/genutil/v2/types.go @@ -1,15 +1,14 @@ package v2 import ( + "context" "encoding/json" - - "cosmossdk.io/log" ) // AppExporter is a function that dumps all app state to // JSON-serializable structure and returns the current validator set. type AppExporter func( - logger log.Logger, + ctx context.Context, height int64, jailAllowedAddrs []string, ) (ExportedApp, error) From ce51d9e0a9fc55d25f117d763bbaa9e545d2fff9 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Wed, 11 Sep 2024 11:05:10 -0500 Subject: [PATCH 10/57] go mod tidy all --- simapp/v2/go.mod | 2 +- simapp/v2/go.sum | 2 -- tests/e2e/genutil/export_test.go | 2 +- tests/go.mod | 2 +- x/upgrade/go.mod | 4 ++-- x/upgrade/go.sum | 2 -- 6 files changed, 5 insertions(+), 9 deletions(-) diff --git a/simapp/v2/go.mod b/simapp/v2/go.mod index cb2fb4f72522..bd4a502a9750 100644 --- a/simapp/v2/go.mod +++ b/simapp/v2/go.mod @@ -287,8 +287,8 @@ replace ( // server v2 integration replace ( cosmossdk.io/api => ../../api - cosmossdk.io/core/testing => ../../core/testing cosmossdk.io/core => ../../core + cosmossdk.io/core/testing => ../../core/testing cosmossdk.io/runtime/v2 => ../../runtime/v2 cosmossdk.io/server/v2 => ../../server/v2 cosmossdk.io/server/v2/appmanager => ../../server/v2/appmanager diff --git a/simapp/v2/go.sum b/simapp/v2/go.sum index 3c065e3b33b5..7e5bce683a3a 100644 --- a/simapp/v2/go.sum +++ b/simapp/v2/go.sum @@ -192,8 +192,6 @@ cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xX cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cosmossdk.io/core v1.0.0-alpha.1 h1:iElkDJhxmy51aLMSLMZcfsqcv4QG4/1UHbHiW8Llw6k= -cosmossdk.io/core v1.0.0-alpha.1/go.mod h1:abgLjeFLhtuKIYZWSPlVUgQBrKObO7ULV35KYfexE90= cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050= cosmossdk.io/depinject v1.0.0/go.mod h1:zxK/h3HgHoA/eJVtiSsoaRaRA2D5U4cJ5thIG4ssbB8= cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= diff --git a/tests/e2e/genutil/export_test.go b/tests/e2e/genutil/export_test.go index cb41aa53d2c5..a920a9e6f9e0 100644 --- a/tests/e2e/genutil/export_test.go +++ b/tests/e2e/genutil/export_test.go @@ -30,9 +30,9 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/server/types" simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + gentestutil "github.com/cosmos/cosmos-sdk/testutil/x/genutil" "github.com/cosmos/cosmos-sdk/x/genutil" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" - gentestutil "github.com/cosmos/cosmos-sdk/x/genutil/client/testutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" ) diff --git a/tests/go.mod b/tests/go.mod index 8da1a0ffb34a..ff042592ccf8 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -50,6 +50,7 @@ require ( github.com/google/go-cmp v0.6.0 github.com/google/gofuzz v1.2.0 github.com/jhump/protoreflect v1.17.0 + github.com/rs/zerolog v1.33.0 github.com/spf13/viper v1.19.0 ) @@ -180,7 +181,6 @@ require ( github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/rs/cors v1.11.0 // indirect - github.com/rs/zerolog v1.33.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sasha-s/go-deadlock v0.3.5 // indirect diff --git a/x/upgrade/go.mod b/x/upgrade/go.mod index c8ba2ea80817..cde367e43de1 100644 --- a/x/upgrade/go.mod +++ b/x/upgrade/go.mod @@ -26,7 +26,6 @@ require ( github.com/spf13/cast v1.7.0 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 google.golang.org/grpc v1.66.1 @@ -161,6 +160,7 @@ require ( github.com/sasha-s/go-deadlock v0.3.5 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/viper v1.19.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/supranational/blst v0.3.13 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect @@ -204,7 +204,7 @@ replace github.com/cosmos/cosmos-sdk => ../../. replace ( cosmossdk.io/api => ../../api - cosmossdk.io/core => ../../core + cosmossdk.io/core => ../../core cosmossdk.io/core/testing => ../../core/testing cosmossdk.io/store => ../../store cosmossdk.io/x/bank => ../bank diff --git a/x/upgrade/go.sum b/x/upgrade/go.sum index c613fe60dd7d..c3ed86c29f1d 100644 --- a/x/upgrade/go.sum +++ b/x/upgrade/go.sum @@ -194,8 +194,6 @@ cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1V cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s= cosmossdk.io/collections v0.4.0/go.mod h1:oa5lUING2dP+gdDquow+QjlF45eL1t4TJDypgGd+tv0= -cosmossdk.io/core v1.0.0-alpha.1 h1:iElkDJhxmy51aLMSLMZcfsqcv4QG4/1UHbHiW8Llw6k= -cosmossdk.io/core v1.0.0-alpha.1/go.mod h1:abgLjeFLhtuKIYZWSPlVUgQBrKObO7ULV35KYfexE90= cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050= cosmossdk.io/depinject v1.0.0/go.mod h1:zxK/h3HgHoA/eJVtiSsoaRaRA2D5U4cJ5thIG4ssbB8= cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= From 441423d7b892477e579a878b46e5dde341a1565e Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Wed, 11 Sep 2024 11:25:38 -0500 Subject: [PATCH 11/57] lint fix --- server/v2/cometbft/abci_test.go | 16 +++++++--------- server/v2/cometbft/internal/mock/mock_store.go | 3 +-- simapp/v2/app_di.go | 3 ++- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/server/v2/cometbft/abci_test.go b/server/v2/cometbft/abci_test.go index 64b321630cc0..fc67c2aa9635 100644 --- a/server/v2/cometbft/abci_test.go +++ b/server/v2/cometbft/abci_test.go @@ -3,11 +3,18 @@ package cometbft import ( "context" "crypto/sha256" + "encoding/json" "io" "strings" "testing" "time" + abciproto "github.com/cometbft/cometbft/api/cometbft/abci/v1" + v1 "github.com/cometbft/cometbft/api/cometbft/types/v1" + "github.com/cosmos/gogoproto/proto" + gogotypes "github.com/cosmos/gogoproto/types" + "github.com/stretchr/testify/require" + appmodulev2 "cosmossdk.io/core/appmodule/v2" "cosmossdk.io/core/store" "cosmossdk.io/core/transaction" @@ -20,16 +27,7 @@ import ( "cosmossdk.io/server/v2/stf" "cosmossdk.io/server/v2/stf/branch" "cosmossdk.io/server/v2/stf/mock" - abciproto "github.com/cometbft/cometbft/api/cometbft/abci/v1" - v1 "github.com/cometbft/cometbft/api/cometbft/types/v1" - - "github.com/cosmos/gogoproto/proto" - - "encoding/json" - consensustypes "cosmossdk.io/x/consensus/types" - gogotypes "github.com/cosmos/gogoproto/types" - "github.com/stretchr/testify/require" ) var ( diff --git a/server/v2/cometbft/internal/mock/mock_store.go b/server/v2/cometbft/internal/mock/mock_store.go index dee4d8baf915..e3e7f4dc708c 100644 --- a/server/v2/cometbft/internal/mock/mock_store.go +++ b/server/v2/cometbft/internal/mock/mock_store.go @@ -6,7 +6,6 @@ import ( "cosmossdk.io/core/log" corestore "cosmossdk.io/core/store" - storev2 "cosmossdk.io/store/v2" "cosmossdk.io/store/v2/commitment" "cosmossdk.io/store/v2/commitment/iavl" @@ -17,7 +16,7 @@ import ( ) type MockStore struct { - Storage storev2.VersionedDatabase + Storage storev2.VersionedDatabase Committer storev2.Committer } diff --git a/simapp/v2/app_di.go b/simapp/v2/app_di.go index 441e44eaa7ac..06b3456f61a2 100644 --- a/simapp/v2/app_di.go +++ b/simapp/v2/app_di.go @@ -1,9 +1,9 @@ package simapp import ( - "cosmossdk.io/store/v2/root" _ "embed" + "github.com/spf13/viper" clienthelpers "cosmossdk.io/client/v2/helpers" @@ -13,6 +13,7 @@ import ( "cosmossdk.io/depinject" "cosmossdk.io/log" "cosmossdk.io/runtime/v2" + "cosmossdk.io/store/v2/root" "cosmossdk.io/x/accounts" authzkeeper "cosmossdk.io/x/authz/keeper" bankkeeper "cosmossdk.io/x/bank/keeper" From 7e508c39a3043d79aaf4909373d142a0371fa29f Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Wed, 11 Sep 2024 11:27:04 -0500 Subject: [PATCH 12/57] fix simapp v1 build with core replace --- simapp/go.mod | 1 + 1 file changed, 1 insertion(+) diff --git a/simapp/go.mod b/simapp/go.mod index 592237457cba..8ba341e967b6 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -241,6 +241,7 @@ replace ( cosmossdk.io/api => ../api cosmossdk.io/client/v2 => ../client/v2 cosmossdk.io/collections => ../collections + cosmossdk.io/core => ../core cosmossdk.io/core/testing => ../core/testing cosmossdk.io/store => ../store cosmossdk.io/tools/confix => ../tools/confix From 99c2a5c301b3f39c066980bd12dfe8388f90487d Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Wed, 11 Sep 2024 11:27:42 -0500 Subject: [PATCH 13/57] add comment --- core/server/config.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/server/config.go b/core/server/config.go index bac396651ce6..997633fe46b3 100644 --- a/core/server/config.go +++ b/core/server/config.go @@ -1,5 +1,7 @@ package server +// DynamicConfig defines an interface for configuration that can be dynamically +// fetched at runtime by an arbitrary key. type DynamicConfig interface { Get(string) any GetString(string) string From e0c9e3d9328397b120bf1ab8fd7ce11559e86812 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Wed, 11 Sep 2024 11:30:54 -0500 Subject: [PATCH 14/57] go mod tidy all --- simapp/go.sum | 2 -- 1 file changed, 2 deletions(-) diff --git a/simapp/go.sum b/simapp/go.sum index 4998b693ccd9..bdff4b296d92 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -192,8 +192,6 @@ cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xX cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cosmossdk.io/core v1.0.0-alpha.1 h1:iElkDJhxmy51aLMSLMZcfsqcv4QG4/1UHbHiW8Llw6k= -cosmossdk.io/core v1.0.0-alpha.1/go.mod h1:abgLjeFLhtuKIYZWSPlVUgQBrKObO7ULV35KYfexE90= cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050= cosmossdk.io/depinject v1.0.0/go.mod h1:zxK/h3HgHoA/eJVtiSsoaRaRA2D5U4cJ5thIG4ssbB8= cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= From 2d28d64592a92fdccc2f1346510a4bb6b4bfd6cc Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Wed, 11 Sep 2024 11:47:56 -0500 Subject: [PATCH 15/57] wip --- tests/go.mod | 10 ++++++++++ tests/go.sum | 10 ++++++++-- tests/integration/v2/app_helpers.go | 4 ++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/tests/go.mod b/tests/go.mod index ff042592ccf8..b828ec3d3c64 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -34,6 +34,7 @@ require ( require ( cosmossdk.io/core/testing v0.0.0-00010101000000-000000000000 + cosmossdk.io/runtime/v2 v2.0.0-20240911143651-72620a577660 cosmossdk.io/x/accounts v0.0.0-20240226161501-23359a0b6d91 cosmossdk.io/x/accounts/defaults/lockup v0.0.0-20240417181816-5e7aae0db1f5 cosmossdk.io/x/accounts/defaults/multisig v0.0.0-00010101000000-000000000000 @@ -65,7 +66,11 @@ require ( cloud.google.com/go/storage v1.43.0 // indirect cosmossdk.io/client/v2 v2.0.0-20230630094428-02b760776860 // indirect cosmossdk.io/errors v1.0.1 // indirect + cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5 // indirect cosmossdk.io/schema v0.2.0 // indirect + cosmossdk.io/server/v2/appmanager v0.0.0-00010101000000-000000000000 // indirect + cosmossdk.io/server/v2/stf v0.0.0-00010101000000-000000000000 // indirect + cosmossdk.io/store/v2 v2.0.0-00010101000000-000000000000 // indirect cosmossdk.io/x/circuit v0.0.0-20230613133644-0a778132a60f // indirect cosmossdk.io/x/epochs v0.0.0-20240522060652-a1ae4c3e0337 // indirect filippo.io/edwards25519 v1.1.0 // indirect @@ -162,6 +167,7 @@ require ( github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-sqlite3 v1.14.22 // indirect github.com/minio/highwayhash v1.0.3 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect @@ -237,8 +243,12 @@ replace ( cosmossdk.io/api => ../api cosmossdk.io/client/v2 => ../client/v2 cosmossdk.io/collections => ../collections + cosmossdk.io/core => ../core cosmossdk.io/core/testing => ../core/testing + cosmossdk.io/server/v2/appmanager => ../server/v2/appmanager + cosmossdk.io/server/v2/stf => ../server/v2/stf cosmossdk.io/store => ../store + cosmossdk.io/store/v2 => ../store/v2 cosmossdk.io/x/accounts => ../x/accounts cosmossdk.io/x/accounts/defaults/lockup => ../x/accounts/defaults/lockup cosmossdk.io/x/accounts/defaults/multisig => ../x/accounts/defaults/multisig diff --git a/tests/go.sum b/tests/go.sum index 5a4c6593f4e0..e85dc34ff39c 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -192,16 +192,18 @@ cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xX cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cosmossdk.io/core v1.0.0-alpha.1 h1:iElkDJhxmy51aLMSLMZcfsqcv4QG4/1UHbHiW8Llw6k= -cosmossdk.io/core v1.0.0-alpha.1/go.mod h1:abgLjeFLhtuKIYZWSPlVUgQBrKObO7ULV35KYfexE90= cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050= cosmossdk.io/depinject v1.0.0/go.mod h1:zxK/h3HgHoA/eJVtiSsoaRaRA2D5U4cJ5thIG4ssbB8= cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= cosmossdk.io/errors v1.0.1/go.mod h1:MeelVSZThMi4bEakzhhhE/CKqVv3nOJDA25bIqRDu/U= +cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5 h1:IQNdY2kB+k+1OM2DvqFG1+UgeU1JzZrWtwuWzI3ZfwA= +cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5/go.mod h1:0CuYKkFHxc1vw2JC+t21THBCALJVROrWVR/3PQ1urpc= cosmossdk.io/log v1.4.1 h1:wKdjfDRbDyZRuWa8M+9nuvpVYxrEOwbD/CA8hvhU8QM= cosmossdk.io/log v1.4.1/go.mod h1:k08v0Pyq+gCP6phvdI6RCGhLf/r425UT6Rk/m+o74rU= cosmossdk.io/math v1.3.0 h1:RC+jryuKeytIiictDslBP9i1fhkVm6ZDmZEoNP316zE= cosmossdk.io/math v1.3.0/go.mod h1:vnRTxewy+M7BtXBNFybkuhSH4WfedVAAnERHgVFhp3k= +cosmossdk.io/runtime/v2 v2.0.0-20240911143651-72620a577660 h1:NgyI4yInpx2y4JahKsPiwOEOxqG3lQ0dzfoOyHhNHCE= +cosmossdk.io/runtime/v2 v2.0.0-20240911143651-72620a577660/go.mod h1:Y3FOIo7VrpECV02VOtMIOiKzwREB68TzPABo4psaK/g= cosmossdk.io/schema v0.2.0 h1:UH5CR1DqUq8yP+5Np8PbvG4YX0zAUsTN2Qk6yThmfMk= cosmossdk.io/schema v0.2.0/go.mod h1:RDAhxIeNB4bYqAlF4NBJwRrgtnciMcyyg0DOKnhNZQQ= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= @@ -648,6 +650,8 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= @@ -839,6 +843,8 @@ go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVf go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= diff --git a/tests/integration/v2/app_helpers.go b/tests/integration/v2/app_helpers.go index 24a72abcdc06..4d7d03373c43 100644 --- a/tests/integration/v2/app_helpers.go +++ b/tests/integration/v2/app_helpers.go @@ -149,6 +149,10 @@ type dynamicConfigImpl struct { homeDir string } +func (d *dynamicConfigImpl) Get(key string) any { + return d.GetString(key) +} + func (d *dynamicConfigImpl) GetString(key string) string { switch key { case runtime.FlagHome: From 0e71ce308e719f21e631d68f36acd60943fe3cd4 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Thu, 12 Sep 2024 09:13:02 -0500 Subject: [PATCH 16/57] fix(runtime/v2): provide default factory options if unset in app builder --- runtime/v2/builder.go | 12 +++++++++--- simapp/v2/app_di.go | 4 ++-- simapp/v2/simdv2/cmd/commands.go | 8 ++------ 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/runtime/v2/builder.go b/runtime/v2/builder.go index 2dc6ca7227d2..0a1b279330de 100644 --- a/runtime/v2/builder.go +++ b/runtime/v2/builder.go @@ -25,7 +25,7 @@ import ( type AppBuilder[T transaction.Tx] struct { app *App[T] config server.DynamicConfig - storeOptions rootstore.Options + storeOptions *rootstore.Options // the following fields are used to overwrite the default branch func(state store.ReaderMap) store.WriterMap @@ -131,10 +131,16 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { panic(err) } + var storeOptions rootstore.Options + if a.storeOptions != nil { + storeOptions = *a.storeOptions + } else { + storeOptions = rootstore.DefaultStoreOptions() + } factoryOptions := &rootstore.FactoryOptions{ Logger: a.app.logger, RootDir: home, - Options: a.storeOptions, + Options: storeOptions, StoreKeys: append(a.app.storeKeys, "stf"), SCRawDB: scRawDb, } @@ -216,7 +222,7 @@ func AppBuilderWithPostTxExec[T transaction.Tx](postTxExec func(ctx context.Cont } } -func AppBuilderWithStoreOptions[T transaction.Tx](opts rootstore.Options) AppBuilderOption[T] { +func AppBuilderWithStoreOptions[T transaction.Tx](opts *rootstore.Options) AppBuilderOption[T] { return func(a *AppBuilder[T]) { a.storeOptions = opts } diff --git a/simapp/v2/app_di.go b/simapp/v2/app_di.go index 1411b28823ba..0328f2f3d1c1 100644 --- a/simapp/v2/app_di.go +++ b/simapp/v2/app_di.go @@ -100,7 +100,7 @@ func NewSimApp[T transaction.Tx]( app = &SimApp[T]{} appBuilder *runtime.AppBuilder[T] err error - storeOptions = root.DefaultStoreOptions() + storeOptions *root.Options // merge the AppConfig and other configuration in one config appConfig = depinject.Configs( @@ -191,7 +191,7 @@ func NewSimApp[T transaction.Tx]( } if sub := viper.Sub("store.options"); sub != nil { - err = sub.Unmarshal(&storeOptions) + err = sub.Unmarshal(storeOptions) if err != nil { panic(err) } diff --git a/simapp/v2/simdv2/cmd/commands.go b/simapp/v2/simdv2/cmd/commands.go index 2e315c64a186..d58619170e0d 100644 --- a/simapp/v2/simdv2/cmd/commands.go +++ b/simapp/v2/simdv2/cmd/commands.go @@ -34,13 +34,9 @@ import ( v2 "github.com/cosmos/cosmos-sdk/x/genutil/v2/cli" ) -func newApp[T transaction.Tx]( - logger log.Logger, viper *viper.Viper, -) serverv2.AppI[T] { +func newApp[T transaction.Tx](logger log.Logger, viper *viper.Viper) serverv2.AppI[T] { viper.Set(serverv2.FlagHome, simapp.DefaultNodeHome) - - return serverv2.AppI[T]( - simapp.NewSimApp[T](logger, viper)) + return serverv2.AppI[T](simapp.NewSimApp[T](logger, viper)) } func initRootCmd[T transaction.Tx]( From 3ad2a6e595f4f8c999194ab8f52401c6201bba8b Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Thu, 12 Sep 2024 09:54:49 -0500 Subject: [PATCH 17/57] fix simapp/v2 usage --- simapp/v2/app_di.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simapp/v2/app_di.go b/simapp/v2/app_di.go index 0328f2f3d1c1..d2940eaa495e 100644 --- a/simapp/v2/app_di.go +++ b/simapp/v2/app_di.go @@ -100,7 +100,7 @@ func NewSimApp[T transaction.Tx]( app = &SimApp[T]{} appBuilder *runtime.AppBuilder[T] err error - storeOptions *root.Options + storeOptions = &root.Options{} // merge the AppConfig and other configuration in one config appConfig = depinject.Configs( From d8a6ed70c8a3f06ba1bfbe1cbadcfbd145359b6f Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Thu, 12 Sep 2024 10:30:49 -0500 Subject: [PATCH 18/57] whitespace? --- testutil/rest.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testutil/rest.go b/testutil/rest.go index 5026d1f01b96..3a3103dcbc8b 100644 --- a/testutil/rest.go +++ b/testutil/rest.go @@ -42,7 +42,7 @@ func GetRequestWithHeaders(url string, headers map[string]string) ([]byte, error // GetRequest defines a wrapper around an HTTP GET request with a provided URL. // An error is returned if the request or reading the body fails. func GetRequest(url string) ([]byte, error) { - res, err := http.Get(url) + res, err := http.Get(url) if err != nil { return nil, err } @@ -61,7 +61,7 @@ func GetRequest(url string) ([]byte, error) { // PostRequest defines a wrapper around an HTTP POST request with a provided URL and data. // An error is returned if the request or reading the body fails. func PostRequest(url, contentType string, data []byte) ([]byte, error) { - res, err := http.Post(url, contentType, bytes.NewBuffer(data)) + res, err := http.Post(url, contentType, bytes.NewBuffer(data)) if err != nil { return nil, fmt.Errorf("error while sending post request: %w", err) } From a47a2869b14f3bc45cf9675d440b7b3c5e358fbf Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Thu, 12 Sep 2024 14:07:25 -0500 Subject: [PATCH 19/57] tidy --- go.sum | 2 -- runtime/v2/go.sum | 2 -- simapp/go.sum | 2 -- simapp/v2/go.sum | 2 -- tests/go.sum | 10 ++++++++-- x/upgrade/depinject.go | 1 - x/upgrade/go.sum | 2 -- 7 files changed, 8 insertions(+), 13 deletions(-) diff --git a/go.sum b/go.sum index dc6f9c737341..b7d35ec030c8 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,6 @@ buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88e buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88ef6483f90f.2/go.mod h1:HqcXMSa5qnNuakaMUo+hWhF51mKbcrZxGl9Vp5EeJXc= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cosmossdk.io/core v1.0.0-alpha.2 h1:epU0Xwces4Rgl5bMhHHkXGaGDcyucNGlC/JDH+Suckg= -cosmossdk.io/core v1.0.0-alpha.2/go.mod h1:abgLjeFLhtuKIYZWSPlVUgQBrKObO7ULV35KYfexE90= cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050= cosmossdk.io/depinject v1.0.0/go.mod h1:zxK/h3HgHoA/eJVtiSsoaRaRA2D5U4cJ5thIG4ssbB8= cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= diff --git a/runtime/v2/go.sum b/runtime/v2/go.sum index caef3800e8f3..7ef0e6524b68 100644 --- a/runtime/v2/go.sum +++ b/runtime/v2/go.sum @@ -2,8 +2,6 @@ buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.34.2-20240701160653-fed buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.34.2-20240701160653-fedbb9acfd2f.2/go.mod h1:1+3gJj2NvZ1mTLAtHu+lMhOjGgQPiCKCeo+9MBww0Eo= buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88ef6483f90f.2 h1:b7EEYTUHmWSBEyISHlHvXbJPqtKiHRuUignL1tsHnNQ= buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88ef6483f90f.2/go.mod h1:HqcXMSa5qnNuakaMUo+hWhF51mKbcrZxGl9Vp5EeJXc= -cosmossdk.io/core v1.0.0-alpha.2 h1:epU0Xwces4Rgl5bMhHHkXGaGDcyucNGlC/JDH+Suckg= -cosmossdk.io/core v1.0.0-alpha.2/go.mod h1:abgLjeFLhtuKIYZWSPlVUgQBrKObO7ULV35KYfexE90= cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050= cosmossdk.io/depinject v1.0.0/go.mod h1:zxK/h3HgHoA/eJVtiSsoaRaRA2D5U4cJ5thIG4ssbB8= cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5 h1:IQNdY2kB+k+1OM2DvqFG1+UgeU1JzZrWtwuWzI3ZfwA= diff --git a/simapp/go.sum b/simapp/go.sum index d70338f8e29a..eaac833fcef7 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -192,8 +192,6 @@ cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xX cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cosmossdk.io/core v1.0.0-alpha.2 h1:epU0Xwces4Rgl5bMhHHkXGaGDcyucNGlC/JDH+Suckg= -cosmossdk.io/core v1.0.0-alpha.2/go.mod h1:abgLjeFLhtuKIYZWSPlVUgQBrKObO7ULV35KYfexE90= cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050= cosmossdk.io/depinject v1.0.0/go.mod h1:zxK/h3HgHoA/eJVtiSsoaRaRA2D5U4cJ5thIG4ssbB8= cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= diff --git a/simapp/v2/go.sum b/simapp/v2/go.sum index 69785f8b2780..433016e076b3 100644 --- a/simapp/v2/go.sum +++ b/simapp/v2/go.sum @@ -192,8 +192,6 @@ cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xX cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cosmossdk.io/core v1.0.0-alpha.2 h1:epU0Xwces4Rgl5bMhHHkXGaGDcyucNGlC/JDH+Suckg= -cosmossdk.io/core v1.0.0-alpha.2/go.mod h1:abgLjeFLhtuKIYZWSPlVUgQBrKObO7ULV35KYfexE90= cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050= cosmossdk.io/depinject v1.0.0/go.mod h1:zxK/h3HgHoA/eJVtiSsoaRaRA2D5U4cJ5thIG4ssbB8= cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= diff --git a/tests/go.sum b/tests/go.sum index c84cadbd0f94..c3c06b6c658a 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -192,16 +192,18 @@ cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xX cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cosmossdk.io/core v1.0.0-alpha.2 h1:epU0Xwces4Rgl5bMhHHkXGaGDcyucNGlC/JDH+Suckg= -cosmossdk.io/core v1.0.0-alpha.2/go.mod h1:abgLjeFLhtuKIYZWSPlVUgQBrKObO7ULV35KYfexE90= cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050= cosmossdk.io/depinject v1.0.0/go.mod h1:zxK/h3HgHoA/eJVtiSsoaRaRA2D5U4cJ5thIG4ssbB8= cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= cosmossdk.io/errors v1.0.1/go.mod h1:MeelVSZThMi4bEakzhhhE/CKqVv3nOJDA25bIqRDu/U= +cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5 h1:IQNdY2kB+k+1OM2DvqFG1+UgeU1JzZrWtwuWzI3ZfwA= +cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5/go.mod h1:0CuYKkFHxc1vw2JC+t21THBCALJVROrWVR/3PQ1urpc= cosmossdk.io/log v1.4.1 h1:wKdjfDRbDyZRuWa8M+9nuvpVYxrEOwbD/CA8hvhU8QM= cosmossdk.io/log v1.4.1/go.mod h1:k08v0Pyq+gCP6phvdI6RCGhLf/r425UT6Rk/m+o74rU= cosmossdk.io/math v1.3.0 h1:RC+jryuKeytIiictDslBP9i1fhkVm6ZDmZEoNP316zE= cosmossdk.io/math v1.3.0/go.mod h1:vnRTxewy+M7BtXBNFybkuhSH4WfedVAAnERHgVFhp3k= +cosmossdk.io/runtime/v2 v2.0.0-20240911143651-72620a577660 h1:NgyI4yInpx2y4JahKsPiwOEOxqG3lQ0dzfoOyHhNHCE= +cosmossdk.io/runtime/v2 v2.0.0-20240911143651-72620a577660/go.mod h1:Y3FOIo7VrpECV02VOtMIOiKzwREB68TzPABo4psaK/g= cosmossdk.io/schema v0.2.0 h1:UH5CR1DqUq8yP+5Np8PbvG4YX0zAUsTN2Qk6yThmfMk= cosmossdk.io/schema v0.2.0/go.mod h1:RDAhxIeNB4bYqAlF4NBJwRrgtnciMcyyg0DOKnhNZQQ= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= @@ -644,6 +646,8 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= @@ -835,6 +839,8 @@ go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVf go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= diff --git a/x/upgrade/depinject.go b/x/upgrade/depinject.go index 204d7630c6bd..d0ad08a1c34e 100644 --- a/x/upgrade/depinject.go +++ b/x/upgrade/depinject.go @@ -7,7 +7,6 @@ import ( "cosmossdk.io/core/address" "cosmossdk.io/core/appmodule" coreserver "cosmossdk.io/core/server" - serverv2 "cosmossdk.io/core/server" "cosmossdk.io/depinject" "cosmossdk.io/depinject/appconfig" "cosmossdk.io/x/upgrade/keeper" diff --git a/x/upgrade/go.sum b/x/upgrade/go.sum index 7947d1fc7e6c..c5259d62c732 100644 --- a/x/upgrade/go.sum +++ b/x/upgrade/go.sum @@ -194,8 +194,6 @@ cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1V cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s= cosmossdk.io/collections v0.4.0/go.mod h1:oa5lUING2dP+gdDquow+QjlF45eL1t4TJDypgGd+tv0= -cosmossdk.io/core v1.0.0-alpha.2 h1:epU0Xwces4Rgl5bMhHHkXGaGDcyucNGlC/JDH+Suckg= -cosmossdk.io/core v1.0.0-alpha.2/go.mod h1:abgLjeFLhtuKIYZWSPlVUgQBrKObO7ULV35KYfexE90= cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050= cosmossdk.io/depinject v1.0.0/go.mod h1:zxK/h3HgHoA/eJVtiSsoaRaRA2D5U4cJ5thIG4ssbB8= cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= From c8ea058b7afbbd46cbbdf7197b75645163085ce0 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Thu, 12 Sep 2024 14:22:38 -0500 Subject: [PATCH 20/57] fix test --- simapp/v2/app_di.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/simapp/v2/app_di.go b/simapp/v2/app_di.go index d2940eaa495e..a41a6addafea 100644 --- a/simapp/v2/app_di.go +++ b/simapp/v2/app_di.go @@ -190,13 +190,15 @@ func NewSimApp[T transaction.Tx]( panic(err) } + var builderOpts []runtime.AppBuilderOption[T] if sub := viper.Sub("store.options"); sub != nil { err = sub.Unmarshal(storeOptions) if err != nil { panic(err) } + builderOpts = append(builderOpts, runtime.AppBuilderWithStoreOptions[T](storeOptions)) } - app.App, err = appBuilder.Build(runtime.AppBuilderWithStoreOptions[T](storeOptions)) + app.App, err = appBuilder.Build(builderOpts...) if err != nil { panic(err) } From 8d3698f9fba33a24e332b427f4f7df3eedbccb14 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Thu, 12 Sep 2024 14:24:36 -0500 Subject: [PATCH 21/57] config fix --- tests/go.mod | 1 + tests/integration/v2/app_helpers.go | 2 ++ 2 files changed, 3 insertions(+) diff --git a/tests/go.mod b/tests/go.mod index b7235d0f776d..81be9b47dd17 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -244,6 +244,7 @@ replace ( cosmossdk.io/collections => ../collections cosmossdk.io/core => ../core cosmossdk.io/core/testing => ../core/testing + cosmossdk.io/runtime/v2 => ../runtime/v2 cosmossdk.io/server/v2/appmanager => ../server/v2/appmanager cosmossdk.io/server/v2/stf => ../server/v2/stf cosmossdk.io/store => ../store diff --git a/tests/integration/v2/app_helpers.go b/tests/integration/v2/app_helpers.go index 4d7d03373c43..db547d583e8c 100644 --- a/tests/integration/v2/app_helpers.go +++ b/tests/integration/v2/app_helpers.go @@ -159,6 +159,8 @@ func (d *dynamicConfigImpl) GetString(key string) string { return d.homeDir case "store.app-db-backend": return "goleveldb" + case "server.minimum-gas-prices": + return "0stake" default: panic(fmt.Sprintf("unknown key: %s", key)) } From 57040e240a254f7f00fea66751f1bac9ba82022f Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Fri, 13 Sep 2024 05:13:14 -0500 Subject: [PATCH 22/57] need comet service bindings --- core/header/service.go | 4 +- runtime/v2/module.go | 6 -- server/v2/appmanager/appmanager.go | 11 ++++ simapp/v2/app_di.go | 24 ++------ simapp/v2/simdv2/cmd/root_di.go | 8 ++- tests/integration/bank/app_test.go | 93 +++++++++++++++++++++++++----- tests/integration/v2-audit.md | 5 ++ 7 files changed, 109 insertions(+), 42 deletions(-) diff --git a/core/header/service.go b/core/header/service.go index 15e6d4257425..8d36087a059c 100644 --- a/core/header/service.go +++ b/core/header/service.go @@ -35,7 +35,7 @@ func (i *Info) Bytes() ([]byte, error) { // Encode Hash if len(i.Hash) != hashSize { - return nil, errors.New("invalid hash size") + return nil, errors.New("invalid Hash size") } buf = append(buf, i.Hash...) @@ -47,7 +47,7 @@ func (i *Info) Bytes() ([]byte, error) { // Encode AppHash if len(i.AppHash) != hashSize { - return nil, errors.New("invalid hash size") + return nil, errors.New("invalid AppHash size") } buf = append(buf, i.AppHash...) diff --git a/runtime/v2/module.go b/runtime/v2/module.go index 3a9aafe3f06d..65be1ceb716e 100644 --- a/runtime/v2/module.go +++ b/runtime/v2/module.go @@ -15,7 +15,6 @@ import ( autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" appmodulev2 "cosmossdk.io/core/appmodule/v2" - "cosmossdk.io/core/comet" "cosmossdk.io/core/registry" "cosmossdk.io/core/server" "cosmossdk.io/core/store" @@ -96,7 +95,6 @@ func init() { ProvideAppBuilder[transaction.Tx], ProvideEnvironment[transaction.Tx], ProvideModuleManager[transaction.Tx], - ProvideCometService, ), appconfig.Invoke(SetupAppBuilder), ) @@ -232,7 +230,3 @@ func storeKeyOverride(config *runtimev2.Module, moduleName string) *runtimev2.St return nil } - -func ProvideCometService() comet.Service { - return &services.ContextAwareCometInfoService{} -} diff --git a/server/v2/appmanager/appmanager.go b/server/v2/appmanager/appmanager.go index 7fb773d28f1e..ebb13eb71d37 100644 --- a/server/v2/appmanager/appmanager.go +++ b/server/v2/appmanager/appmanager.go @@ -204,6 +204,17 @@ func (a AppManager[T]) Simulate( return result, cs, nil } +func (a AppManager[T]) Exec( + ctx context.Context, + fn func(ctx context.Context) error, +) (corestore.WriterMap, error) { + _, state, err := a.db.StateLatest() + if err != nil { + return nil, err + } + return a.stf.RunWithCtx(ctx, state, fn) +} + // Query queries the application at the provided version. // CONTRACT: Version must always be provided, if 0, get latest func (a AppManager[T]) Query( diff --git a/simapp/v2/app_di.go b/simapp/v2/app_di.go index c1dcc0f212b5..80ac09ec1805 100644 --- a/simapp/v2/app_di.go +++ b/simapp/v2/app_di.go @@ -1,9 +1,10 @@ package simapp import ( + "cosmossdk.io/core/comet" + "cosmossdk.io/runtime/v2/services" _ "embed" - "github.com/spf13/viper" clienthelpers "cosmossdk.io/client/v2/helpers" @@ -101,7 +102,8 @@ func NewSimApp[T transaction.Tx]( app = &SimApp[T]{} appBuilder *runtime.AppBuilder[T] err error - storeOptions = &root.Options{} + storeOptions = &root.Options{} + cometService comet.Service = &services.ContextAwareCometInfoService{} // merge the AppConfig and other configuration in one config appConfig = depinject.Configs( @@ -109,6 +111,7 @@ func NewSimApp[T transaction.Tx]( depinject.Supply( logger, viper, + cometService, // ADVANCED CONFIGURATION @@ -155,9 +158,6 @@ func NewSimApp[T transaction.Tx]( codec.ProvideAddressCodec, codec.ProvideProtoCodec, codec.ProvideLegacyAmino, - func() server.DynamicConfig { - return &viperWrapper{viper} - }, ), depinject.Invoke( std.RegisterInterfaces, @@ -249,17 +249,3 @@ func (app *SimApp[T]) GetConsensusAuthority() string { func (app *SimApp[T]) GetStore() any { return app.App.GetStore() } - -var _ server.DynamicConfig = &viperWrapper{} - -type viperWrapper struct { - *viper.Viper -} - -func (v *viperWrapper) UnmarshalSub(key string, cfg any) (bool, error) { - s := v.Viper.Sub(key) - if s == nil { - return false, nil - } - return true, s.Unmarshal(cfg) -} diff --git a/simapp/v2/simdv2/cmd/root_di.go b/simapp/v2/simdv2/cmd/root_di.go index fd5b62b9384b..885d3ac2ef15 100644 --- a/simapp/v2/simdv2/cmd/root_di.go +++ b/simapp/v2/simdv2/cmd/root_di.go @@ -1,6 +1,8 @@ package cmd import ( + "cosmossdk.io/core/comet" + "cosmossdk.io/runtime/v2/services" "os" "github.com/spf13/cobra" @@ -32,12 +34,16 @@ func NewRootCmd[T transaction.Tx]() *cobra.Command { autoCliOpts autocli.AppOptions moduleManager *runtime.MM[T] clientCtx client.Context + cometService comet.Service = &services.ContextAwareCometInfoService{} ) if err := depinject.Inject( depinject.Configs( simapp.AppConfig(), - depinject.Supply(log.NewNopLogger()), + depinject.Supply( + log.NewNopLogger(), + cometService, + ), depinject.Provide( codec.ProvideInterfaceRegistry, codec.ProvideAddressCodec, diff --git a/tests/integration/bank/app_test.go b/tests/integration/bank/app_test.go index e0e2a81a134e..c40a0cdc3d07 100644 --- a/tests/integration/bank/app_test.go +++ b/tests/integration/bank/app_test.go @@ -1,6 +1,8 @@ package bank_test import ( + "context" + "cosmossdk.io/core/server" "testing" abci "github.com/cometbft/cometbft/api/cometbft/abci/v1" @@ -78,10 +80,12 @@ type suite struct { AccountKeeper types.AccountKeeper DistributionKeeper distrkeeper.Keeper App *runtime.App - Appv2 *runtimev2.App[transaction.Tx] + AppV2 *runtimev2.App[transaction.Tx] TxConfig client.TxConfig } +var testAppV2 = false + func createTestSuite(t *testing.T, genesisAccounts []authtypes.GenesisAccount) suite { t.Helper() res := suite{} @@ -105,24 +109,28 @@ func createTestSuite(t *testing.T, genesisAccounts []authtypes.GenesisAccount) s configurator.ProtocolPoolModule(), } var err error - res.App, err = simtestutil.SetupWithConfiguration( - depinject.Configs(configurator.NewAppConfig(moduleConfigs...), depinject.Supply(log.NewNopLogger())), - startupCfg, &res.BankKeeper, &res.AccountKeeper, &res.DistributionKeeper, &res.TxConfig) - require.NoError(t, err) - - v2StartupCfg := integrationv2.DefaultStartUpConfig() - v2StartupCfg.HomeDir = t.TempDir() - res.Appv2, err = integrationv2.SetupWithConfiguration( - depinject.Configs(configurator.NewAppV2Config(moduleConfigs...), depinject.Supply(log.NewNopLogger())), - v2StartupCfg, - &res.BankKeeper, &res.AccountKeeper, &res.DistributionKeeper, &res.TxConfig) - require.NoError(t, err) + if testAppV2 { + v2StartupCfg := integrationv2.DefaultStartUpConfig() + v2StartupCfg.HomeDir = t.TempDir() + res.AppV2, err = integrationv2.SetupWithConfiguration( + depinject.Configs(configurator.NewAppV2Config(moduleConfigs...), depinject.Supply(log.NewNopLogger())), + v2StartupCfg, + &res.BankKeeper, &res.AccountKeeper, &res.DistributionKeeper, &res.TxConfig) + require.NoError(t, err) + } else { + res.App, err = simtestutil.SetupWithConfiguration( + depinject.Configs(configurator.NewAppConfig(moduleConfigs...), depinject.Supply(log.NewNopLogger())), + startupCfg, &res.BankKeeper, &res.AccountKeeper, &res.DistributionKeeper, &res.TxConfig) + require.NoError(t, err) + } return res } // CheckBalance checks the balance of an account. -func checkBalance(t *testing.T, baseApp *baseapp.BaseApp, addr sdk.AccAddress, balances sdk.Coins, keeper bankkeeper.Keeper) { +func checkBalance( + t *testing.T, baseApp *baseapp.BaseApp, addr sdk.AccAddress, balances sdk.Coins, keeper bankkeeper.Keeper, +) { t.Helper() ctxCheck := baseApp.NewContext(true) keeperBalances := keeper.GetAllBalances(ctxCheck, addr) @@ -130,6 +138,7 @@ func checkBalance(t *testing.T, baseApp *baseapp.BaseApp, addr sdk.AccAddress, b } func TestSendNotEnoughBalance(t *testing.T) { + testAppV2 = false acc := &authtypes.BaseAccount{ Address: addr1.String(), } @@ -172,6 +181,62 @@ func TestSendNotEnoughBalance(t *testing.T) { require.Equal(t, origSeq+1, res2.GetSequence()) } +func TestSendNotEnoughBalance_v2(t *testing.T) { + testAppV2 = true + acc := &authtypes.BaseAccount{ + Address: addr1.String(), + } + + genAccs := []authtypes.GenesisAccount{acc} + s := createTestSuite(t, genAccs) + ctx := context.Background() + + _, err := s.AppV2.Exec(ctx, func(ctx context.Context) error { + return testutil.FundAccount( + ctx, s.BankKeeper, addr1, + sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67))) + }) + require.NoError(t, err) + _, _, err = s.AppV2.DeliverBlock(ctx, &server.BlockRequest[transaction.Tx]{ + Height: 1, + Hash: make([]byte, 32), + AppHash: make([]byte, 32), + }) + require.NoError(t, err) + /* + _, err := baseApp.FinalizeBlock(&abci.FinalizeBlockRequest{Height: baseApp.LastBlockHeight() + 1}) + require.NoError(t, err) + _, err = baseApp.Commit() + require.NoError(t, err) + + res1 := s.AccountKeeper.GetAccount(ctx, addr1) + require.NotNil(t, res1) + require.Equal(t, acc, res1.(*authtypes.BaseAccount)) + + origAccNum := res1.GetAccountNumber() + origSeq := res1.GetSequence() + + addr1Str, err := s.AccountKeeper.AddressCodec().BytesToString(addr1) + require.NoError(t, err) + addr2Str, err := s.AccountKeeper.AddressCodec().BytesToString(addr2) + require.NoError(t, err) + sendMsg := types.NewMsgSend(addr1Str, addr2Str, sdk.Coins{sdk.NewInt64Coin("foocoin", 100)}) + header := header.Info{Height: baseApp.LastBlockHeight() + 1} + txConfig := moduletestutil.MakeTestTxConfig(cdctestutil.CodecOptions{}) + _, _, err = simtestutil.SignCheckDeliver(t, txConfig, baseApp, header, []sdk.Msg{sendMsg}, "", []uint64{origAccNum}, []uint64{origSeq}, false, false, priv1) + require.Error(t, err) + + checkBalance(t, baseApp, addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 67)}, s.BankKeeper) + + ctx2 := baseApp.NewContext(true) + res2 := s.AccountKeeper.GetAccount(ctx2, addr1) + require.NotNil(t, res2) + + require.Equal(t, origAccNum, res2.GetAccountNumber()) + require.Equal(t, origSeq+1, res2.GetSequence()) + */ +} + func TestMsgMultiSendWithAccounts(t *testing.T) { addr1Str, err := cdctestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr1) require.NoError(t, err) diff --git a/tests/integration/v2-audit.md b/tests/integration/v2-audit.md index 8613bc0868c4..6cfe9c89386d 100644 --- a/tests/integration/v2-audit.md +++ b/tests/integration/v2-audit.md @@ -32,6 +32,11 @@ testutil/integration can (and should) be moved to tests/integration. +## differences from v1 + +- a v1 app calls commit only after cometbft has committed a block and calls the ABCI life cycle function Commit() +- a v2 app calls commit within FinalizeBlock. + ## simulations In addition to `NewIntegrationApp` many modules also make use of [testutil/sims.SetupWithConfiguration](../../testutil/sims/app_helpers.go#L145) to create a `runtime.App` for simulation testing. For example From 995974cd1f4f07b0029ed7a02bfe05ebba968060 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Fri, 13 Sep 2024 11:25:05 -0500 Subject: [PATCH 23/57] looks like a valid construction --- runtime/v2/builder.go | 67 ++++++----------------------- runtime/v2/module.go | 27 +++++++++--- runtime/v2/store.go | 54 +++++++++++++++++++++++ simapp/v2/app_di.go | 20 ++++----- tests/integration/bank/app_test.go | 2 +- tests/integration/v2/app_helpers.go | 48 +++++++++++++++------ 6 files changed, 132 insertions(+), 86 deletions(-) diff --git a/runtime/v2/builder.go b/runtime/v2/builder.go index c111884586af..7b8ac8627b4a 100644 --- a/runtime/v2/builder.go +++ b/runtime/v2/builder.go @@ -2,35 +2,23 @@ package runtime import ( "context" - "encoding/json" - "fmt" - "io" - "path/filepath" - "cosmossdk.io/core/appmodule" appmodulev2 "cosmossdk.io/core/appmodule/v2" - "cosmossdk.io/core/server" "cosmossdk.io/core/store" "cosmossdk.io/core/transaction" "cosmossdk.io/server/v2/appmanager" "cosmossdk.io/server/v2/stf" "cosmossdk.io/server/v2/stf/branch" - "cosmossdk.io/store/v2/db" - rootstore "cosmossdk.io/store/v2/root" + "encoding/json" + "fmt" + "io" ) -type configProvider interface { - GetString(string) string - UnmarshalSub(string, any) (bool, error) -} - // AppBuilder is a type that is injected into a container by the runtime/v2 module // (as *AppBuilder) which can be used to create an app which is compatible with // the existing app.go initialization conventions. type AppBuilder[T transaction.Tx] struct { - app *App[T] - config server.DynamicConfig - storeOptions *rootstore.Options + app *App[T] // the following fields are used to overwrite the default branch func(state store.ReaderMap) store.WriterMap @@ -102,6 +90,10 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { } } + if a.app.db == nil { + return nil, fmt.Errorf("app.db is not set, it is required to build the app") + } + if err := a.app.moduleManager.RegisterServices(a.app); err != nil { return nil, err } @@ -125,37 +117,6 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { } a.app.stf = stf - home := a.config.GetString(FlagHome) - scRawDb, err := db.NewDB( - db.DBType(a.config.GetString("store.app-db-backend")), - "application", - filepath.Join(home, "data"), - nil, - ) - if err != nil { - panic(err) - } - - var storeOptions rootstore.Options - if a.storeOptions != nil { - storeOptions = *a.storeOptions - } else { - storeOptions = rootstore.DefaultStoreOptions() - } - factoryOptions := &rootstore.FactoryOptions{ - Logger: a.app.logger, - RootDir: home, - Options: storeOptions, - StoreKeys: append(a.app.storeKeys, "stf"), - SCRawDB: scRawDb, - } - - rs, err := rootstore.CreateRootStore(factoryOptions) - if err != nil { - return nil, fmt.Errorf("failed to create root store: %w", err) - } - a.app.db = rs - appManagerBuilder := appmanager.Builder[T]{ STF: a.app.stf, DB: a.app.db, @@ -225,14 +186,12 @@ func AppBuilderWithTxValidator[T transaction.Tx]( // AppBuilderWithPostTxExec sets logic that will be executed after each transaction. // When not provided, a no-op function will be used. -func AppBuilderWithPostTxExec[T transaction.Tx](postTxExec func(ctx context.Context, tx T, success bool) error) AppBuilderOption[T] { +func AppBuilderWithPostTxExec[T transaction.Tx]( + postTxExec func( + ctx context.Context, tx T, success bool, + ) error, +) AppBuilderOption[T] { return func(a *AppBuilder[T]) { a.postTxExec = postTxExec } } - -func AppBuilderWithStoreOptions[T transaction.Tx](opts *rootstore.Options) AppBuilderOption[T] { - return func(a *AppBuilder[T]) { - a.storeOptions = opts - } -} diff --git a/runtime/v2/module.go b/runtime/v2/module.go index 65be1ceb716e..55672648a779 100644 --- a/runtime/v2/module.go +++ b/runtime/v2/module.go @@ -1,6 +1,7 @@ package runtime import ( + rootstore "cosmossdk.io/store/v2/root" "fmt" "os" "slices" @@ -38,19 +39,19 @@ type appModule[T transaction.Tx] struct { func (m appModule[T]) IsOnePerModuleType() {} func (m appModule[T]) IsAppModule() {} -func (m appModule[T]) RegisterServices(registar grpc.ServiceRegistrar) error { +func (m appModule[T]) RegisterServices(registrar grpc.ServiceRegistrar) error { autoCliQueryService, err := services.NewAutoCLIQueryService(m.app.moduleManager.modules) if err != nil { return err } - autocliv1.RegisterQueryServer(registar, autoCliQueryService) + autocliv1.RegisterQueryServer(registrar, autoCliQueryService) reflectionSvc, err := services.NewReflectionService() if err != nil { return err } - reflectionv1.RegisterReflectionServiceServer(registar, reflectionSvc) + reflectionv1.RegisterReflectionServiceServer(registrar, reflectionSvc) return nil } @@ -95,6 +96,7 @@ func init() { ProvideAppBuilder[transaction.Tx], ProvideEnvironment[transaction.Tx], ProvideModuleManager[transaction.Tx], + ProvideStoreBuilder, ), appconfig.Invoke(SetupAppBuilder), ) @@ -143,7 +145,9 @@ type AppInputs struct { InterfaceRegistrar registry.InterfaceRegistrar LegacyAmino registry.AminoRegistrar Logger log.Logger + StoreBuilder *StoreBuilder DynamicConfig server.DynamicConfig `optional:"true"` // can be nil in client wiring + StoreOptions *rootstore.Options `optional:"true"` // if unset defaults will be used } func SetupAppBuilder(inputs AppInputs) { @@ -154,8 +158,17 @@ func SetupAppBuilder(inputs AppInputs) { app.moduleManager.RegisterInterfaces(inputs.InterfaceRegistrar) app.moduleManager.RegisterLegacyAminoCodec(inputs.LegacyAmino) - if inputs.DynamicConfig != nil { - inputs.AppBuilder.config = inputs.DynamicConfig + if inputs.DynamicConfig == nil { + return + } + storeOptions := rootstore.DefaultStoreOptions() + if inputs.StoreOptions != nil { + storeOptions = *inputs.StoreOptions + } + var err error + app.db, err = inputs.StoreBuilder.Build(inputs.Logger, app.storeKeys, inputs.DynamicConfig, storeOptions) + if err != nil { + panic(err) } } @@ -217,8 +230,8 @@ func ProvideEnvironment[T transaction.Tx]( return env, kvService, memKvService } -func registerStoreKey[T transaction.Tx](wrapper *AppBuilder[T], key string) { - wrapper.app.storeKeys = append(wrapper.app.storeKeys, key) +func registerStoreKey[T transaction.Tx](builder *AppBuilder[T], key string) { + builder.app.storeKeys = append(builder.app.storeKeys, key) } func storeKeyOverride(config *runtimev2.Module, moduleName string) *runtimev2.StoreKeyConfig { diff --git a/runtime/v2/store.go b/runtime/v2/store.go index 78223d4fdf24..d9e5aa7c71a3 100644 --- a/runtime/v2/store.go +++ b/runtime/v2/store.go @@ -1,10 +1,16 @@ package runtime import ( + "cosmossdk.io/core/server" "cosmossdk.io/core/store" + "cosmossdk.io/log" "cosmossdk.io/server/v2/stf" storev2 "cosmossdk.io/store/v2" + "cosmossdk.io/store/v2/db" "cosmossdk.io/store/v2/proof" + "cosmossdk.io/store/v2/root" + "fmt" + "path/filepath" ) // NewKVStoreService creates a new KVStoreService. @@ -55,3 +61,51 @@ type Store interface { // LastCommitID returns the latest commit ID LastCommitID() (proof.CommitID, error) } + +type StoreBuilder struct { + store Store +} + +func (sb *StoreBuilder) Build( + logger log.Logger, + storeKeys []string, + config server.DynamicConfig, + options root.Options, +) (Store, error) { + if sb.store != nil { + return sb.store, nil + } + home := config.GetString(FlagHome) + scRawDb, err := db.NewDB( + db.DBType(config.GetString("store.app-db-backend")), + "application", + filepath.Join(home, "data"), + nil, + ) + if err != nil { + return nil, fmt.Errorf("failed to create SCRawDB: %w", err) + } + + factoryOptions := &root.FactoryOptions{ + Logger: logger, + RootDir: home, + Options: options, + StoreKeys: append(storeKeys, "stf"), + SCRawDB: scRawDb, + } + + rs, err := root.CreateRootStore(factoryOptions) + if err != nil { + return nil, fmt.Errorf("failed to create root store: %w", err) + } + sb.store = rs + return sb.store, nil +} + +func (sb *StoreBuilder) Get() Store { + return sb.store +} + +func ProvideStoreBuilder() *StoreBuilder { + return &StoreBuilder{} +} diff --git a/simapp/v2/app_di.go b/simapp/v2/app_di.go index 80ac09ec1805..365570c6eb6f 100644 --- a/simapp/v2/app_di.go +++ b/simapp/v2/app_di.go @@ -102,7 +102,6 @@ func NewSimApp[T transaction.Tx]( app = &SimApp[T]{} appBuilder *runtime.AppBuilder[T] err error - storeOptions = &root.Options{} cometService comet.Service = &services.ContextAwareCometInfoService{} // merge the AppConfig and other configuration in one config @@ -166,6 +165,15 @@ func NewSimApp[T transaction.Tx]( ) ) + if sub := viper.Sub("store.options"); sub != nil { + storeOptions := &root.Options{} + err := sub.Unmarshal(storeOptions) + if err != nil { + panic(err) + } + appConfig = depinject.Configs(appConfig, depinject.Supply(storeOptions)) + } + if err := depinject.Inject(appConfig, &appBuilder, &app.appCodec, @@ -194,15 +202,7 @@ func NewSimApp[T transaction.Tx]( panic(err) } - var builderOpts []runtime.AppBuilderOption[T] - if sub := viper.Sub("store.options"); sub != nil { - err = sub.Unmarshal(storeOptions) - if err != nil { - panic(err) - } - builderOpts = append(builderOpts, runtime.AppBuilderWithStoreOptions[T](storeOptions)) - } - app.App, err = appBuilder.Build(builderOpts...) + app.App, err = appBuilder.Build() if err != nil { panic(err) } diff --git a/tests/integration/bank/app_test.go b/tests/integration/bank/app_test.go index c40a0cdc3d07..80b3b43b49df 100644 --- a/tests/integration/bank/app_test.go +++ b/tests/integration/bank/app_test.go @@ -198,7 +198,7 @@ func TestSendNotEnoughBalance_v2(t *testing.T) { }) require.NoError(t, err) _, _, err = s.AppV2.DeliverBlock(ctx, &server.BlockRequest[transaction.Tx]{ - Height: 1, + Height: 2, // TODO how to auto-advance height with app v2 interface? Hash: make([]byte, 32), AppHash: make([]byte, 32), }) diff --git a/tests/integration/v2/app_helpers.go b/tests/integration/v2/app_helpers.go index db547d583e8c..d7fd4f12e381 100644 --- a/tests/integration/v2/app_helpers.go +++ b/tests/integration/v2/app_helpers.go @@ -3,6 +3,7 @@ package integration import ( "context" + "cosmossdk.io/core/comet" "crypto/sha256" "encoding/json" "errors" @@ -170,6 +171,14 @@ func (d *dynamicConfigImpl) UnmarshalSub(string, any) (bool, error) { return false, nil } +var _ comet.Service = &cometServiceImpl{} + +type cometServiceImpl struct{} + +func (c cometServiceImpl) CometInfo(context.Context) comet.Info { + return comet.Info{} +} + // SetupWithConfiguration initializes a new runtime.App. A Nop logger is set in runtime.App. // appConfig defines the application configuration (f.e. app_config.go). // extraOutputs defines the extra outputs to be assigned by the dependency injector (depinject). @@ -182,7 +191,9 @@ func SetupWithConfiguration( var ( app *runtime.App[stateMachineTx] appBuilder *runtime.AppBuilder[stateMachineTx] + storeBuilder *runtime.StoreBuilder txConfigOptions tx.ConfigOptions + cometService comet.Service = &cometServiceImpl{} cdc codec.Codec err error ) @@ -191,12 +202,15 @@ func SetupWithConfiguration( depinject.Configs( appConfig, codec.DefaultProviders, - depinject.Supply(&dynamicConfigImpl{startupConfig.HomeDir}), + depinject.Supply( + &dynamicConfigImpl{startupConfig.HomeDir}, + cometService, + ), depinject.Invoke( std.RegisterInterfaces, ), ), - append(extraOutputs, &appBuilder, &cdc, &txConfigOptions)...); err != nil { + append(extraOutputs, &appBuilder, &cdc, &txConfigOptions, &storeBuilder)...); err != nil { return nil, fmt.Errorf("failed to inject dependencies: %w", err) } @@ -263,7 +277,7 @@ func SetupWithConfiguration( ) emptyHash := sha256.Sum256(nil) - _, _, err = app.InitGenesis( + _, state, err := app.InitGenesis( ctx, &server.BlockRequest[stateMachineTx]{ Height: 1, @@ -280,17 +294,23 @@ func SetupWithConfiguration( return nil, fmt.Errorf("failed to init genesis: %w", err) } - // commit genesis changes - // not sure if this is needed yet - // if !startupConfig.AtGenesis { - // _, err = app.FinalizeBlock(&abci.FinalizeBlockRequest{ - // Height: app.LastBlockHeight() + 1, - // NextValidatorsHash: valSet.Hash(), - // }) - // if err != nil { - // return nil, fmt.Errorf("failed to finalize block: %w", err) - // } - // } + store := storeBuilder.Get() + if store == nil { + return nil, fmt.Errorf("failed to build store: %w", err) + } + err = store.SetInitialVersion(1) + if err != nil { + return nil, fmt.Errorf("failed to set initial version: %w", err) + } + genesisChanges, err := state.GetStateChanges() + if err != nil { + return nil, fmt.Errorf("failed to get genesis state changes: %w", err) + } + cs := &corestore.Changeset{Changes: genesisChanges} + _, err = store.Commit(cs) + if err != nil { + return nil, fmt.Errorf("failed to commit initial version: %w", err) + } return app, nil } From 69598d432d556f6f5f3791fa54b5c8ad3afb7b3c Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Sun, 15 Sep 2024 13:56:54 -0500 Subject: [PATCH 24/57] genesis service --- core/store/service.go | 4 ++ runtime/v2/builder.go | 54 +++++++++++---- runtime/v2/genesis.go | 100 +++++++++++++++++++++++++++ runtime/v2/module.go | 37 ++++++++-- server/v2/appmanager/appmanager.go | 39 ++++------- server/v2/appmanager/genesis.go | 18 ++++- server/v2/stf/core_header_service.go | 2 - server/v2/stf/stf.go | 4 +- simapp/v2/app_di.go | 11 ++- simapp/v2/simdv2/cmd/root_di.go | 21 ++++-- tests/integration/bank/app_test.go | 4 +- tests/integration/v2/app_helpers.go | 72 ++++++++++--------- 12 files changed, 270 insertions(+), 96 deletions(-) create mode 100644 runtime/v2/genesis.go diff --git a/core/store/service.go b/core/store/service.go index 11eeaf0de9b3..60d4c023cc30 100644 --- a/core/store/service.go +++ b/core/store/service.go @@ -10,6 +10,8 @@ type KVStoreService interface { OpenKVStore(context.Context) KVStore } +type KVStoreServiceFactory func([]byte) KVStoreService + // MemoryStoreService represents a unique, non-forgeable handle to a memory-backed // KVStore. It should be provided as a module-scoped dependency by the runtime // module being used to build the app. @@ -18,6 +20,8 @@ type MemoryStoreService interface { OpenMemoryStore(context.Context) KVStore } +type MemoryStoreServiceFactory func([]byte) MemoryStoreService + // TransientStoreService represents a unique, non-forgeable handle to a memory-backed // KVStore which is reset at the start of every block. It should be provided as // a module-scoped dependency by the runtime module being used to build the app. diff --git a/runtime/v2/builder.go b/runtime/v2/builder.go index 7b8ac8627b4a..cc51ec5f5ff7 100644 --- a/runtime/v2/builder.go +++ b/runtime/v2/builder.go @@ -2,6 +2,11 @@ package runtime import ( "context" + "encoding/json" + "errors" + "fmt" + "io" + "cosmossdk.io/core/appmodule" appmodulev2 "cosmossdk.io/core/appmodule/v2" "cosmossdk.io/core/store" @@ -9,9 +14,6 @@ import ( "cosmossdk.io/server/v2/appmanager" "cosmossdk.io/server/v2/stf" "cosmossdk.io/server/v2/stf/branch" - "encoding/json" - "fmt" - "io" ) // AppBuilder is a type that is injected into a container by the runtime/v2 module @@ -38,7 +40,13 @@ func (a *AppBuilder[T]) RegisterModules(modules map[string]appmodulev2.AppModule // if a (legacy) module implements the HasName interface, check that the name matches if mod, ok := appModule.(interface{ Name() string }); ok { if name != mod.Name() { - a.app.logger.Warn(fmt.Sprintf("module name %q does not match name returned by HasName: %q", name, mod.Name())) + a.app.logger.Warn( + fmt.Sprintf( + "module name %q does not match name returned by HasName: %q", + name, + mod.Name(), + ), + ) } } @@ -123,20 +131,38 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { ValidateTxGasLimit: a.app.config.GasConfig.ValidateTxGasLimit, QueryGasLimit: a.app.config.GasConfig.QueryGasLimit, SimulationGasLimit: a.app.config.GasConfig.SimulationGasLimit, - InitGenesis: func(ctx context.Context, src io.Reader, txHandler func(json.RawMessage) error) error { + InitGenesis: func( + ctx context.Context, + src io.Reader, + txHandler func(json.RawMessage) error, + ) (store.WriterMap, error) { // this implementation assumes that the state is a JSON object bz, err := io.ReadAll(src) if err != nil { - return fmt.Errorf("failed to read import state: %w", err) + return nil, fmt.Errorf("failed to read import state: %w", err) + } + var genesisJSON map[string]json.RawMessage + if err = json.Unmarshal(bz, &genesisJSON); err != nil { + return nil, err } - var genesisState map[string]json.RawMessage - if err = json.Unmarshal(bz, &genesisState); err != nil { - return err + + v, zeroState, err := a.app.db.StateLatest() + if err != nil { + return nil, fmt.Errorf("unable to get latest state: %w", err) } - if err = a.app.moduleManager.InitGenesisJSON(ctx, genesisState, txHandler); err != nil { - return fmt.Errorf("failed to init genesis: %w", err) + if v != 0 { // TODO: genesis state may be > 0, we need to set version on store + return nil, errors.New("cannot init genesis on non-zero state") } - return nil + genesisCtx := makeGenesisContext(a.branch(zeroState)) + genesisState, err := genesisCtx.Run(ctx, func(ctx context.Context) error { + err = a.app.moduleManager.InitGenesisJSON(ctx, genesisJSON, txHandler) + if err != nil { + return fmt.Errorf("failed to init genesis: %w", err) + } + return nil + }) + + return genesisState, err }, ExportGenesis: func(ctx context.Context, version uint64) ([]byte, error) { genesisJson, err := a.app.moduleManager.ExportGenesisForModules(ctx) @@ -166,7 +192,9 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { type AppBuilderOption[T transaction.Tx] func(*AppBuilder[T]) // AppBuilderWithBranch sets a custom branch implementation for the app. -func AppBuilderWithBranch[T transaction.Tx](branch func(state store.ReaderMap) store.WriterMap) AppBuilderOption[T] { +func AppBuilderWithBranch[T transaction.Tx]( + branch func(state store.ReaderMap) store.WriterMap, +) AppBuilderOption[T] { return func(a *AppBuilder[T]) { a.branch = branch } diff --git a/runtime/v2/genesis.go b/runtime/v2/genesis.go new file mode 100644 index 000000000000..aca1f0fe3dd9 --- /dev/null +++ b/runtime/v2/genesis.go @@ -0,0 +1,100 @@ +package runtime + +import ( + "context" + "fmt" + + "cosmossdk.io/core/header" + "cosmossdk.io/core/store" +) + +var _ store.KVStoreService = (*GenesisKVStoreServie)(nil) + +type genesisContextKeyType struct{} + +var genesisContextKey = genesisContextKeyType{} + +type genesisContext struct { + state store.WriterMap + headerInfo header.Info + didRun bool +} + +func makeGenesisContext(state store.WriterMap) genesisContext { + return genesisContext{ + state: state, + } +} + +func (g *genesisContext) Run( + ctx context.Context, + fn func(ctx context.Context) error, +) (store.WriterMap, error) { + ctx = context.WithValue(ctx, genesisContextKey, g) + err := fn(ctx) + if err != nil { + return nil, err + } + g.didRun = true + return g.state, nil +} + +type GenesisKVStoreServie struct { + genesisCapable bool + actor []byte + execution store.KVStoreService +} + +func NewGenesisCapableKVStoreService( + actor []byte, + execution store.KVStoreService, +) *GenesisKVStoreServie { + return &GenesisKVStoreServie{ + genesisCapable: true, + actor: actor, + execution: execution, + } +} + +// OpenKVStore implements store.KVStoreService. +func (g *GenesisKVStoreServie) OpenKVStore(ctx context.Context) store.KVStore { + if !g.genesisCapable { + return g.execution.OpenKVStore(ctx) + } + v := ctx.Value(genesisContextKey) + if v == nil { + panic("genesis context not found") + } + genCtx, ok := v.(*genesisContext) + if !ok { + panic(fmt.Errorf("unexpected genesis context type: %T", v)) + } + if genCtx.didRun { + g.genesisCapable = false + return g.execution.OpenKVStore(ctx) + } + state, err := genCtx.state.GetWriter(g.actor) + if err != nil { + panic(err) + } + return state +} + +type GenesisHeaderService struct { + genesisCapable bool +} + +// HeaderInfo implements header.Service. +func (g *GenesisHeaderService) HeaderInfo(ctx context.Context) header.Info { + v := ctx.Value(genesisContextKey) + if v == nil { + panic("genesis context not found") + } + genCtx, ok := v.(*genesisContext) + if !ok { + panic(fmt.Errorf("unexpected genesis context type: %T", v)) + } + return genCtx.headerInfo +} + +var _ header.Service = (*GenesisHeaderService)(nil) diff --git a/runtime/v2/module.go b/runtime/v2/module.go index 55672648a779..3faad8c97570 100644 --- a/runtime/v2/module.go +++ b/runtime/v2/module.go @@ -1,11 +1,13 @@ package runtime import ( - rootstore "cosmossdk.io/store/v2/root" "fmt" "os" "slices" + "cosmossdk.io/core/comet" + rootstore "cosmossdk.io/store/v2/root" + "github.com/cosmos/gogoproto/proto" "google.golang.org/grpc" "google.golang.org/protobuf/reflect/protodesc" @@ -166,7 +168,12 @@ func SetupAppBuilder(inputs AppInputs) { storeOptions = *inputs.StoreOptions } var err error - app.db, err = inputs.StoreBuilder.Build(inputs.Logger, app.storeKeys, inputs.DynamicConfig, storeOptions) + app.db, err = inputs.StoreBuilder.Build( + inputs.Logger, + app.storeKeys, + inputs.DynamicConfig, + storeOptions, + ) if err != nil { panic(err) } @@ -186,6 +193,8 @@ func ProvideEnvironment[T transaction.Tx]( config *runtimev2.Module, key depinject.ModuleKey, appBuilder *AppBuilder[T], + kvFactory store.KVStoreServiceFactory, + memFactory store.MemoryStoreServiceFactory, ) ( appmodulev2.Environment, store.KVStoreService, @@ -207,11 +216,11 @@ func ProvideEnvironment[T transaction.Tx]( } registerStoreKey(appBuilder, kvStoreKey) - kvService = stf.NewKVStoreService([]byte(kvStoreKey)) + kvService = kvFactory([]byte(kvStoreKey)) memStoreKey := fmt.Sprintf("memory:%s", key.Name()) registerStoreKey(appBuilder, memStoreKey) - memKvService = stf.NewMemoryStoreService([]byte(memStoreKey)) + memKvService = memFactory([]byte(memStoreKey)) } env := appmodulev2.Environment{ @@ -243,3 +252,23 @@ func storeKeyOverride(config *runtimev2.Module, moduleName string) *runtimev2.St return nil } + +func DefaultServiceBindings() depinject.Config { + var ( + kvServiceFactory store.KVStoreServiceFactory = func(actor []byte) store.KVStoreService { + return NewGenesisService( + actor, + stf.NewKVStoreService(actor), + ) + } + memStoreServiceFactory store.MemoryStoreServiceFactory = func(actor []byte) store.MemoryStoreService { + return stf.NewMemoryStoreService(actor) + } + cometService comet.Service = &services.ContextAwareCometInfoService{} + ) + return depinject.Supply( + kvServiceFactory, + memStoreServiceFactory, + cometService, + ) +} diff --git a/server/v2/appmanager/appmanager.go b/server/v2/appmanager/appmanager.go index ebb13eb71d37..cb8609c4fb30 100644 --- a/server/v2/appmanager/appmanager.go +++ b/server/v2/appmanager/appmanager.go @@ -43,34 +43,17 @@ func (a AppManager[T]) InitGenesis( initGenesisJSON []byte, txCodec transaction.Codec[T], ) (*server.BlockResponse, corestore.WriterMap, error) { - v, zeroState, err := a.db.StateLatest() - if err != nil { - return nil, nil, fmt.Errorf("unable to get latest state: %w", err) - } - if v != 0 { // TODO: genesis state may be > 0, we need to set version on store - return nil, nil, errors.New("cannot init genesis on non-zero state") - } - var genTxs []T - genesisState, err := a.stf.RunWithCtx( + genesisState, err := a.initGenesis( ctx, - zeroState, - func(ctx context.Context) error { - return a.initGenesis( - ctx, - bytes.NewBuffer(initGenesisJSON), - func(jsonTx json.RawMessage) error { - genTx, err := txCodec.DecodeJSON(jsonTx) - if err != nil { - return fmt.Errorf( - "failed to decode genesis transaction: %w", - err, - ) - } - genTxs = append(genTxs, genTx) - return nil - }, - ) + bytes.NewBuffer(initGenesisJSON), + func(jsonTx json.RawMessage) error { + genTx, err := txCodec.DecodeJSON(jsonTx) + if err != nil { + return fmt.Errorf("failed to decode genesis transaction: %w", err) + } + genTxs = append(genTxs, genTx) + return nil }, ) if err != nil { @@ -204,6 +187,10 @@ func (a AppManager[T]) Simulate( return result, cs, nil } +// Exec executes a function within the context of the latest state. +// It is required for integration testing. +// Alternative #1: Provide STF directly to the test. Blocking: STF is not exported. +// Alternative #2: Provide parallel implementation of all services provided by STF for testing. func (a AppManager[T]) Exec( ctx context.Context, fn func(ctx context.Context) error, diff --git a/server/v2/appmanager/genesis.go b/server/v2/appmanager/genesis.go index 8acad003b694..989ae442a9b9 100644 --- a/server/v2/appmanager/genesis.go +++ b/server/v2/appmanager/genesis.go @@ -4,11 +4,25 @@ import ( "context" "encoding/json" "io" + + "cosmossdk.io/core/store" ) type ( // ExportGenesis is a function type that represents the export of the genesis state. ExportGenesis func(ctx context.Context, version uint64) ([]byte, error) - // InitGenesis is a function type that represents the initialization of the genesis state. - InitGenesis func(ctx context.Context, src io.Reader, txHandler func(json.RawMessage) error) error + + // InitGenesis is a function that will run at application genesis, it will be called with + // the following arguments: + // - ctx: the context of the genesis operation + // - src: the source containing the raw genesis state + // - txHandler: a function capable of decoding a json tx, will be run for each genesis + // transaction + // + // It must return a map of the dirty state after the genesis operation. + InitGenesis func( + ctx context.Context, + src io.Reader, + txHandler func(json.RawMessage) error, + ) (store.WriterMap, error) ) diff --git a/server/v2/stf/core_header_service.go b/server/v2/stf/core_header_service.go index 8b7f6c412be9..bef2ad8894ea 100644 --- a/server/v2/stf/core_header_service.go +++ b/server/v2/stf/core_header_service.go @@ -24,8 +24,6 @@ const headerInfoPrefix = 0x37 // setHeaderInfo sets the header info in the state to be used by queries in the future. func (s STF[T]) setHeaderInfo(state store.WriterMap, headerInfo header.Info) error { - // TODO storing header info is too low level here, stf should be stateless. - // We should have a keeper that does this. runtimeStore, err := state.GetWriter(Identity) if err != nil { return err diff --git a/server/v2/stf/stf.go b/server/v2/stf/stf.go index e32a8f33293e..2824125bb712 100644 --- a/server/v2/stf/stf.go +++ b/server/v2/stf/stf.go @@ -550,7 +550,7 @@ func (e *executionContext) Value(key any) any { func (s STF[T]) makeContext( ctx context.Context, sender transaction.Identity, - store store.WriterMap, + state store.WriterMap, execMode transaction.ExecMode, ) *executionContext { valuedCtx := context.WithValue(ctx, corecontext.ExecModeKey, execMode) @@ -560,7 +560,7 @@ func (s STF[T]) makeContext( s.makeGasMeteredState, s.branchFn, sender, - store, + state, execMode, s.msgRouter, s.queryRouter, diff --git a/simapp/v2/app_di.go b/simapp/v2/app_di.go index 365570c6eb6f..52e8d8bfdbe7 100644 --- a/simapp/v2/app_di.go +++ b/simapp/v2/app_di.go @@ -1,8 +1,6 @@ package simapp import ( - "cosmossdk.io/core/comet" - "cosmossdk.io/runtime/v2/services" _ "embed" "github.com/spf13/viper" @@ -99,18 +97,17 @@ func NewSimApp[T transaction.Tx]( viper *viper.Viper, ) *SimApp[T] { var ( - app = &SimApp[T]{} - appBuilder *runtime.AppBuilder[T] - err error - cometService comet.Service = &services.ContextAwareCometInfoService{} + app = &SimApp[T]{} + appBuilder *runtime.AppBuilder[T] + err error // merge the AppConfig and other configuration in one config appConfig = depinject.Configs( AppConfig(), + runtime.DefaultServiceBindings(), depinject.Supply( logger, viper, - cometService, // ADVANCED CONFIGURATION diff --git a/simapp/v2/simdv2/cmd/root_di.go b/simapp/v2/simdv2/cmd/root_di.go index 885d3ac2ef15..ecdad86048f4 100644 --- a/simapp/v2/simdv2/cmd/root_di.go +++ b/simapp/v2/simdv2/cmd/root_di.go @@ -1,8 +1,6 @@ package cmd import ( - "cosmossdk.io/core/comet" - "cosmossdk.io/runtime/v2/services" "os" "github.com/spf13/cobra" @@ -34,15 +32,14 @@ func NewRootCmd[T transaction.Tx]() *cobra.Command { autoCliOpts autocli.AppOptions moduleManager *runtime.MM[T] clientCtx client.Context - cometService comet.Service = &services.ContextAwareCometInfoService{} ) if err := depinject.Inject( depinject.Configs( simapp.AppConfig(), + runtime.DefaultServiceBindings(), depinject.Supply( log.NewNopLogger(), - cometService, ), depinject.Provide( codec.ProvideInterfaceRegistry, @@ -75,7 +72,11 @@ func NewRootCmd[T transaction.Tx]() *cobra.Command { } customClientTemplate, customClientConfig := initClientConfig() - clientCtx, err = config.CreateClientConfig(clientCtx, customClientTemplate, customClientConfig) + clientCtx, err = config.CreateClientConfig( + clientCtx, + customClientTemplate, + customClientConfig, + ) if err != nil { return err } @@ -114,7 +115,9 @@ func ProvideClientContext( amino, ok := legacyAmino.(*codec.LegacyAmino) if !ok { - panic("registry.AminoRegistrar must be an *codec.LegacyAmino instance for legacy ClientContext") + panic( + "registry.AminoRegistrar must be an *codec.LegacyAmino instance for legacy ClientContext", + ) } clientCtx := client.Context{}. @@ -131,7 +134,11 @@ func ProvideClientContext( // Read the config to overwrite the default values with the values from the config file customClientTemplate, customClientConfig := initClientConfig() - clientCtx, err = config.CreateClientConfig(clientCtx, customClientTemplate, customClientConfig) + clientCtx, err = config.CreateClientConfig( + clientCtx, + customClientTemplate, + customClientConfig, + ) if err != nil { panic(err) } diff --git a/tests/integration/bank/app_test.go b/tests/integration/bank/app_test.go index 80b3b43b49df..d0ebfb4c3ab7 100644 --- a/tests/integration/bank/app_test.go +++ b/tests/integration/bank/app_test.go @@ -14,7 +14,6 @@ import ( "cosmossdk.io/depinject" "cosmossdk.io/log" sdkmath "cosmossdk.io/math" - runtimev2 "cosmossdk.io/runtime/v2" _ "cosmossdk.io/x/accounts" bankkeeper "cosmossdk.io/x/bank/keeper" "cosmossdk.io/x/bank/testutil" @@ -80,10 +79,11 @@ type suite struct { AccountKeeper types.AccountKeeper DistributionKeeper distrkeeper.Keeper App *runtime.App - AppV2 *runtimev2.App[transaction.Tx] + AppV2 *integrationv2.App TxConfig client.TxConfig } +// TODO move to param var testAppV2 = false func createTestSuite(t *testing.T, genesisAccounts []authtypes.GenesisAccount) suite { diff --git a/tests/integration/v2/app_helpers.go b/tests/integration/v2/app_helpers.go index d7fd4f12e381..be19cc26aba3 100644 --- a/tests/integration/v2/app_helpers.go +++ b/tests/integration/v2/app_helpers.go @@ -10,11 +10,6 @@ import ( "fmt" "time" - cmtproto "github.com/cometbft/cometbft/api/cometbft/types/v1" - cmtjson "github.com/cometbft/cometbft/libs/json" - cmttypes "github.com/cometbft/cometbft/types" - dbm "github.com/cosmos/cosmos-db" - corecontext "cosmossdk.io/core/context" "cosmossdk.io/core/server" corestore "cosmossdk.io/core/store" @@ -25,13 +20,14 @@ import ( banktypes "cosmossdk.io/x/bank/types" consensustypes "cosmossdk.io/x/consensus/types" stakingtypes "cosmossdk.io/x/staking/types" + cmtproto "github.com/cometbft/cometbft/api/cometbft/types/v1" + cmtjson "github.com/cometbft/cometbft/libs/json" + cmttypes "github.com/cometbft/cometbft/types" - "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - servertypes "github.com/cosmos/cosmos-sdk/server/types" "github.com/cosmos/cosmos-sdk/std" "github.com/cosmos/cosmos-sdk/testutil/mock" sdk "github.com/cosmos/cosmos-sdk/types" @@ -95,7 +91,6 @@ type StartupConfig struct { AppOption runtime.AppBuilderOption[stateMachineTx] AtGenesis bool GenesisAccounts []GenesisAccount - DB corestore.KVStoreWithBatch HomeDir string } @@ -117,7 +112,6 @@ func DefaultStartUpConfig() StartupConfig { ValidatorSet: CreateRandomValidatorSet, AtGenesis: false, GenesisAccounts: []GenesisAccount{ga}, - DB: dbm.NewMemDB(), } } @@ -126,7 +120,7 @@ func DefaultStartUpConfig() StartupConfig { func Setup( appConfig depinject.Config, extraOutputs ...interface{}, -) (*runtime.App[stateMachineTx], error) { +) (*App, error) { return SetupWithConfiguration( appConfig, DefaultStartUpConfig(), @@ -138,7 +132,7 @@ func Setup( func SetupAtGenesis( appConfig depinject.Config, extraOutputs ...interface{}, -) (*runtime.App[transaction.Tx], error) { +) (*App, error) { cfg := DefaultStartUpConfig() cfg.AtGenesis = true return SetupWithConfiguration(appConfig, cfg, extraOutputs...) @@ -186,16 +180,22 @@ func SetupWithConfiguration( appConfig depinject.Config, startupConfig StartupConfig, extraOutputs ...interface{}, -) (*runtime.App[stateMachineTx], error) { +) (*App, error) { // create the app with depinject var ( app *runtime.App[stateMachineTx] appBuilder *runtime.AppBuilder[stateMachineTx] storeBuilder *runtime.StoreBuilder txConfigOptions tx.ConfigOptions - cometService comet.Service = &cometServiceImpl{} - cdc codec.Codec - err error + cometService comet.Service = &cometServiceImpl{} + kvFactory corestore.KVStoreServiceFactory = func(actor []byte) corestore.KVStoreService { + return &storeService{actor} + } + memFactory corestore.MemoryStoreServiceFactory = func(actor []byte) corestore.MemoryStoreService { + return &storeService{actor} + } + cdc codec.Codec + err error ) if err := depinject.Inject( @@ -205,6 +205,8 @@ func SetupWithConfiguration( depinject.Supply( &dynamicConfigImpl{startupConfig.HomeDir}, cometService, + kvFactory, + memFactory, ), depinject.Invoke( std.RegisterInterfaces, @@ -312,7 +314,7 @@ func SetupWithConfiguration( return nil, fmt.Errorf("failed to commit initial version: %w", err) } - return app, nil + return &App{App: app, Store: store}, nil } // genesisStateWithValSet returns a new genesis state with the validator set @@ -453,28 +455,36 @@ func (t *genericTxDecoder) DecodeJSON(bz []byte) (stateMachineTx, error) { return out, nil } -// EmptyAppOptions is a stub implementing AppOptions -type EmptyAppOptions struct{} +type App struct { + *runtime.App[stateMachineTx] + Store runtime.Store +} -// Get implements AppOptions -func (ao EmptyAppOptions) Get(o string) interface{} { - return nil +type storeService struct { + actor []byte } -// AppOptionsMap is a stub implementing AppOptions which can get data from a map -type AppOptionsMap map[string]interface{} +type contextKeyType struct{} + +var contextKey = contextKeyType{} + +type integrationContext struct { + state corestore.WriterMap +} -func (m AppOptionsMap) Get(key string) interface{} { - v, ok := m[key] +func (s storeService) OpenKVStore(ctx context.Context) corestore.KVStore { + iCtx, ok := ctx.Value(contextKey).(integrationContext) if !ok { - return interface{}(nil) + panic("failed to get integration context") } - return v + state, err := iCtx.state.GetWriter(s.actor) + if err != nil { + panic(err) + } + return state } -func NewAppOptionsWithFlagHome(homePath string) servertypes.AppOptions { - return AppOptionsMap{ - flags.FlagHome: homePath, - } +func (s storeService) OpenMemoryStore(ctx context.Context) corestore.KVStore { + return s.OpenKVStore(ctx) } From 29b0ebeedf4a0afd6304884201c25a984e6b0f3b Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Sun, 15 Sep 2024 14:27:11 -0500 Subject: [PATCH 25/57] genesis working --- core/header/service.go | 2 ++ runtime/v2/genesis.go | 30 ++++++++++++++++++++++-------- runtime/v2/module.go | 12 ++++++++---- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/core/header/service.go b/core/header/service.go index 8d36087a059c..29ee248f1389 100644 --- a/core/header/service.go +++ b/core/header/service.go @@ -13,6 +13,8 @@ type Service interface { HeaderInfo(context.Context) Info } +type HeaderServiceFactory func() Service + // Info defines a struct that contains information about the header type Info struct { Height int64 // Height returns the height of the block diff --git a/runtime/v2/genesis.go b/runtime/v2/genesis.go index aca1f0fe3dd9..0dea54c97790 100644 --- a/runtime/v2/genesis.go +++ b/runtime/v2/genesis.go @@ -15,9 +15,8 @@ type genesisContextKeyType struct{} var genesisContextKey = genesisContextKeyType{} type genesisContext struct { - state store.WriterMap - headerInfo header.Info - didRun bool + state store.WriterMap + didRun bool } func makeGenesisContext(state store.WriterMap) genesisContext { @@ -45,7 +44,7 @@ type GenesisKVStoreServie struct { execution store.KVStoreService } -func NewGenesisCapableKVStoreService( +func NewGenesisKVService( actor []byte, execution store.KVStoreService, ) *GenesisKVStoreServie { @@ -63,7 +62,7 @@ func (g *GenesisKVStoreServie) OpenKVStore(ctx context.Context) store.KVStore { } v := ctx.Value(genesisContextKey) if v == nil { - panic("genesis context not found") + return g.execution.OpenKVStore(ctx) } genCtx, ok := v.(*genesisContext) if !ok { @@ -81,20 +80,35 @@ func (g *GenesisKVStoreServie) OpenKVStore(ctx context.Context) store.KVStore { } type GenesisHeaderService struct { - genesisCapable bool + genesisCapable bool + executionService header.Service } // HeaderInfo implements header.Service. func (g *GenesisHeaderService) HeaderInfo(ctx context.Context) header.Info { + if !g.genesisCapable { + return g.executionService.HeaderInfo(ctx) + } v := ctx.Value(genesisContextKey) if v == nil { - panic("genesis context not found") + return g.executionService.HeaderInfo(ctx) } genCtx, ok := v.(*genesisContext) if !ok { panic(fmt.Errorf("unexpected genesis context type: %T", v)) } - return genCtx.headerInfo + if genCtx.didRun { + g.genesisCapable = false + return g.executionService.HeaderInfo(ctx) + } + return header.Info{} +} + +func NewGenesisHeaderService(executionService header.Service) *GenesisHeaderService { + return &GenesisHeaderService{ + genesisCapable: true, + executionService: executionService, + } } var _ header.Service = (*GenesisHeaderService)(nil) diff --git a/runtime/v2/module.go b/runtime/v2/module.go index 3faad8c97570..8920fa975313 100644 --- a/runtime/v2/module.go +++ b/runtime/v2/module.go @@ -6,6 +6,7 @@ import ( "slices" "cosmossdk.io/core/comet" + "cosmossdk.io/core/header" rootstore "cosmossdk.io/store/v2/root" "github.com/cosmos/gogoproto/proto" @@ -195,6 +196,7 @@ func ProvideEnvironment[T transaction.Tx]( appBuilder *AppBuilder[T], kvFactory store.KVStoreServiceFactory, memFactory store.MemoryStoreServiceFactory, + headerFactory header.HeaderServiceFactory, ) ( appmodulev2.Environment, store.KVStoreService, @@ -228,7 +230,7 @@ func ProvideEnvironment[T transaction.Tx]( BranchService: stf.BranchService{}, EventService: stf.NewEventService(), GasService: stf.NewGasMeterService(), - HeaderService: stf.HeaderService{}, + HeaderService: headerFactory(), QueryRouterService: stf.NewQueryRouterService(), MsgRouterService: stf.NewMsgRouterService([]byte(key.Name())), TransactionService: services.NewContextAwareTransactionService(), @@ -256,13 +258,14 @@ func storeKeyOverride(config *runtimev2.Module, moduleName string) *runtimev2.St func DefaultServiceBindings() depinject.Config { var ( kvServiceFactory store.KVStoreServiceFactory = func(actor []byte) store.KVStoreService { - return NewGenesisService( + return NewGenesisKVService( actor, stf.NewKVStoreService(actor), ) } - memStoreServiceFactory store.MemoryStoreServiceFactory = func(actor []byte) store.MemoryStoreService { - return stf.NewMemoryStoreService(actor) + memStoreServiceFactory store.MemoryStoreServiceFactory = stf.NewMemoryStoreService + headerServiceFactory header.HeaderServiceFactory = func() header.Service { + return NewGenesisHeaderService(stf.HeaderService{}) } cometService comet.Service = &services.ContextAwareCometInfoService{} ) @@ -270,5 +273,6 @@ func DefaultServiceBindings() depinject.Config { kvServiceFactory, memStoreServiceFactory, cometService, + headerServiceFactory, ) } From a9773384255e9fa0417ab588ada9ea4b06ea3ed8 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Sun, 15 Sep 2024 14:32:16 -0500 Subject: [PATCH 26/57] refactor(stf): rm RunWithCtx --- core/header/service.go | 6 +- core/store/service.go | 4 + runtime/v2/builder.go | 55 +++++++++++--- runtime/v2/genesis.go | 114 +++++++++++++++++++++++++++++ runtime/v2/go.mod | 1 + runtime/v2/module.go | 37 ++++++++-- server/v2/appmanager/appmanager.go | 59 ++++++++++----- server/v2/appmanager/genesis.go | 18 ++++- simapp/v2/app_di.go | 1 + simapp/v2/go.mod | 1 + simapp/v2/simdv2/cmd/root_di.go | 17 ++++- 11 files changed, 267 insertions(+), 46 deletions(-) create mode 100644 runtime/v2/genesis.go diff --git a/core/header/service.go b/core/header/service.go index 15e6d4257425..29ee248f1389 100644 --- a/core/header/service.go +++ b/core/header/service.go @@ -13,6 +13,8 @@ type Service interface { HeaderInfo(context.Context) Info } +type HeaderServiceFactory func() Service + // Info defines a struct that contains information about the header type Info struct { Height int64 // Height returns the height of the block @@ -35,7 +37,7 @@ func (i *Info) Bytes() ([]byte, error) { // Encode Hash if len(i.Hash) != hashSize { - return nil, errors.New("invalid hash size") + return nil, errors.New("invalid Hash size") } buf = append(buf, i.Hash...) @@ -47,7 +49,7 @@ func (i *Info) Bytes() ([]byte, error) { // Encode AppHash if len(i.AppHash) != hashSize { - return nil, errors.New("invalid hash size") + return nil, errors.New("invalid AppHash size") } buf = append(buf, i.AppHash...) diff --git a/core/store/service.go b/core/store/service.go index 11eeaf0de9b3..60d4c023cc30 100644 --- a/core/store/service.go +++ b/core/store/service.go @@ -10,6 +10,8 @@ type KVStoreService interface { OpenKVStore(context.Context) KVStore } +type KVStoreServiceFactory func([]byte) KVStoreService + // MemoryStoreService represents a unique, non-forgeable handle to a memory-backed // KVStore. It should be provided as a module-scoped dependency by the runtime // module being used to build the app. @@ -18,6 +20,8 @@ type MemoryStoreService interface { OpenMemoryStore(context.Context) KVStore } +type MemoryStoreServiceFactory func([]byte) MemoryStoreService + // TransientStoreService represents a unique, non-forgeable handle to a memory-backed // KVStore which is reset at the start of every block. It should be provided as // a module-scoped dependency by the runtime module being used to build the app. diff --git a/runtime/v2/builder.go b/runtime/v2/builder.go index 0a1b279330de..5120725bea19 100644 --- a/runtime/v2/builder.go +++ b/runtime/v2/builder.go @@ -3,6 +3,7 @@ package runtime import ( "context" "encoding/json" + "errors" "fmt" "io" "path/filepath" @@ -45,7 +46,13 @@ func (a *AppBuilder[T]) RegisterModules(modules map[string]appmodulev2.AppModule // if a (legacy) module implements the HasName interface, check that the name matches if mod, ok := appModule.(interface{ Name() string }); ok { if name != mod.Name() { - a.app.logger.Warn(fmt.Sprintf("module name %q does not match name returned by HasName: %q", name, mod.Name())) + a.app.logger.Warn( + fmt.Sprintf( + "module name %q does not match name returned by HasName: %q", + name, + mod.Name(), + ), + ) } } @@ -157,20 +164,38 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { ValidateTxGasLimit: a.app.config.GasConfig.ValidateTxGasLimit, QueryGasLimit: a.app.config.GasConfig.QueryGasLimit, SimulationGasLimit: a.app.config.GasConfig.SimulationGasLimit, - InitGenesis: func(ctx context.Context, src io.Reader, txHandler func(json.RawMessage) error) error { + InitGenesis: func( + ctx context.Context, + src io.Reader, + txHandler func(json.RawMessage) error, + ) (store.WriterMap, error) { // this implementation assumes that the state is a JSON object bz, err := io.ReadAll(src) if err != nil { - return fmt.Errorf("failed to read import state: %w", err) + return nil, fmt.Errorf("failed to read import state: %w", err) } - var genesisState map[string]json.RawMessage - if err = json.Unmarshal(bz, &genesisState); err != nil { - return err + var genesisJSON map[string]json.RawMessage + if err = json.Unmarshal(bz, &genesisJSON); err != nil { + return nil, err } - if err = a.app.moduleManager.InitGenesisJSON(ctx, genesisState, txHandler); err != nil { - return fmt.Errorf("failed to init genesis: %w", err) + + v, zeroState, err := a.app.db.StateLatest() + if err != nil { + return nil, fmt.Errorf("unable to get latest state: %w", err) } - return nil + if v != 0 { // TODO: genesis state may be > 0, we need to set version on store + return nil, errors.New("cannot init genesis on non-zero state") + } + genesisCtx := makeGenesisContext(a.branch(zeroState)) + genesisState, err := genesisCtx.Run(ctx, func(ctx context.Context) error { + err = a.app.moduleManager.InitGenesisJSON(ctx, genesisJSON, txHandler) + if err != nil { + return fmt.Errorf("failed to init genesis: %w", err) + } + return nil + }) + + return genesisState, err }, ExportGenesis: func(ctx context.Context, version uint64) ([]byte, error) { genesisJson, err := a.app.moduleManager.ExportGenesisForModules(ctx) @@ -200,7 +225,9 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { type AppBuilderOption[T transaction.Tx] func(*AppBuilder[T]) // AppBuilderWithBranch sets a custom branch implementation for the app. -func AppBuilderWithBranch[T transaction.Tx](branch func(state store.ReaderMap) store.WriterMap) AppBuilderOption[T] { +func AppBuilderWithBranch[T transaction.Tx]( + branch func(state store.ReaderMap) store.WriterMap, +) AppBuilderOption[T] { return func(a *AppBuilder[T]) { a.branch = branch } @@ -208,7 +235,9 @@ func AppBuilderWithBranch[T transaction.Tx](branch func(state store.ReaderMap) s // AppBuilderWithTxValidator sets the tx validator for the app. // It overrides all default tx validators defined by modules. -func AppBuilderWithTxValidator[T transaction.Tx](txValidators func(ctx context.Context, tx T) error) AppBuilderOption[T] { +func AppBuilderWithTxValidator[T transaction.Tx]( + txValidators func(ctx context.Context, tx T) error, +) AppBuilderOption[T] { return func(a *AppBuilder[T]) { a.txValidator = txValidators } @@ -216,7 +245,9 @@ func AppBuilderWithTxValidator[T transaction.Tx](txValidators func(ctx context.C // AppBuilderWithPostTxExec sets logic that will be executed after each transaction. // When not provided, a no-op function will be used. -func AppBuilderWithPostTxExec[T transaction.Tx](postTxExec func(ctx context.Context, tx T, success bool) error) AppBuilderOption[T] { +func AppBuilderWithPostTxExec[T transaction.Tx]( + postTxExec func(ctx context.Context, tx T, success bool) error, +) AppBuilderOption[T] { return func(a *AppBuilder[T]) { a.postTxExec = postTxExec } diff --git a/runtime/v2/genesis.go b/runtime/v2/genesis.go new file mode 100644 index 000000000000..0dea54c97790 --- /dev/null +++ b/runtime/v2/genesis.go @@ -0,0 +1,114 @@ +package runtime + +import ( + "context" + "fmt" + + "cosmossdk.io/core/header" + "cosmossdk.io/core/store" +) + +var _ store.KVStoreService = (*GenesisKVStoreServie)(nil) + +type genesisContextKeyType struct{} + +var genesisContextKey = genesisContextKeyType{} + +type genesisContext struct { + state store.WriterMap + didRun bool +} + +func makeGenesisContext(state store.WriterMap) genesisContext { + return genesisContext{ + state: state, + } +} + +func (g *genesisContext) Run( + ctx context.Context, + fn func(ctx context.Context) error, +) (store.WriterMap, error) { + ctx = context.WithValue(ctx, genesisContextKey, g) + err := fn(ctx) + if err != nil { + return nil, err + } + g.didRun = true + return g.state, nil +} + +type GenesisKVStoreServie struct { + genesisCapable bool + actor []byte + execution store.KVStoreService +} + +func NewGenesisKVService( + actor []byte, + execution store.KVStoreService, +) *GenesisKVStoreServie { + return &GenesisKVStoreServie{ + genesisCapable: true, + actor: actor, + execution: execution, + } +} + +// OpenKVStore implements store.KVStoreService. +func (g *GenesisKVStoreServie) OpenKVStore(ctx context.Context) store.KVStore { + if !g.genesisCapable { + return g.execution.OpenKVStore(ctx) + } + v := ctx.Value(genesisContextKey) + if v == nil { + return g.execution.OpenKVStore(ctx) + } + genCtx, ok := v.(*genesisContext) + if !ok { + panic(fmt.Errorf("unexpected genesis context type: %T", v)) + } + if genCtx.didRun { + g.genesisCapable = false + return g.execution.OpenKVStore(ctx) + } + state, err := genCtx.state.GetWriter(g.actor) + if err != nil { + panic(err) + } + return state +} + +type GenesisHeaderService struct { + genesisCapable bool + executionService header.Service +} + +// HeaderInfo implements header.Service. +func (g *GenesisHeaderService) HeaderInfo(ctx context.Context) header.Info { + if !g.genesisCapable { + return g.executionService.HeaderInfo(ctx) + } + v := ctx.Value(genesisContextKey) + if v == nil { + return g.executionService.HeaderInfo(ctx) + } + genCtx, ok := v.(*genesisContext) + if !ok { + panic(fmt.Errorf("unexpected genesis context type: %T", v)) + } + if genCtx.didRun { + g.genesisCapable = false + return g.executionService.HeaderInfo(ctx) + } + return header.Info{} +} + +func NewGenesisHeaderService(executionService header.Service) *GenesisHeaderService { + return &GenesisHeaderService{ + genesisCapable: true, + executionService: executionService, + } +} + +var _ header.Service = (*GenesisHeaderService)(nil) diff --git a/runtime/v2/go.mod b/runtime/v2/go.mod index 4327d9d1c3e9..f4d68948f661 100644 --- a/runtime/v2/go.mod +++ b/runtime/v2/go.mod @@ -5,6 +5,7 @@ go 1.23 // server v2 integration replace ( cosmossdk.io/api => ../../api + cosmossdk.io/core => ../../core cosmossdk.io/core/testing => ../../core/testing cosmossdk.io/server/v2/appmanager => ../../server/v2/appmanager cosmossdk.io/server/v2/stf => ../../server/v2/stf diff --git a/runtime/v2/module.go b/runtime/v2/module.go index 8db0f557a57b..f07da52abcbe 100644 --- a/runtime/v2/module.go +++ b/runtime/v2/module.go @@ -16,6 +16,7 @@ import ( reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" appmodulev2 "cosmossdk.io/core/appmodule/v2" "cosmossdk.io/core/comet" + "cosmossdk.io/core/header" "cosmossdk.io/core/registry" "cosmossdk.io/core/server" "cosmossdk.io/core/store" @@ -96,7 +97,6 @@ func init() { ProvideAppBuilder[transaction.Tx], ProvideEnvironment[transaction.Tx], ProvideModuleManager[transaction.Tx], - ProvideCometService, ), appconfig.Invoke(SetupAppBuilder), ) @@ -176,6 +176,9 @@ func ProvideEnvironment[T transaction.Tx]( config *runtimev2.Module, key depinject.ModuleKey, appBuilder *AppBuilder[T], + kvFactory store.KVStoreServiceFactory, + memFactory store.MemoryStoreServiceFactory, + headerFactory header.HeaderServiceFactory, ) ( appmodulev2.Environment, store.KVStoreService, @@ -197,11 +200,11 @@ func ProvideEnvironment[T transaction.Tx]( } registerStoreKey(appBuilder, kvStoreKey) - kvService = stf.NewKVStoreService([]byte(kvStoreKey)) + kvService = kvFactory([]byte(kvStoreKey)) memStoreKey := fmt.Sprintf("memory:%s", key.Name()) registerStoreKey(appBuilder, memStoreKey) - memKvService = stf.NewMemoryStoreService([]byte(memStoreKey)) + memKvService = memFactory([]byte(memStoreKey)) } env := appmodulev2.Environment{ @@ -209,7 +212,7 @@ func ProvideEnvironment[T transaction.Tx]( BranchService: stf.BranchService{}, EventService: stf.NewEventService(), GasService: stf.NewGasMeterService(), - HeaderService: stf.HeaderService{}, + HeaderService: headerFactory(), QueryRouterService: stf.NewQueryRouterService(), MsgRouterService: stf.NewMsgRouterService([]byte(key.Name())), TransactionService: services.NewContextAwareTransactionService(), @@ -220,8 +223,8 @@ func ProvideEnvironment[T transaction.Tx]( return env, kvService, memKvService } -func registerStoreKey[T transaction.Tx](wrapper *AppBuilder[T], key string) { - wrapper.app.storeKeys = append(wrapper.app.storeKeys, key) +func registerStoreKey[T transaction.Tx](builder *AppBuilder[T], key string) { + builder.app.storeKeys = append(builder.app.storeKeys, key) } func storeKeyOverride(config *runtimev2.Module, moduleName string) *runtimev2.StoreKeyConfig { @@ -234,6 +237,24 @@ func storeKeyOverride(config *runtimev2.Module, moduleName string) *runtimev2.St return nil } -func ProvideCometService() comet.Service { - return &services.ContextAwareCometInfoService{} +func DefaultServiceBindings() depinject.Config { + var ( + kvServiceFactory store.KVStoreServiceFactory = func(actor []byte) store.KVStoreService { + return NewGenesisKVService( + actor, + stf.NewKVStoreService(actor), + ) + } + memStoreServiceFactory store.MemoryStoreServiceFactory = stf.NewMemoryStoreService + headerServiceFactory header.HeaderServiceFactory = func() header.Service { + return NewGenesisHeaderService(stf.HeaderService{}) + } + cometService comet.Service = &services.ContextAwareCometInfoService{} + ) + return depinject.Supply( + kvServiceFactory, + memStoreServiceFactory, + cometService, + headerServiceFactory, + ) } diff --git a/server/v2/appmanager/appmanager.go b/server/v2/appmanager/appmanager.go index e367c7d8fbfe..ca6ab55b03ed 100644 --- a/server/v2/appmanager/appmanager.go +++ b/server/v2/appmanager/appmanager.go @@ -43,25 +43,19 @@ func (a AppManager[T]) InitGenesis( initGenesisJSON []byte, txDecoder transaction.Codec[T], ) (*server.BlockResponse, corestore.WriterMap, error) { - v, zeroState, err := a.db.StateLatest() - if err != nil { - return nil, nil, fmt.Errorf("unable to get latest state: %w", err) - } - if v != 0 { // TODO: genesis state may be > 0, we need to set version on store - return nil, nil, errors.New("cannot init genesis on non-zero state") - } - var genTxs []T - genesisState, err := a.stf.RunWithCtx(ctx, zeroState, func(ctx context.Context) error { - return a.initGenesis(ctx, bytes.NewBuffer(initGenesisJSON), func(jsonTx json.RawMessage) error { + genesisState, err := a.initGenesis( + ctx, + bytes.NewBuffer(initGenesisJSON), + func(jsonTx json.RawMessage) error { genTx, err := txDecoder.DecodeJSON(jsonTx) if err != nil { return fmt.Errorf("failed to decode genesis transaction: %w", err) } genTxs = append(genTxs, genTx) return nil - }) - }) + }, + ) if err != nil { return nil, nil, fmt.Errorf("failed to import genesis state: %w", err) } @@ -70,7 +64,11 @@ func (a AppManager[T]) InitGenesis( blockResponse, blockZeroState, err := a.stf.DeliverBlock(ctx, blockRequest, genesisState) if err != nil { - return blockResponse, nil, fmt.Errorf("failed to deliver block %d: %w", blockRequest.Height, err) + return blockResponse, nil, fmt.Errorf( + "failed to deliver block %d: %w", + blockRequest.Height, + err, + ) } // after executing block 0, we extract the changes and apply them to the genesis state. @@ -81,7 +79,10 @@ func (a AppManager[T]) InitGenesis( err = genesisState.ApplyStateChanges(stateChanges) if err != nil { - return nil, nil, fmt.Errorf("failed to apply block zero state changes to genesis state: %w", err) + return nil, nil, fmt.Errorf( + "failed to apply block zero state changes to genesis state: %w", + err, + ) } return blockResponse, genesisState, err @@ -120,11 +121,19 @@ func (a AppManager[T]) DeliverBlock( ) (*server.BlockResponse, corestore.WriterMap, error) { latestVersion, currentState, err := a.db.StateLatest() if err != nil { - return nil, nil, fmt.Errorf("unable to create new state for height %d: %w", block.Height, err) + return nil, nil, fmt.Errorf( + "unable to create new state for height %d: %w", + block.Height, + err, + ) } if latestVersion+1 != block.Height { - return nil, nil, fmt.Errorf("invalid DeliverBlock height wanted %d, got %d", latestVersion+1, block.Height) + return nil, nil, fmt.Errorf( + "invalid DeliverBlock height wanted %d, got %d", + latestVersion+1, + block.Height, + ) } blockResponse, newState, err := a.stf.DeliverBlock(ctx, block, currentState) @@ -148,18 +157,30 @@ func (a AppManager[T]) ValidateTx(ctx context.Context, tx T) (server.TxResult, e } // Simulate runs validation and execution flow of a Tx. -func (a AppManager[T]) Simulate(ctx context.Context, tx T) (server.TxResult, corestore.WriterMap, error) { +func (a AppManager[T]) Simulate( + ctx context.Context, + tx T, +) (server.TxResult, corestore.WriterMap, error) { _, state, err := a.db.StateLatest() if err != nil { return server.TxResult{}, nil, err } - result, cs := a.stf.Simulate(ctx, state, a.config.SimulationGasLimit, tx) // TODO: check if this is done in the antehandler + result, cs := a.stf.Simulate( + ctx, + state, + a.config.SimulationGasLimit, + tx, + ) // TODO: check if this is done in the antehandler return result, cs, nil } // Query queries the application at the provided version. // CONTRACT: Version must always be provided, if 0, get latest -func (a AppManager[T]) Query(ctx context.Context, version uint64, request transaction.Msg) (transaction.Msg, error) { +func (a AppManager[T]) Query( + ctx context.Context, + version uint64, + request transaction.Msg, +) (transaction.Msg, error) { // if version is provided attempt to do a height query. if version != 0 { queryState, err := a.db.StateAt(version) diff --git a/server/v2/appmanager/genesis.go b/server/v2/appmanager/genesis.go index 8acad003b694..989ae442a9b9 100644 --- a/server/v2/appmanager/genesis.go +++ b/server/v2/appmanager/genesis.go @@ -4,11 +4,25 @@ import ( "context" "encoding/json" "io" + + "cosmossdk.io/core/store" ) type ( // ExportGenesis is a function type that represents the export of the genesis state. ExportGenesis func(ctx context.Context, version uint64) ([]byte, error) - // InitGenesis is a function type that represents the initialization of the genesis state. - InitGenesis func(ctx context.Context, src io.Reader, txHandler func(json.RawMessage) error) error + + // InitGenesis is a function that will run at application genesis, it will be called with + // the following arguments: + // - ctx: the context of the genesis operation + // - src: the source containing the raw genesis state + // - txHandler: a function capable of decoding a json tx, will be run for each genesis + // transaction + // + // It must return a map of the dirty state after the genesis operation. + InitGenesis func( + ctx context.Context, + src io.Reader, + txHandler func(json.RawMessage) error, + ) (store.WriterMap, error) ) diff --git a/simapp/v2/app_di.go b/simapp/v2/app_di.go index 733ab1ffc829..3c4e9f5db5b3 100644 --- a/simapp/v2/app_di.go +++ b/simapp/v2/app_di.go @@ -71,6 +71,7 @@ func NewSimApp[T transaction.Tx]( // merge the AppConfig and other configuration in one config appConfig = depinject.Configs( AppConfig(), + runtime.DefaultServiceBindings(), depinject.Supply( logger, viper, diff --git a/simapp/v2/go.mod b/simapp/v2/go.mod index e4003e4c9012..d61f3c214d3c 100644 --- a/simapp/v2/go.mod +++ b/simapp/v2/go.mod @@ -286,6 +286,7 @@ replace ( // server v2 integration replace ( cosmossdk.io/api => ../../api + cosmossdk.io/core => ../../core cosmossdk.io/core/testing => ../../core/testing cosmossdk.io/runtime/v2 => ../../runtime/v2 cosmossdk.io/server/v2 => ../../server/v2 diff --git a/simapp/v2/simdv2/cmd/root_di.go b/simapp/v2/simdv2/cmd/root_di.go index fd5b62b9384b..130130b8e57f 100644 --- a/simapp/v2/simdv2/cmd/root_di.go +++ b/simapp/v2/simdv2/cmd/root_di.go @@ -37,6 +37,7 @@ func NewRootCmd[T transaction.Tx]() *cobra.Command { if err := depinject.Inject( depinject.Configs( simapp.AppConfig(), + runtime.DefaultServiceBindings(), depinject.Supply(log.NewNopLogger()), depinject.Provide( codec.ProvideInterfaceRegistry, @@ -69,7 +70,11 @@ func NewRootCmd[T transaction.Tx]() *cobra.Command { } customClientTemplate, customClientConfig := initClientConfig() - clientCtx, err = config.CreateClientConfig(clientCtx, customClientTemplate, customClientConfig) + clientCtx, err = config.CreateClientConfig( + clientCtx, + customClientTemplate, + customClientConfig, + ) if err != nil { return err } @@ -108,7 +113,9 @@ func ProvideClientContext( amino, ok := legacyAmino.(*codec.LegacyAmino) if !ok { - panic("registry.AminoRegistrar must be an *codec.LegacyAmino instance for legacy ClientContext") + panic( + "registry.AminoRegistrar must be an *codec.LegacyAmino instance for legacy ClientContext", + ) } clientCtx := client.Context{}. @@ -125,7 +132,11 @@ func ProvideClientContext( // Read the config to overwrite the default values with the values from the config file customClientTemplate, customClientConfig := initClientConfig() - clientCtx, err = config.CreateClientConfig(clientCtx, customClientTemplate, customClientConfig) + clientCtx, err = config.CreateClientConfig( + clientCtx, + customClientTemplate, + customClientConfig, + ) if err != nil { panic(err) } From 30814acab941a5d566f30164bc56ffc72ddcdf2f Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Sun, 15 Sep 2024 14:45:05 -0500 Subject: [PATCH 27/57] migrate export genesis and remove stf.RunWithCtx --- .vscode/launch.json | 2 +- runtime/v2/builder.go | 12 ++++++++- runtime/v2/genesis.go | 24 +++++------------- server/v2/appmanager/appmanager.go | 24 +++--------------- server/v2/appmanager/types.go | 8 ------ server/v2/stf/stf.go | 39 ++++++++++++++++++------------ 6 files changed, 44 insertions(+), 65 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index a5e7a729457b..5e7c4837581e 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -18,7 +18,7 @@ "request": "launch", "mode": "debug", "program": "${workspaceFolder}/simapp/v2/simdv2", - "args": ["start"], + "args": ["genesis", "export"], "buildFlags": "" }, { diff --git a/runtime/v2/builder.go b/runtime/v2/builder.go index 5120725bea19..fc370a2ffe11 100644 --- a/runtime/v2/builder.go +++ b/runtime/v2/builder.go @@ -198,7 +198,17 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { return genesisState, err }, ExportGenesis: func(ctx context.Context, version uint64) ([]byte, error) { - genesisJson, err := a.app.moduleManager.ExportGenesisForModules(ctx) + _, state, err := a.app.db.StateLatest() + if err != nil { + return nil, fmt.Errorf("unable to get latest state: %w", err) + } + genesisCtx := makeGenesisContext(a.branch(state)) + + var genesisJson map[string]json.RawMessage + _, err = genesisCtx.Run(ctx, func(ctx context.Context) error { + genesisJson, err = a.app.moduleManager.ExportGenesisForModules(ctx) + return err + }) if err != nil { return nil, fmt.Errorf("failed to export genesis: %w", err) } diff --git a/runtime/v2/genesis.go b/runtime/v2/genesis.go index 0dea54c97790..5bb2fef72b7b 100644 --- a/runtime/v2/genesis.go +++ b/runtime/v2/genesis.go @@ -39,9 +39,8 @@ func (g *genesisContext) Run( } type GenesisKVStoreServie struct { - genesisCapable bool - actor []byte - execution store.KVStoreService + actor []byte + executionService store.KVStoreService } func NewGenesisKVService( @@ -49,28 +48,23 @@ func NewGenesisKVService( execution store.KVStoreService, ) *GenesisKVStoreServie { return &GenesisKVStoreServie{ - genesisCapable: true, - actor: actor, - execution: execution, + actor: actor, + executionService: execution, } } // OpenKVStore implements store.KVStoreService. func (g *GenesisKVStoreServie) OpenKVStore(ctx context.Context) store.KVStore { - if !g.genesisCapable { - return g.execution.OpenKVStore(ctx) - } v := ctx.Value(genesisContextKey) if v == nil { - return g.execution.OpenKVStore(ctx) + return g.executionService.OpenKVStore(ctx) } genCtx, ok := v.(*genesisContext) if !ok { panic(fmt.Errorf("unexpected genesis context type: %T", v)) } if genCtx.didRun { - g.genesisCapable = false - return g.execution.OpenKVStore(ctx) + return g.executionService.OpenKVStore(ctx) } state, err := genCtx.state.GetWriter(g.actor) if err != nil { @@ -80,15 +74,11 @@ func (g *GenesisKVStoreServie) OpenKVStore(ctx context.Context) store.KVStore { } type GenesisHeaderService struct { - genesisCapable bool executionService header.Service } // HeaderInfo implements header.Service. func (g *GenesisHeaderService) HeaderInfo(ctx context.Context) header.Info { - if !g.genesisCapable { - return g.executionService.HeaderInfo(ctx) - } v := ctx.Value(genesisContextKey) if v == nil { return g.executionService.HeaderInfo(ctx) @@ -98,7 +88,6 @@ func (g *GenesisHeaderService) HeaderInfo(ctx context.Context) header.Info { panic(fmt.Errorf("unexpected genesis context type: %T", v)) } if genCtx.didRun { - g.genesisCapable = false return g.executionService.HeaderInfo(ctx) } return header.Info{} @@ -106,7 +95,6 @@ func (g *GenesisHeaderService) HeaderInfo(ctx context.Context) header.Info { func NewGenesisHeaderService(executionService header.Service) *GenesisHeaderService { return &GenesisHeaderService{ - genesisCapable: true, executionService: executionService, } } diff --git a/server/v2/appmanager/appmanager.go b/server/v2/appmanager/appmanager.go index ca6ab55b03ed..869d7e6d1dba 100644 --- a/server/v2/appmanager/appmanager.go +++ b/server/v2/appmanager/appmanager.go @@ -90,29 +90,11 @@ func (a AppManager[T]) InitGenesis( // ExportGenesis exports the genesis state of the application. func (a AppManager[T]) ExportGenesis(ctx context.Context, version uint64) ([]byte, error) { - zeroState, err := a.db.StateAt(version) - if err != nil { - return nil, fmt.Errorf("unable to get latest state: %w", err) - } - - bz := make([]byte, 0) - _, err = a.stf.RunWithCtx(ctx, zeroState, func(ctx context.Context) error { - if a.exportGenesis == nil { - return errors.New("export genesis function not set") - } - - bz, err = a.exportGenesis(ctx, version) - if err != nil { - return fmt.Errorf("failed to export genesis state: %w", err) - } - - return nil - }) - if err != nil { - return nil, fmt.Errorf("failed to export genesis state: %w", err) + if a.exportGenesis == nil { + return nil, errors.New("export genesis function not set") } - return bz, nil + return a.exportGenesis(ctx, version) } func (a AppManager[T]) DeliverBlock( diff --git a/server/v2/appmanager/types.go b/server/v2/appmanager/types.go index 149f190f353e..1e769c13ff9c 100644 --- a/server/v2/appmanager/types.go +++ b/server/v2/appmanager/types.go @@ -40,12 +40,4 @@ type StateTransitionFunction[T transaction.Tx] interface { gasLimit uint64, req transaction.Msg, ) (transaction.Msg, error) - - // RunWithCtx executes the provided closure within a context. - // TODO: remove - RunWithCtx( - ctx context.Context, - state store.ReaderMap, - closure func(ctx context.Context) error, - ) (store.WriterMap, error) } diff --git a/server/v2/stf/stf.go b/server/v2/stf/stf.go index e32a8f33293e..02b5f941f9c5 100644 --- a/server/v2/stf/stf.go +++ b/server/v2/stf/stf.go @@ -202,7 +202,14 @@ func (s STF[T]) deliverTx( } } - execResp, execGas, execEvents, err := s.execTx(ctx, state, gasLimit-validateGas, tx, execMode, hi) + execResp, execGas, execEvents, err := s.execTx( + ctx, + state, + gasLimit-validateGas, + tx, + execMode, + hi, + ) return server.TxResult{ Events: append(validationEvents, execEvents...), GasUsed: execGas + validateGas, @@ -250,7 +257,14 @@ func (s STF[T]) execTx( ) ([]transaction.Msg, uint64, []event.Event, error) { execState := s.branchFn(state) - msgsResp, gasUsed, runTxMsgsEvents, txErr := s.runTxMsgs(ctx, execState, gasLimit, tx, execMode, hi) + msgsResp, gasUsed, runTxMsgsEvents, txErr := s.runTxMsgs( + ctx, + execState, + gasLimit, + tx, + execMode, + hi, + ) if txErr != nil { // in case of error during message execution, we do not apply the exec state. // instead we run the post exec handler in a new branchFn from the initial state. @@ -430,7 +444,13 @@ func (s STF[T]) ValidateTx( tx T, ) server.TxResult { validationState := s.branchFn(state) - gasUsed, events, err := s.validateTx(ctx, validationState, gasLimit, tx, transaction.ExecModeCheck) + gasUsed, events, err := s.validateTx( + ctx, + validationState, + gasLimit, + tx, + transaction.ExecModeCheck, + ) return server.TxResult{ Events: events, GasUsed: gasUsed, @@ -456,19 +476,6 @@ func (s STF[T]) Query( return s.queryRouter.Invoke(queryCtx, req) } -// RunWithCtx is made to support genesis, if genesis was just the execution of messages instead -// of being something custom then we would not need this. PLEASE DO NOT USE. -// TODO: Remove -func (s STF[T]) RunWithCtx( - ctx context.Context, - state store.ReaderMap, - closure func(ctx context.Context) error, -) (store.WriterMap, error) { - branchedState := s.branchFn(state) - stfCtx := s.makeContext(ctx, nil, branchedState, internal.ExecModeFinalize) - return branchedState, closure(stfCtx) -} - // clone clones STF. func (s STF[T]) clone() STF[T] { return STF[T]{ From ef50b4f036c65064b7fa5aff96a1d3a705c8e9c0 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Sun, 15 Sep 2024 22:16:08 -0500 Subject: [PATCH 28/57] revert line wrapping --- runtime/v2/builder.go | 20 +++---------- server/v2/appmanager/appmanager.go | 47 +++++------------------------- server/v2/stf/stf.go | 26 ++--------------- simapp/v2/simdv2/cmd/root_di.go | 16 ++-------- 4 files changed, 18 insertions(+), 91 deletions(-) diff --git a/runtime/v2/builder.go b/runtime/v2/builder.go index fc370a2ffe11..f21c38639e20 100644 --- a/runtime/v2/builder.go +++ b/runtime/v2/builder.go @@ -46,13 +46,7 @@ func (a *AppBuilder[T]) RegisterModules(modules map[string]appmodulev2.AppModule // if a (legacy) module implements the HasName interface, check that the name matches if mod, ok := appModule.(interface{ Name() string }); ok { if name != mod.Name() { - a.app.logger.Warn( - fmt.Sprintf( - "module name %q does not match name returned by HasName: %q", - name, - mod.Name(), - ), - ) + a.app.logger.Warn(fmt.Sprintf("module name %q does not match name returned by HasName: %q", name, mod.Name())) } } @@ -235,9 +229,7 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { type AppBuilderOption[T transaction.Tx] func(*AppBuilder[T]) // AppBuilderWithBranch sets a custom branch implementation for the app. -func AppBuilderWithBranch[T transaction.Tx]( - branch func(state store.ReaderMap) store.WriterMap, -) AppBuilderOption[T] { +func AppBuilderWithBranch[T transaction.Tx](branch func(state store.ReaderMap) store.WriterMap) AppBuilderOption[T] { return func(a *AppBuilder[T]) { a.branch = branch } @@ -245,9 +237,7 @@ func AppBuilderWithBranch[T transaction.Tx]( // AppBuilderWithTxValidator sets the tx validator for the app. // It overrides all default tx validators defined by modules. -func AppBuilderWithTxValidator[T transaction.Tx]( - txValidators func(ctx context.Context, tx T) error, -) AppBuilderOption[T] { +func AppBuilderWithTxValidator[T transaction.Tx](txValidators func(ctx context.Context, tx T) error) AppBuilderOption[T] { return func(a *AppBuilder[T]) { a.txValidator = txValidators } @@ -255,9 +245,7 @@ func AppBuilderWithTxValidator[T transaction.Tx]( // AppBuilderWithPostTxExec sets logic that will be executed after each transaction. // When not provided, a no-op function will be used. -func AppBuilderWithPostTxExec[T transaction.Tx]( - postTxExec func(ctx context.Context, tx T, success bool) error, -) AppBuilderOption[T] { +func AppBuilderWithPostTxExec[T transaction.Tx](postTxExec func(ctx context.Context, tx T, success bool) error) AppBuilderOption[T] { return func(a *AppBuilder[T]) { a.postTxExec = postTxExec } diff --git a/server/v2/appmanager/appmanager.go b/server/v2/appmanager/appmanager.go index 869d7e6d1dba..6a5f96ec5fa9 100644 --- a/server/v2/appmanager/appmanager.go +++ b/server/v2/appmanager/appmanager.go @@ -64,11 +64,7 @@ func (a AppManager[T]) InitGenesis( blockResponse, blockZeroState, err := a.stf.DeliverBlock(ctx, blockRequest, genesisState) if err != nil { - return blockResponse, nil, fmt.Errorf( - "failed to deliver block %d: %w", - blockRequest.Height, - err, - ) + return blockResponse, nil, fmt.Errorf("failed to deliver block %d: %w", blockRequest.Height, err) } // after executing block 0, we extract the changes and apply them to the genesis state. @@ -79,10 +75,7 @@ func (a AppManager[T]) InitGenesis( err = genesisState.ApplyStateChanges(stateChanges) if err != nil { - return nil, nil, fmt.Errorf( - "failed to apply block zero state changes to genesis state: %w", - err, - ) + return nil, nil, fmt.Errorf("failed to apply block zero state changes to genesis state: %w", err) } return blockResponse, genesisState, err @@ -103,19 +96,11 @@ func (a AppManager[T]) DeliverBlock( ) (*server.BlockResponse, corestore.WriterMap, error) { latestVersion, currentState, err := a.db.StateLatest() if err != nil { - return nil, nil, fmt.Errorf( - "unable to create new state for height %d: %w", - block.Height, - err, - ) + return nil, nil, fmt.Errorf("unable to create new state for height %d: %w", block.Height, err) } if latestVersion+1 != block.Height { - return nil, nil, fmt.Errorf( - "invalid DeliverBlock height wanted %d, got %d", - latestVersion+1, - block.Height, - ) + return nil, nil, fmt.Errorf("invalid DeliverBlock height wanted %d, got %d", latestVersion+1, block.Height) } blockResponse, newState, err := a.stf.DeliverBlock(ctx, block, currentState) @@ -139,30 +124,18 @@ func (a AppManager[T]) ValidateTx(ctx context.Context, tx T) (server.TxResult, e } // Simulate runs validation and execution flow of a Tx. -func (a AppManager[T]) Simulate( - ctx context.Context, - tx T, -) (server.TxResult, corestore.WriterMap, error) { +func (a AppManager[T]) Simulate(ctx context.Context, tx T) (server.TxResult, corestore.WriterMap, error) { _, state, err := a.db.StateLatest() if err != nil { return server.TxResult{}, nil, err } - result, cs := a.stf.Simulate( - ctx, - state, - a.config.SimulationGasLimit, - tx, - ) // TODO: check if this is done in the antehandler + result, cs := a.stf.Simulate(ctx, state, a.config.SimulationGasLimit, tx) // TODO: check if this is done in the antehandler return result, cs, nil } // Query queries the application at the provided version. // CONTRACT: Version must always be provided, if 0, get latest -func (a AppManager[T]) Query( - ctx context.Context, - version uint64, - request transaction.Msg, -) (transaction.Msg, error) { +func (a AppManager[T]) Query(ctx context.Context, version uint64, request transaction.Msg) (transaction.Msg, error) { // if version is provided attempt to do a height query. if version != 0 { queryState, err := a.db.StateAt(version) @@ -183,10 +156,6 @@ func (a AppManager[T]) Query( // QueryWithState executes a query with the provided state. This allows to process a query // independently of the db state. For example, it can be used to process a query with temporary // and uncommitted state -func (a AppManager[T]) QueryWithState( - ctx context.Context, - state corestore.ReaderMap, - request transaction.Msg, -) (transaction.Msg, error) { +func (a AppManager[T]) QueryWithState(ctx context.Context, state corestore.ReaderMap, request transaction.Msg) (transaction.Msg, error) { return a.stf.Query(ctx, state, a.config.QueryGasLimit, request) } diff --git a/server/v2/stf/stf.go b/server/v2/stf/stf.go index 02b5f941f9c5..06a993fd91e3 100644 --- a/server/v2/stf/stf.go +++ b/server/v2/stf/stf.go @@ -202,14 +202,7 @@ func (s STF[T]) deliverTx( } } - execResp, execGas, execEvents, err := s.execTx( - ctx, - state, - gasLimit-validateGas, - tx, - execMode, - hi, - ) + execResp, execGas, execEvents, err := s.execTx(ctx, state, gasLimit-validateGas, tx, execMode, hi) return server.TxResult{ Events: append(validationEvents, execEvents...), GasUsed: execGas + validateGas, @@ -257,14 +250,7 @@ func (s STF[T]) execTx( ) ([]transaction.Msg, uint64, []event.Event, error) { execState := s.branchFn(state) - msgsResp, gasUsed, runTxMsgsEvents, txErr := s.runTxMsgs( - ctx, - execState, - gasLimit, - tx, - execMode, - hi, - ) + msgsResp, gasUsed, runTxMsgsEvents, txErr := s.runTxMsgs(ctx, execState, gasLimit, tx, execMode, hi) if txErr != nil { // in case of error during message execution, we do not apply the exec state. // instead we run the post exec handler in a new branchFn from the initial state. @@ -444,13 +430,7 @@ func (s STF[T]) ValidateTx( tx T, ) server.TxResult { validationState := s.branchFn(state) - gasUsed, events, err := s.validateTx( - ctx, - validationState, - gasLimit, - tx, - transaction.ExecModeCheck, - ) + gasUsed, events, err := s.validateTx(ctx, validationState, gasLimit, tx, transaction.ExecModeCheck) return server.TxResult{ Events: events, GasUsed: gasUsed, diff --git a/simapp/v2/simdv2/cmd/root_di.go b/simapp/v2/simdv2/cmd/root_di.go index 130130b8e57f..1ad834b53a5a 100644 --- a/simapp/v2/simdv2/cmd/root_di.go +++ b/simapp/v2/simdv2/cmd/root_di.go @@ -70,11 +70,7 @@ func NewRootCmd[T transaction.Tx]() *cobra.Command { } customClientTemplate, customClientConfig := initClientConfig() - clientCtx, err = config.CreateClientConfig( - clientCtx, - customClientTemplate, - customClientConfig, - ) + clientCtx, err = config.CreateClientConfig(clientCtx, customClientTemplate, customClientConfig) if err != nil { return err } @@ -113,9 +109,7 @@ func ProvideClientContext( amino, ok := legacyAmino.(*codec.LegacyAmino) if !ok { - panic( - "registry.AminoRegistrar must be an *codec.LegacyAmino instance for legacy ClientContext", - ) + panic("registry.AminoRegistrar must be an *codec.LegacyAmino instance for legacy ClientContext") } clientCtx := client.Context{}. @@ -132,11 +126,7 @@ func ProvideClientContext( // Read the config to overwrite the default values with the values from the config file customClientTemplate, customClientConfig := initClientConfig() - clientCtx, err = config.CreateClientConfig( - clientCtx, - customClientTemplate, - customClientConfig, - ) + clientCtx, err = config.CreateClientConfig(clientCtx, customClientTemplate, customClientConfig) if err != nil { panic(err) } From 177a0da035c57387905b197fa5594c59f747c71f Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 16 Sep 2024 08:57:51 -0500 Subject: [PATCH 29/57] small refactor move genesis services --- runtime/v2/builder.go | 5 +++-- runtime/v2/module.go | 4 ++-- runtime/v2/{ => services}/genesis.go | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) rename runtime/v2/{ => services}/genesis.go (96%) diff --git a/runtime/v2/builder.go b/runtime/v2/builder.go index f21c38639e20..65b128572c33 100644 --- a/runtime/v2/builder.go +++ b/runtime/v2/builder.go @@ -13,6 +13,7 @@ import ( "cosmossdk.io/core/server" "cosmossdk.io/core/store" "cosmossdk.io/core/transaction" + "cosmossdk.io/runtime/v2/services" "cosmossdk.io/server/v2/appmanager" "cosmossdk.io/server/v2/stf" "cosmossdk.io/server/v2/stf/branch" @@ -180,7 +181,7 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { if v != 0 { // TODO: genesis state may be > 0, we need to set version on store return nil, errors.New("cannot init genesis on non-zero state") } - genesisCtx := makeGenesisContext(a.branch(zeroState)) + genesisCtx := services.NewGenesisContext(a.branch(zeroState)) genesisState, err := genesisCtx.Run(ctx, func(ctx context.Context) error { err = a.app.moduleManager.InitGenesisJSON(ctx, genesisJSON, txHandler) if err != nil { @@ -196,7 +197,7 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { if err != nil { return nil, fmt.Errorf("unable to get latest state: %w", err) } - genesisCtx := makeGenesisContext(a.branch(state)) + genesisCtx := services.NewGenesisContext(a.branch(state)) var genesisJson map[string]json.RawMessage _, err = genesisCtx.Run(ctx, func(ctx context.Context) error { diff --git a/runtime/v2/module.go b/runtime/v2/module.go index f07da52abcbe..60e2e2c96878 100644 --- a/runtime/v2/module.go +++ b/runtime/v2/module.go @@ -240,14 +240,14 @@ func storeKeyOverride(config *runtimev2.Module, moduleName string) *runtimev2.St func DefaultServiceBindings() depinject.Config { var ( kvServiceFactory store.KVStoreServiceFactory = func(actor []byte) store.KVStoreService { - return NewGenesisKVService( + return services.NewGenesisKVService( actor, stf.NewKVStoreService(actor), ) } memStoreServiceFactory store.MemoryStoreServiceFactory = stf.NewMemoryStoreService headerServiceFactory header.HeaderServiceFactory = func() header.Service { - return NewGenesisHeaderService(stf.HeaderService{}) + return services.NewGenesisHeaderService(stf.HeaderService{}) } cometService comet.Service = &services.ContextAwareCometInfoService{} ) diff --git a/runtime/v2/genesis.go b/runtime/v2/services/genesis.go similarity index 96% rename from runtime/v2/genesis.go rename to runtime/v2/services/genesis.go index 5bb2fef72b7b..7a0839e48322 100644 --- a/runtime/v2/genesis.go +++ b/runtime/v2/services/genesis.go @@ -1,4 +1,4 @@ -package runtime +package services import ( "context" @@ -19,7 +19,7 @@ type genesisContext struct { didRun bool } -func makeGenesisContext(state store.WriterMap) genesisContext { +func NewGenesisContext(state store.WriterMap) genesisContext { return genesisContext{ state: state, } From 45ff83a1f96147ce32577ad54da29784be6522be Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 16 Sep 2024 08:58:35 -0500 Subject: [PATCH 30/57] go mod tidy all --- runtime/v2/go.sum | 2 -- simapp/v2/go.sum | 2 -- 2 files changed, 4 deletions(-) diff --git a/runtime/v2/go.sum b/runtime/v2/go.sum index 30d27ab50056..6a4643be1e08 100644 --- a/runtime/v2/go.sum +++ b/runtime/v2/go.sum @@ -2,8 +2,6 @@ buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.34.2-20240701160653-fed buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.34.2-20240701160653-fedbb9acfd2f.2/go.mod h1:1+3gJj2NvZ1mTLAtHu+lMhOjGgQPiCKCeo+9MBww0Eo= buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88ef6483f90f.2 h1:b7EEYTUHmWSBEyISHlHvXbJPqtKiHRuUignL1tsHnNQ= buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88ef6483f90f.2/go.mod h1:HqcXMSa5qnNuakaMUo+hWhF51mKbcrZxGl9Vp5EeJXc= -cosmossdk.io/core v1.0.0-alpha.2 h1:epU0Xwces4Rgl5bMhHHkXGaGDcyucNGlC/JDH+Suckg= -cosmossdk.io/core v1.0.0-alpha.2/go.mod h1:abgLjeFLhtuKIYZWSPlVUgQBrKObO7ULV35KYfexE90= cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050= cosmossdk.io/depinject v1.0.0/go.mod h1:zxK/h3HgHoA/eJVtiSsoaRaRA2D5U4cJ5thIG4ssbB8= cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5 h1:IQNdY2kB+k+1OM2DvqFG1+UgeU1JzZrWtwuWzI3ZfwA= diff --git a/simapp/v2/go.sum b/simapp/v2/go.sum index ede14d58a04e..4856648b3768 100644 --- a/simapp/v2/go.sum +++ b/simapp/v2/go.sum @@ -192,8 +192,6 @@ cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xX cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cosmossdk.io/core v1.0.0-alpha.2 h1:epU0Xwces4Rgl5bMhHHkXGaGDcyucNGlC/JDH+Suckg= -cosmossdk.io/core v1.0.0-alpha.2/go.mod h1:abgLjeFLhtuKIYZWSPlVUgQBrKObO7ULV35KYfexE90= cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050= cosmossdk.io/depinject v1.0.0/go.mod h1:zxK/h3HgHoA/eJVtiSsoaRaRA2D5U4cJ5thIG4ssbB8= cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= From 16a0e996cc6b8e4d134ab41829bad46e81fd8f1d Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 16 Sep 2024 08:59:08 -0500 Subject: [PATCH 31/57] revert vscode change --- .vscode/launch.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 5e7c4837581e..a5e7a729457b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -18,7 +18,7 @@ "request": "launch", "mode": "debug", "program": "${workspaceFolder}/simapp/v2/simdv2", - "args": ["genesis", "export"], + "args": ["start"], "buildFlags": "" }, { From 9fe10204d02b15d7096857aa272fc2f650d3c09d Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 16 Sep 2024 09:41:36 -0500 Subject: [PATCH 32/57] update genesis service --- runtime/v2/services/genesis.go | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/runtime/v2/services/genesis.go b/runtime/v2/services/genesis.go index 7a0839e48322..8f09520336ab 100644 --- a/runtime/v2/services/genesis.go +++ b/runtime/v2/services/genesis.go @@ -15,8 +15,7 @@ type genesisContextKeyType struct{} var genesisContextKey = genesisContextKeyType{} type genesisContext struct { - state store.WriterMap - didRun bool + state store.WriterMap } func NewGenesisContext(state store.WriterMap) genesisContext { @@ -34,7 +33,6 @@ func (g *genesisContext) Run( if err != nil { return nil, err } - g.didRun = true return g.state, nil } @@ -63,9 +61,6 @@ func (g *GenesisKVStoreServie) OpenKVStore(ctx context.Context) store.KVStore { if !ok { panic(fmt.Errorf("unexpected genesis context type: %T", v)) } - if genCtx.didRun { - return g.executionService.OpenKVStore(ctx) - } state, err := genCtx.state.GetWriter(g.actor) if err != nil { panic(err) @@ -83,13 +78,6 @@ func (g *GenesisHeaderService) HeaderInfo(ctx context.Context) header.Info { if v == nil { return g.executionService.HeaderInfo(ctx) } - genCtx, ok := v.(*genesisContext) - if !ok { - panic(fmt.Errorf("unexpected genesis context type: %T", v)) - } - if genCtx.didRun { - return g.executionService.HeaderInfo(ctx) - } return header.Info{} } From 80db042ec6f6773f706ccb8bf1c04e6e31eecb6e Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 16 Sep 2024 10:15:46 -0500 Subject: [PATCH 33/57] clean up --- core/header/service.go | 2 -- core/store/service.go | 5 +++-- runtime/v2/module.go | 17 ++++++----------- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/core/header/service.go b/core/header/service.go index 29ee248f1389..8d36087a059c 100644 --- a/core/header/service.go +++ b/core/header/service.go @@ -13,8 +13,6 @@ type Service interface { HeaderInfo(context.Context) Info } -type HeaderServiceFactory func() Service - // Info defines a struct that contains information about the header type Info struct { Height int64 // Height returns the height of the block diff --git a/core/store/service.go b/core/store/service.go index 60d4c023cc30..6faec8bdb0ce 100644 --- a/core/store/service.go +++ b/core/store/service.go @@ -10,6 +10,9 @@ type KVStoreService interface { OpenKVStore(context.Context) KVStore } +// KVStoreServiceFactory is a function that creates a new KVStoreService. +// It can be used to override the default KVStoreService bindings for cases +// where an application must supply a custom stateful backend. type KVStoreServiceFactory func([]byte) KVStoreService // MemoryStoreService represents a unique, non-forgeable handle to a memory-backed @@ -20,8 +23,6 @@ type MemoryStoreService interface { OpenMemoryStore(context.Context) KVStore } -type MemoryStoreServiceFactory func([]byte) MemoryStoreService - // TransientStoreService represents a unique, non-forgeable handle to a memory-backed // KVStore which is reset at the start of every block. It should be provided as // a module-scoped dependency by the runtime module being used to build the app. diff --git a/runtime/v2/module.go b/runtime/v2/module.go index 60e2e2c96878..9f55024af893 100644 --- a/runtime/v2/module.go +++ b/runtime/v2/module.go @@ -177,8 +177,7 @@ func ProvideEnvironment[T transaction.Tx]( key depinject.ModuleKey, appBuilder *AppBuilder[T], kvFactory store.KVStoreServiceFactory, - memFactory store.MemoryStoreServiceFactory, - headerFactory header.HeaderServiceFactory, + headerService header.Service, ) ( appmodulev2.Environment, store.KVStoreService, @@ -204,7 +203,7 @@ func ProvideEnvironment[T transaction.Tx]( memStoreKey := fmt.Sprintf("memory:%s", key.Name()) registerStoreKey(appBuilder, memStoreKey) - memKvService = memFactory([]byte(memStoreKey)) + memKvService = stf.NewMemoryStoreService([]byte(memStoreKey)) } env := appmodulev2.Environment{ @@ -212,7 +211,7 @@ func ProvideEnvironment[T transaction.Tx]( BranchService: stf.BranchService{}, EventService: stf.NewEventService(), GasService: stf.NewGasMeterService(), - HeaderService: headerFactory(), + HeaderService: headerService, QueryRouterService: stf.NewQueryRouterService(), MsgRouterService: stf.NewMsgRouterService([]byte(key.Name())), TransactionService: services.NewContextAwareTransactionService(), @@ -245,16 +244,12 @@ func DefaultServiceBindings() depinject.Config { stf.NewKVStoreService(actor), ) } - memStoreServiceFactory store.MemoryStoreServiceFactory = stf.NewMemoryStoreService - headerServiceFactory header.HeaderServiceFactory = func() header.Service { - return services.NewGenesisHeaderService(stf.HeaderService{}) - } - cometService comet.Service = &services.ContextAwareCometInfoService{} + headerService header.Service = services.NewGenesisHeaderService(stf.HeaderService{}) + cometService comet.Service = &services.ContextAwareCometInfoService{} ) return depinject.Supply( kvServiceFactory, - memStoreServiceFactory, + headerService, cometService, - headerServiceFactory, ) } From 57ec23946fcc6c8322393c2b11ec56996e78dcd7 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 16 Sep 2024 10:17:02 -0500 Subject: [PATCH 34/57] fix typo --- runtime/v2/services/genesis.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/runtime/v2/services/genesis.go b/runtime/v2/services/genesis.go index 8f09520336ab..72db330667c7 100644 --- a/runtime/v2/services/genesis.go +++ b/runtime/v2/services/genesis.go @@ -8,7 +8,7 @@ import ( "cosmossdk.io/core/store" ) -var _ store.KVStoreService = (*GenesisKVStoreServie)(nil) +var _ store.KVStoreService = (*GenesisKVStoreService)(nil) type genesisContextKeyType struct{} @@ -36,7 +36,7 @@ func (g *genesisContext) Run( return g.state, nil } -type GenesisKVStoreServie struct { +type GenesisKVStoreService struct { actor []byte executionService store.KVStoreService } @@ -44,15 +44,15 @@ type GenesisKVStoreServie struct { func NewGenesisKVService( actor []byte, execution store.KVStoreService, -) *GenesisKVStoreServie { - return &GenesisKVStoreServie{ +) *GenesisKVStoreService { + return &GenesisKVStoreService{ actor: actor, executionService: execution, } } // OpenKVStore implements store.KVStoreService. -func (g *GenesisKVStoreServie) OpenKVStore(ctx context.Context) store.KVStore { +func (g *GenesisKVStoreService) OpenKVStore(ctx context.Context) store.KVStore { v := ctx.Value(genesisContextKey) if v == nil { return g.executionService.OpenKVStore(ctx) From c20649d97f996c0d6c90295c541fbb1aef519110 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 16 Sep 2024 11:18:01 -0500 Subject: [PATCH 35/57] fix test --- server/v2/cometbft/abci_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/v2/cometbft/abci_test.go b/server/v2/cometbft/abci_test.go index 0a4f1b16f975..991611ccfc62 100644 --- a/server/v2/cometbft/abci_test.go +++ b/server/v2/cometbft/abci_test.go @@ -686,8 +686,8 @@ func setUpConsensus(t *testing.T, gasLimit uint64, mempool mempool.Mempool[mock. ValidateTxGasLimit: gasLimit, QueryGasLimit: gasLimit, SimulationGasLimit: gasLimit, - InitGenesis: func(ctx context.Context, src io.Reader, txHandler func(json.RawMessage) error) error { - return nil + InitGenesis: func(ctx context.Context, src io.Reader, txHandler func(json.RawMessage) error) (store.WriterMap, error) { + return nil, nil }, } From ea930ac0020410431b3e92f7cd8a7c8f1bfc76f8 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 16 Sep 2024 12:33:21 -0500 Subject: [PATCH 36/57] fix test --- server/v2/cometbft/abci_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/v2/cometbft/abci_test.go b/server/v2/cometbft/abci_test.go index 991611ccfc62..79892729da5e 100644 --- a/server/v2/cometbft/abci_test.go +++ b/server/v2/cometbft/abci_test.go @@ -687,7 +687,9 @@ func setUpConsensus(t *testing.T, gasLimit uint64, mempool mempool.Mempool[mock. QueryGasLimit: gasLimit, SimulationGasLimit: gasLimit, InitGenesis: func(ctx context.Context, src io.Reader, txHandler func(json.RawMessage) error) (store.WriterMap, error) { - return nil, nil + _, st, err := mockStore.StateLatest() + require.NoError(t, err) + return branch.DefaultNewWriterMap(st), nil }, } From 8b9b66c8a671cb7c52c6287b641daaa27f8ccbf6 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 16 Sep 2024 13:20:03 -0500 Subject: [PATCH 37/57] fix merge badness --- runtime/v2/builder.go | 2 +- runtime/v2/genesis.go | 114 ------------------------------------------ runtime/v2/module.go | 8 ++- runtime/v2/store.go | 5 +- 4 files changed, 5 insertions(+), 124 deletions(-) delete mode 100644 runtime/v2/genesis.go diff --git a/runtime/v2/builder.go b/runtime/v2/builder.go index 92ff49bcf046..03e38c648c4e 100644 --- a/runtime/v2/builder.go +++ b/runtime/v2/builder.go @@ -154,7 +154,7 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { if v != 0 { // TODO: genesis state may be > 0, we need to set version on store return nil, errors.New("cannot init genesis on non-zero state") } - genesisCtx := makeGenesisContext(a.branch(zeroState)) + genesisCtx := services.NewGenesisContext(a.branch(zeroState)) genesisState, err := genesisCtx.Run(ctx, func(ctx context.Context) error { err = a.app.moduleManager.InitGenesisJSON(ctx, genesisJSON, txHandler) if err != nil { diff --git a/runtime/v2/genesis.go b/runtime/v2/genesis.go deleted file mode 100644 index 0dea54c97790..000000000000 --- a/runtime/v2/genesis.go +++ /dev/null @@ -1,114 +0,0 @@ -package runtime - -import ( - "context" - "fmt" - - "cosmossdk.io/core/header" - "cosmossdk.io/core/store" -) - -var _ store.KVStoreService = (*GenesisKVStoreServie)(nil) - -type genesisContextKeyType struct{} - -var genesisContextKey = genesisContextKeyType{} - -type genesisContext struct { - state store.WriterMap - didRun bool -} - -func makeGenesisContext(state store.WriterMap) genesisContext { - return genesisContext{ - state: state, - } -} - -func (g *genesisContext) Run( - ctx context.Context, - fn func(ctx context.Context) error, -) (store.WriterMap, error) { - ctx = context.WithValue(ctx, genesisContextKey, g) - err := fn(ctx) - if err != nil { - return nil, err - } - g.didRun = true - return g.state, nil -} - -type GenesisKVStoreServie struct { - genesisCapable bool - actor []byte - execution store.KVStoreService -} - -func NewGenesisKVService( - actor []byte, - execution store.KVStoreService, -) *GenesisKVStoreServie { - return &GenesisKVStoreServie{ - genesisCapable: true, - actor: actor, - execution: execution, - } -} - -// OpenKVStore implements store.KVStoreService. -func (g *GenesisKVStoreServie) OpenKVStore(ctx context.Context) store.KVStore { - if !g.genesisCapable { - return g.execution.OpenKVStore(ctx) - } - v := ctx.Value(genesisContextKey) - if v == nil { - return g.execution.OpenKVStore(ctx) - } - genCtx, ok := v.(*genesisContext) - if !ok { - panic(fmt.Errorf("unexpected genesis context type: %T", v)) - } - if genCtx.didRun { - g.genesisCapable = false - return g.execution.OpenKVStore(ctx) - } - state, err := genCtx.state.GetWriter(g.actor) - if err != nil { - panic(err) - } - return state -} - -type GenesisHeaderService struct { - genesisCapable bool - executionService header.Service -} - -// HeaderInfo implements header.Service. -func (g *GenesisHeaderService) HeaderInfo(ctx context.Context) header.Info { - if !g.genesisCapable { - return g.executionService.HeaderInfo(ctx) - } - v := ctx.Value(genesisContextKey) - if v == nil { - return g.executionService.HeaderInfo(ctx) - } - genCtx, ok := v.(*genesisContext) - if !ok { - panic(fmt.Errorf("unexpected genesis context type: %T", v)) - } - if genCtx.didRun { - g.genesisCapable = false - return g.executionService.HeaderInfo(ctx) - } - return header.Info{} -} - -func NewGenesisHeaderService(executionService header.Service) *GenesisHeaderService { - return &GenesisHeaderService{ - genesisCapable: true, - executionService: executionService, - } -} - -var _ header.Service = (*GenesisHeaderService)(nil) diff --git a/runtime/v2/module.go b/runtime/v2/module.go index d81a246f988f..2eee11485234 100644 --- a/runtime/v2/module.go +++ b/runtime/v2/module.go @@ -5,10 +5,6 @@ import ( "os" "slices" - "cosmossdk.io/core/comet" - "cosmossdk.io/core/header" - rootstore "cosmossdk.io/store/v2/root" - "github.com/cosmos/gogoproto/proto" "google.golang.org/grpc" "google.golang.org/protobuf/reflect/protodesc" @@ -19,6 +15,7 @@ import ( autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" appmodulev2 "cosmossdk.io/core/appmodule/v2" + "cosmossdk.io/core/comet" "cosmossdk.io/core/header" "cosmossdk.io/core/registry" "cosmossdk.io/core/server" @@ -29,6 +26,7 @@ import ( "cosmossdk.io/log" "cosmossdk.io/runtime/v2/services" "cosmossdk.io/server/v2/stf" + rootstore "cosmossdk.io/store/v2/root" ) var ( @@ -223,7 +221,7 @@ func ProvideEnvironment[T transaction.Tx]( memStoreKey := fmt.Sprintf("memory:%s", key.Name()) registerStoreKey(appBuilder, memStoreKey) - memKvService = memFactory([]byte(memStoreKey)) + memKvService = stf.NewMemoryStoreService([]byte(memStoreKey)) } env := appmodulev2.Environment{ diff --git a/runtime/v2/store.go b/runtime/v2/store.go index 01ca8711e5f0..b2c239a38975 100644 --- a/runtime/v2/store.go +++ b/runtime/v2/store.go @@ -1,13 +1,10 @@ package runtime import ( - "fmt" - - "cosmossdk.io/core/server" - "fmt" "path/filepath" + "cosmossdk.io/core/server" "cosmossdk.io/core/store" "cosmossdk.io/log" "cosmossdk.io/server/v2/stf" From b6d6f75ca8a9c9611fc57509f6e90302ed9bc152 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Fri, 20 Sep 2024 12:32:11 -0500 Subject: [PATCH 38/57] kinda working --- runtime/v2/module.go | 6 +- tests/integration/bank/app_test.go | 7 ++- tests/integration/v2/app_helpers.go | 90 +++++++++++++++++++++-------- 3 files changed, 75 insertions(+), 28 deletions(-) diff --git a/runtime/v2/module.go b/runtime/v2/module.go index 975dc94f9055..a8fb394419fc 100644 --- a/runtime/v2/module.go +++ b/runtime/v2/module.go @@ -16,6 +16,7 @@ import ( reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" appmodulev2 "cosmossdk.io/core/appmodule/v2" "cosmossdk.io/core/comet" + "cosmossdk.io/core/event" "cosmossdk.io/core/header" "cosmossdk.io/core/registry" "cosmossdk.io/core/server" @@ -196,6 +197,7 @@ func ProvideEnvironment[T transaction.Tx]( appBuilder *AppBuilder[T], kvFactory store.KVStoreServiceFactory, headerService header.Service, + eventService event.Service, ) ( appmodulev2.Environment, store.KVStoreService, @@ -227,7 +229,7 @@ func ProvideEnvironment[T transaction.Tx]( env := appmodulev2.Environment{ Logger: logger, BranchService: stf.BranchService{}, - EventService: stf.NewEventService(), + EventService: eventService, GasService: stf.NewGasMeterService(), HeaderService: headerService, QueryRouterService: stf.NewQueryRouterService(), @@ -272,10 +274,12 @@ func DefaultServiceBindings() depinject.Config { } headerService header.Service = services.NewGenesisHeaderService(stf.HeaderService{}) cometService comet.Service = &services.ContextAwareCometInfoService{} + eventService = stf.NewEventService() ) return depinject.Supply( kvServiceFactory, headerService, cometService, + eventService, ) } diff --git a/tests/integration/bank/app_test.go b/tests/integration/bank/app_test.go index d657e10f8d05..6227065db675 100644 --- a/tests/integration/bank/app_test.go +++ b/tests/integration/bank/app_test.go @@ -103,7 +103,7 @@ func createTestSuite(t *testing.T, genesisAccounts []authtypes.GenesisAccount) s configurator.AuthModule(), configurator.StakingModule(), configurator.TxModule(), - configurator.ValidationModule(), + configurator.ValidateModule(), configurator.ConsensusModule(), configurator.BankModule(), configurator.GovModule(), @@ -193,7 +193,10 @@ func TestSendNotEnoughBalance_v2(t *testing.T) { s := createTestSuite(t, genAccs) ctx := context.Background() - _, err := s.AppV2.Exec(ctx, func(ctx context.Context) error { + _, state, err := s.AppV2.Store.StateLatest() + require.NoError(t, err) + + _, err = s.AppV2.Run(ctx, state, func(ctx context.Context) error { return testutil.FundAccount( ctx, s.BankKeeper, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67))) diff --git a/tests/integration/v2/app_helpers.go b/tests/integration/v2/app_helpers.go index be19cc26aba3..c1ba03898d3b 100644 --- a/tests/integration/v2/app_helpers.go +++ b/tests/integration/v2/app_helpers.go @@ -3,20 +3,24 @@ package integration import ( "context" - "cosmossdk.io/core/comet" "crypto/sha256" "encoding/json" "errors" "fmt" "time" + "cosmossdk.io/core/comet" corecontext "cosmossdk.io/core/context" + "cosmossdk.io/core/event" "cosmossdk.io/core/server" corestore "cosmossdk.io/core/store" "cosmossdk.io/core/transaction" "cosmossdk.io/depinject" sdkmath "cosmossdk.io/math" "cosmossdk.io/runtime/v2" + "cosmossdk.io/runtime/v2/services" + "cosmossdk.io/server/v2/stf" + "cosmossdk.io/server/v2/stf/branch" banktypes "cosmossdk.io/x/bank/types" consensustypes "cosmossdk.io/x/consensus/types" stakingtypes "cosmossdk.io/x/staking/types" @@ -189,10 +193,7 @@ func SetupWithConfiguration( txConfigOptions tx.ConfigOptions cometService comet.Service = &cometServiceImpl{} kvFactory corestore.KVStoreServiceFactory = func(actor []byte) corestore.KVStoreService { - return &storeService{actor} - } - memFactory corestore.MemoryStoreServiceFactory = func(actor []byte) corestore.MemoryStoreService { - return &storeService{actor} + return services.NewGenesisKVService(actor, &storeService{actor, stf.NewKVStoreService(actor)}) } cdc codec.Codec err error @@ -203,10 +204,11 @@ func SetupWithConfiguration( appConfig, codec.DefaultProviders, depinject.Supply( + services.NewGenesisHeaderService(stf.HeaderService{}), &dynamicConfigImpl{startupConfig.HomeDir}, cometService, kvFactory, - memFactory, + &eventService{}, ), depinject.Invoke( std.RegisterInterfaces, @@ -245,7 +247,7 @@ func SetupWithConfiguration( ) } - genesisState, err := genesisStateWithValSet( + genesisJSON, err := genesisStateWithValSet( cdc, app.DefaultGenesis(), valSet, @@ -256,7 +258,7 @@ func SetupWithConfiguration( } // init chain must be called to stop deliverState from being nil - stateBytes, err := cmtjson.MarshalIndent(genesisState, "", " ") + genesisJSONBytes, err := cmtjson.MarshalIndent(genesisJSON, "", " ") if err != nil { return nil, fmt.Errorf( "failed to marshal default genesis state: %w", @@ -278,8 +280,18 @@ func SetupWithConfiguration( }, ) + store := storeBuilder.Get() + if store == nil { + return nil, fmt.Errorf("failed to build store: %w", err) + } + err = store.SetInitialVersion(1) + if err != nil { + return nil, fmt.Errorf("failed to set initial version: %w", err) + } + integrationApp := &App{App: app, Store: store} + emptyHash := sha256.Sum256(nil) - _, state, err := app.InitGenesis( + _, genesisState, err := app.InitGenesis( ctx, &server.BlockRequest[stateMachineTx]{ Height: 1, @@ -289,22 +301,14 @@ func SetupWithConfiguration( AppHash: emptyHash[:], IsGenesis: true, }, - stateBytes, + genesisJSONBytes, &genericTxDecoder{txConfigOptions}, ) if err != nil { - return nil, fmt.Errorf("failed to init genesis: %w", err) + return nil, fmt.Errorf("failed init genesiss: %w", err) } - store := storeBuilder.Get() - if store == nil { - return nil, fmt.Errorf("failed to build store: %w", err) - } - err = store.SetInitialVersion(1) - if err != nil { - return nil, fmt.Errorf("failed to set initial version: %w", err) - } - genesisChanges, err := state.GetStateChanges() + genesisChanges, err := genesisState.GetStateChanges() if err != nil { return nil, fmt.Errorf("failed to get genesis state changes: %w", err) } @@ -314,7 +318,7 @@ func SetupWithConfiguration( return nil, fmt.Errorf("failed to commit initial version: %w", err) } - return &App{App: app, Store: store}, nil + return integrationApp, nil } // genesisStateWithValSet returns a new genesis state with the validator set @@ -461,7 +465,8 @@ type App struct { } type storeService struct { - actor []byte + actor []byte + executionService corestore.KVStoreService } type contextKeyType struct{} @@ -475,7 +480,7 @@ type integrationContext struct { func (s storeService) OpenKVStore(ctx context.Context) corestore.KVStore { iCtx, ok := ctx.Value(contextKey).(integrationContext) if !ok { - panic("failed to get integration context") + return s.executionService.OpenKVStore(ctx) } state, err := iCtx.state.GetWriter(s.actor) @@ -485,6 +490,41 @@ func (s storeService) OpenKVStore(ctx context.Context) corestore.KVStore { return state } -func (s storeService) OpenMemoryStore(ctx context.Context) corestore.KVStore { - return s.OpenKVStore(ctx) +var ( + _ event.Service = &eventService{} + _ event.Manager = &eventManager{} +) + +type eventService struct{} + +// EventManager implements event.Service. +func (e *eventService) EventManager(context.Context) event.Manager { + return &eventManager{} +} + +type eventManager struct{} + +// Emit implements event.Manager. +func (e *eventManager) Emit(event transaction.Msg) error { + return nil +} + +// EmitKV implements event.Manager. +func (e *eventManager) EmitKV(eventType string, attrs ...event.Attribute) error { + return nil +} + +func (a *App) Run( + ctx context.Context, + state corestore.ReaderMap, + fn func(ctx context.Context) error, +) (corestore.ReaderMap, error) { + nextState := branch.DefaultNewWriterMap(state) + iCtx := integrationContext{state: nextState} + ctx = context.WithValue(ctx, contextKey, iCtx) + err := fn(ctx) + if err != nil { + return nil, err + } + return nextState, nil } From d8fc366bbaa8eb3d171b4c9ef360332502176672 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 23 Sep 2024 12:40:24 -0500 Subject: [PATCH 39/57] passin with lots of debug printlns --- collections/map.go | 5 +- store/cachekv/store.go | 7 ++- store/cachemulti/store.go | 3 +- tests/integration/bank/app_test.go | 95 ++++++++++++++++++++--------- tests/integration/v2/app_helpers.go | 9 +++ 5 files changed, 88 insertions(+), 31 deletions(-) diff --git a/collections/map.go b/collections/map.go index 360d96feafa3..d04d23d18108 100644 --- a/collections/map.go +++ b/collections/map.go @@ -87,6 +87,7 @@ func (m Map[K, V]) Get(ctx context.Context, key K) (v V, err error) { if err != nil { return v, err } + fmt.Printf("collectiosn/map bytesKey=%x value=%x\n", bytesKey, valueBytes) if valueBytes == nil { return v, fmt.Errorf("%w: key '%s' of type %s", ErrNotFound, m.kc.Stringify(key), m.vc.ValueType()) } @@ -131,7 +132,9 @@ func (m Map[K, V]) Iterate(ctx context.Context, ranger Ranger[K]) (Iterator[K, V // walk function with the decoded key and value. If the callback function // returns true then the walking is stopped. // A nil ranger equals to walking over the entire key and value set. -func (m Map[K, V]) Walk(ctx context.Context, ranger Ranger[K], walkFunc func(key K, value V) (stop bool, err error)) error { +func (m Map[K, V]) Walk( + ctx context.Context, ranger Ranger[K], walkFunc func(key K, value V) (stop bool, err error), +) error { iter, err := m.Iterate(ctx, ranger) if err != nil { return err diff --git a/store/cachekv/store.go b/store/cachekv/store.go index 3509cef6aee3..40478e4a4979 100644 --- a/store/cachekv/store.go +++ b/store/cachekv/store.go @@ -2,6 +2,7 @@ package cachekv import ( "bytes" + "fmt" "io" "sort" "sync" @@ -153,8 +154,10 @@ func (store *Store) Write() { // save the byteslice, then we can assume only a read-only copy is sufficient. if obj.val.value != nil { // It already exists in the parent, hence update it. + fmt.Printf("cachekv/Write() key=%x value=%x rm=%t\n", obj.key, obj.val.value, false) store.parent.Set([]byte(obj.key), obj.val.value) } else { + fmt.Printf("cachekv/Write() key=%x value=%x rm=%t\n", obj.key, obj.val.value, true) store.parent.Delete([]byte(obj.key)) } } @@ -366,7 +369,9 @@ func (store *Store) dirtyItems(start, end []byte) { store.clearUnsortedCacheSubset(kvL, stateAlreadySorted) } -func (store *Store) clearUnsortedCacheSubset(unsorted []*kv.Pair, sortState sortState) { //nolint:staticcheck // We are in store v1. +func (store *Store) clearUnsortedCacheSubset( + unsorted []*kv.Pair, sortState sortState, +) { //nolint:staticcheck // We are in store v1. n := len(store.unsortedCache) if len(unsorted) == n { // This pattern allows the Go compiler to emit the map clearing idiom for the entire map. for key := range store.unsortedCache { diff --git a/store/cachemulti/store.go b/store/cachemulti/store.go index 42742f566ed9..7e9be34ff191 100644 --- a/store/cachemulti/store.go +++ b/store/cachemulti/store.go @@ -121,7 +121,8 @@ func (cms Store) GetStoreType() types.StoreType { // Write calls Write on each underlying store. func (cms Store) Write() { cms.db.Write() - for _, store := range cms.stores { + for k, store := range cms.stores { + fmt.Printf("store/Write() %s\n", k.Name()) store.Write() } } diff --git a/tests/integration/bank/app_test.go b/tests/integration/bank/app_test.go index 6227065db675..80659541d2dc 100644 --- a/tests/integration/bank/app_test.go +++ b/tests/integration/bank/app_test.go @@ -2,16 +2,18 @@ package bank_test import ( "context" + "encoding/hex" + "errors" + "fmt" "testing" - "cosmossdk.io/core/server" - abci "github.com/cometbft/cometbft/api/cometbft/abci/v1" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + secp256k1_internal "gitlab.com/yawning/secp256k1-voi" + "gitlab.com/yawning/secp256k1-voi/secec" "cosmossdk.io/core/header" - "cosmossdk.io/core/transaction" "cosmossdk.io/depinject" "cosmossdk.io/log" sdkmath "cosmossdk.io/math" @@ -63,7 +65,10 @@ type ( ) var ( - priv1 = secp256k1.GenPrivKey() + stablePrivateKey, _ = secec.NewPrivateKeyFromScalar(secp256k1_internal.NewScalarFromUint64(100)) + stablePriv1 = &secp256k1.PrivKey{Key: stablePrivateKey.Bytes()} + //priv1 = secp256k1.GenPrivKey() + priv1 = stablePriv1 addr1 = sdk.AccAddress(priv1.PubKey().Address()) priv2 = secp256k1.GenPrivKey() addr2 = sdk.AccAddress(priv2.PubKey().Address()) @@ -91,13 +96,6 @@ func createTestSuite(t *testing.T, genesisAccounts []authtypes.GenesisAccount) s t.Helper() res := suite{} - var genAccounts []simtestutil.GenesisAccount - for _, acc := range genesisAccounts { - genAccounts = append(genAccounts, simtestutil.GenesisAccount{GenesisAccount: acc}) - } - - startupCfg := simtestutil.DefaultStartUpConfig() - startupCfg.GenesisAccounts = genAccounts moduleConfigs := []configurator.ModuleOption{ configurator.AccountsModule(), configurator.AuthModule(), @@ -112,14 +110,25 @@ func createTestSuite(t *testing.T, genesisAccounts []authtypes.GenesisAccount) s } var err error if testAppV2 { - v2StartupCfg := integrationv2.DefaultStartUpConfig() - v2StartupCfg.HomeDir = t.TempDir() + startupCfg := integrationv2.DefaultStartUpConfig() + var genAccounts []integrationv2.GenesisAccount + for _, acc := range genesisAccounts { + genAccounts = append(genAccounts, integrationv2.GenesisAccount{GenesisAccount: acc}) + } + startupCfg.GenesisAccounts = genAccounts + startupCfg.HomeDir = t.TempDir() res.AppV2, err = integrationv2.SetupWithConfiguration( depinject.Configs(configurator.NewAppV2Config(moduleConfigs...), depinject.Supply(log.NewNopLogger())), - v2StartupCfg, + startupCfg, &res.BankKeeper, &res.AccountKeeper, &res.DistributionKeeper, &res.TxConfig) require.NoError(t, err) } else { + var genAccounts []simtestutil.GenesisAccount + for _, acc := range genesisAccounts { + genAccounts = append(genAccounts, simtestutil.GenesisAccount{GenesisAccount: acc}) + } + startupCfg := simtestutil.DefaultStartUpConfig() + startupCfg.GenesisAccounts = genAccounts res.App, err = simtestutil.SetupWithConfiguration( depinject.Configs(configurator.NewAppConfig(moduleConfigs...), depinject.Supply(log.NewNopLogger())), startupCfg, &res.BankKeeper, &res.AccountKeeper, &res.DistributionKeeper, &res.TxConfig) @@ -149,6 +158,8 @@ func TestSendNotEnoughBalance(t *testing.T) { s := createTestSuite(t, genAccs) baseApp := s.App.BaseApp ctx := baseApp.NewContext(false) + fmt.Printf("*** presence test\n") + require.NotNil(t, s.AccountKeeper.GetAccount(ctx, addr1)) require.NoError(t, testutil.FundAccount(ctx, s.BankKeeper, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67)))) _, err := baseApp.FinalizeBlock(&abci.FinalizeBlockRequest{Height: baseApp.LastBlockHeight() + 1}) @@ -193,31 +204,58 @@ func TestSendNotEnoughBalance_v2(t *testing.T) { s := createTestSuite(t, genAccs) ctx := context.Background() + randomAssert := func(actor, key, value string) error { + _, state, err := s.AppV2.Store.StateLatest() + if err != nil { + return err + } + rdr, err := state.GetReader([]byte(actor)) + if err != nil { + return err + } + k, err := hex.DecodeString(key) + if err != nil { + return err + } + v, err := rdr.Get(k) + if err != nil { + return err + } + if hex.EncodeToString(v) != value { + return errors.New("unexpected value") + } + return nil + } + _, state, err := s.AppV2.Store.StateLatest() + require.NoError(t, randomAssert("acc", + "6163636f756e744e756d6265720000000000000002", + "93354845030274cd4bf1686abd60ab28ec52e1a7")) require.NoError(t, err) - _, err = s.AppV2.Run(ctx, state, func(ctx context.Context) error { + nextState, err := s.AppV2.Run(ctx, state, func(ctx context.Context) error { + acc := s.AccountKeeper.GetAccount(ctx, addr1) + require.NotNil(t, acc) return testutil.FundAccount( ctx, s.BankKeeper, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67))) }) require.NoError(t, err) - _, _, err = s.AppV2.DeliverBlock(ctx, &server.BlockRequest[transaction.Tx]{ - Height: 2, // TODO how to auto-advance height with app v2 interface? - Hash: make([]byte, 32), - AppHash: make([]byte, 32), - }) + //_, _, err = s.AppV2.DeliverBlock(ctx, &server.BlockRequest[transaction.Tx]{ + // Height: 2, // TODO how to auto-advance height with app v2 interface? + // Hash: make([]byte, 32), + // AppHash: make([]byte, 32), + //}) require.NoError(t, err) - /* - _, err := baseApp.FinalizeBlock(&abci.FinalizeBlockRequest{Height: baseApp.LastBlockHeight() + 1}) - require.NoError(t, err) - _, err = baseApp.Commit() - require.NoError(t, err) - + nextState, err = s.AppV2.Run(ctx, nextState, func(ctx context.Context) error { res1 := s.AccountKeeper.GetAccount(ctx, addr1) require.NotNil(t, res1) require.Equal(t, acc, res1.(*authtypes.BaseAccount)) + return nil + }) + + /* origAccNum := res1.GetAccountNumber() origSeq := res1.GetSequence() @@ -226,9 +264,10 @@ func TestSendNotEnoughBalance_v2(t *testing.T) { addr2Str, err := s.AccountKeeper.AddressCodec().BytesToString(addr2) require.NoError(t, err) sendMsg := types.NewMsgSend(addr1Str, addr2Str, sdk.Coins{sdk.NewInt64Coin("foocoin", 100)}) - header := header.Info{Height: baseApp.LastBlockHeight() + 1} + hdr := header.Info{Height: 3} // TODO how to auto-advance height with app v2 interface? + txConfig := moduletestutil.MakeTestTxConfig(cdctestutil.CodecOptions{}) - _, _, err = simtestutil.SignCheckDeliver(t, txConfig, baseApp, header, []sdk.Msg{sendMsg}, "", []uint64{origAccNum}, []uint64{origSeq}, false, false, priv1) + _, _, err = simtestutil.SignCheckDeliver(t, txConfig, baseApp, hdr, []sdk.Msg{sendMsg}, "", []uint64{origAccNum}, []uint64{origSeq}, false, false, priv1) require.Error(t, err) checkBalance(t, baseApp, addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 67)}, s.BankKeeper) diff --git a/tests/integration/v2/app_helpers.go b/tests/integration/v2/app_helpers.go index c1ba03898d3b..969722071137 100644 --- a/tests/integration/v2/app_helpers.go +++ b/tests/integration/v2/app_helpers.go @@ -2,6 +2,7 @@ package integration import ( + "bytes" "context" "crypto/sha256" "encoding/json" @@ -313,6 +314,14 @@ func SetupWithConfiguration( return nil, fmt.Errorf("failed to get genesis state changes: %w", err) } cs := &corestore.Changeset{Changes: genesisChanges} + for _, change := range genesisChanges { + if !bytes.Equal(change.Actor, []byte("acc")) { + continue + } + for _, kv := range change.StateChanges { + fmt.Printf("actor: %s, key: %x, value: %x\n", change.Actor, kv.Key, kv.Value) + } + } _, err = store.Commit(cs) if err != nil { return nil, fmt.Errorf("failed to commit initial version: %w", err) From 00dd82aef465fcd9f75081eedb6a66f676dbb62e Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Tue, 24 Sep 2024 08:57:48 -0500 Subject: [PATCH 40/57] working integration test! --- collections/map.go | 1 - server/v2/stf/stf.go | 10 +- store/cachekv/store.go | 3 - store/cachemulti/store.go | 3 +- tests/integration/bank/app_test.go | 75 ++---- tests/integration/v2/app_helpers.go | 391 +++++++++------------------- tests/integration/v2/genesis.go | 176 +++++++++++++ tests/integration/v2/services.go | 99 +++++++ 8 files changed, 428 insertions(+), 330 deletions(-) create mode 100644 tests/integration/v2/genesis.go create mode 100644 tests/integration/v2/services.go diff --git a/collections/map.go b/collections/map.go index d04d23d18108..b9fcd93b4ac3 100644 --- a/collections/map.go +++ b/collections/map.go @@ -87,7 +87,6 @@ func (m Map[K, V]) Get(ctx context.Context, key K) (v V, err error) { if err != nil { return v, err } - fmt.Printf("collectiosn/map bytesKey=%x value=%x\n", bytesKey, valueBytes) if valueBytes == nil { return v, fmt.Errorf("%w: key '%s' of type %s", ErrNotFound, m.kc.Stringify(key), m.vc.ValueType()) } diff --git a/server/v2/stf/stf.go b/server/v2/stf/stf.go index 5a8d03f13701..b72e788caa62 100644 --- a/server/v2/stf/stf.go +++ b/server/v2/stf/stf.go @@ -204,13 +204,21 @@ func (s STF[T]) deliverTx( } execResp, execGas, execEvents, err := s.execTx(ctx, state, gasLimit-validateGas, tx, execMode, hi) - return server.TxResult{ + res := server.TxResult{ Events: append(validationEvents, execEvents...), GasUsed: execGas + validateGas, GasWanted: gasLimit, Resp: execResp, Error: err, } + // TODO + // we should be using cosmossdk.io/errors here, but that dependency brings in + // grpc, which we want to avoid. can the error matching code be pulled out? + // below is a temporary solution. + if err != nil { + res.Code = 1 + } + return res } // validateTx validates a transaction given the provided WritableState and gas limit. diff --git a/store/cachekv/store.go b/store/cachekv/store.go index 40478e4a4979..c0798455aba8 100644 --- a/store/cachekv/store.go +++ b/store/cachekv/store.go @@ -2,7 +2,6 @@ package cachekv import ( "bytes" - "fmt" "io" "sort" "sync" @@ -154,10 +153,8 @@ func (store *Store) Write() { // save the byteslice, then we can assume only a read-only copy is sufficient. if obj.val.value != nil { // It already exists in the parent, hence update it. - fmt.Printf("cachekv/Write() key=%x value=%x rm=%t\n", obj.key, obj.val.value, false) store.parent.Set([]byte(obj.key), obj.val.value) } else { - fmt.Printf("cachekv/Write() key=%x value=%x rm=%t\n", obj.key, obj.val.value, true) store.parent.Delete([]byte(obj.key)) } } diff --git a/store/cachemulti/store.go b/store/cachemulti/store.go index 7e9be34ff191..42742f566ed9 100644 --- a/store/cachemulti/store.go +++ b/store/cachemulti/store.go @@ -121,8 +121,7 @@ func (cms Store) GetStoreType() types.StoreType { // Write calls Write on each underlying store. func (cms Store) Write() { cms.db.Write() - for k, store := range cms.stores { - fmt.Printf("store/Write() %s\n", k.Name()) + for _, store := range cms.stores { store.Write() } } diff --git a/tests/integration/bank/app_test.go b/tests/integration/bank/app_test.go index 80659541d2dc..48aa35bd7de7 100644 --- a/tests/integration/bank/app_test.go +++ b/tests/integration/bank/app_test.go @@ -2,8 +2,6 @@ package bank_test import ( "context" - "encoding/hex" - "errors" "fmt" "testing" @@ -204,81 +202,42 @@ func TestSendNotEnoughBalance_v2(t *testing.T) { s := createTestSuite(t, genAccs) ctx := context.Background() - randomAssert := func(actor, key, value string) error { - _, state, err := s.AppV2.Store.StateLatest() - if err != nil { - return err - } - rdr, err := state.GetReader([]byte(actor)) - if err != nil { - return err - } - k, err := hex.DecodeString(key) - if err != nil { - return err - } - v, err := rdr.Get(k) - if err != nil { - return err - } - if hex.EncodeToString(v) != value { - return errors.New("unexpected value") - } - return nil - } - - _, state, err := s.AppV2.Store.StateLatest() - require.NoError(t, randomAssert("acc", - "6163636f756e744e756d6265720000000000000002", - "93354845030274cd4bf1686abd60ab28ec52e1a7")) - require.NoError(t, err) + _, state, storeErr := s.AppV2.Store.StateLatest() + require.NoError(t, storeErr) - nextState, err := s.AppV2.Run(ctx, state, func(ctx context.Context) error { - acc := s.AccountKeeper.GetAccount(ctx, addr1) - require.NotNil(t, acc) - return testutil.FundAccount( + _, err := s.AppV2.Run(ctx, state, func(ctx context.Context) error { + err := testutil.FundAccount( ctx, s.BankKeeper, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67))) - }) - require.NoError(t, err) - //_, _, err = s.AppV2.DeliverBlock(ctx, &server.BlockRequest[transaction.Tx]{ - // Height: 2, // TODO how to auto-advance height with app v2 interface? - // Hash: make([]byte, 32), - // AppHash: make([]byte, 32), - //}) - require.NoError(t, err) - nextState, err = s.AppV2.Run(ctx, nextState, func(ctx context.Context) error { + require.NoError(t, err) res1 := s.AccountKeeper.GetAccount(ctx, addr1) require.NotNil(t, res1) require.Equal(t, acc, res1.(*authtypes.BaseAccount)) - return nil - }) - - /* origAccNum := res1.GetAccountNumber() origSeq := res1.GetSequence() - addr1Str, err := s.AccountKeeper.AddressCodec().BytesToString(addr1) require.NoError(t, err) addr2Str, err := s.AccountKeeper.AddressCodec().BytesToString(addr2) require.NoError(t, err) sendMsg := types.NewMsgSend(addr1Str, addr2Str, sdk.Coins{sdk.NewInt64Coin("foocoin", 100)}) - hdr := header.Info{Height: 3} // TODO how to auto-advance height with app v2 interface? - - txConfig := moduletestutil.MakeTestTxConfig(cdctestutil.CodecOptions{}) - _, _, err = simtestutil.SignCheckDeliver(t, txConfig, baseApp, hdr, []sdk.Msg{sendMsg}, "", []uint64{origAccNum}, []uint64{origSeq}, false, false, priv1) - require.Error(t, err) - - checkBalance(t, baseApp, addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 67)}, s.BankKeeper) - ctx2 := baseApp.NewContext(true) - res2 := s.AccountKeeper.GetAccount(ctx2, addr1) + // TODO how to auto-advance height with app v2 interface? + s.AppV2.SignCheckDeliver( + t, ctx, 2, []sdk.Msg{sendMsg}, "", []uint64{origAccNum}, []uint64{origSeq}, + []cryptotypes.PrivKey{priv1}, + "spendable balance 67foocoin is smaller than 100foocoin", + ) + s.AppV2.CheckBalance(ctx, t, addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 67)}, s.BankKeeper) + res2 := s.AccountKeeper.GetAccount(ctx, addr1) require.NotNil(t, res2) require.Equal(t, origAccNum, res2.GetAccountNumber()) require.Equal(t, origSeq+1, res2.GetSequence()) - */ + + return nil + }) + require.NoError(t, err) } func TestMsgMultiSendWithAccounts(t *testing.T) { diff --git a/tests/integration/v2/app_helpers.go b/tests/integration/v2/app_helpers.go index 969722071137..226a547e8707 100644 --- a/tests/integration/v2/app_helpers.go +++ b/tests/integration/v2/app_helpers.go @@ -2,17 +2,22 @@ package integration import ( - "bytes" "context" "crypto/sha256" - "encoding/json" "errors" "fmt" + "github.com/cosmos/cosmos-sdk/client" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + authsign "github.com/cosmos/cosmos-sdk/x/auth/signing" + "github.com/stretchr/testify/require" + "math/rand" + "testing" "time" "cosmossdk.io/core/comet" corecontext "cosmossdk.io/core/context" - "cosmossdk.io/core/event" "cosmossdk.io/core/server" corestore "cosmossdk.io/core/store" "cosmossdk.io/core/transaction" @@ -22,19 +27,16 @@ import ( "cosmossdk.io/runtime/v2/services" "cosmossdk.io/server/v2/stf" "cosmossdk.io/server/v2/stf/branch" + bankkeeper "cosmossdk.io/x/bank/keeper" banktypes "cosmossdk.io/x/bank/types" consensustypes "cosmossdk.io/x/consensus/types" - stakingtypes "cosmossdk.io/x/staking/types" cmtproto "github.com/cometbft/cometbft/api/cometbft/types/v1" cmtjson "github.com/cometbft/cometbft/libs/json" cmttypes "github.com/cometbft/cometbft/types" "github.com/cosmos/cosmos-sdk/codec" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" "github.com/cosmos/cosmos-sdk/std" - "github.com/cosmos/cosmos-sdk/testutil/mock" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/tx" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -67,25 +69,6 @@ var DefaultConsensusParams = &cmtproto.ConsensusParams{ }, } -// CreateRandomValidatorSet creates a validator set with one random validator -func CreateRandomValidatorSet() (*cmttypes.ValidatorSet, error) { - privVal := mock.NewPV() - pubKey, err := privVal.GetPubKey() - if err != nil { - return nil, fmt.Errorf("failed to get pub key: %w", err) - } - - // create validator set with single validator - validator := cmttypes.NewValidator(pubKey, 1) - - return cmttypes.NewValidatorSet([]*cmttypes.Validator{validator}), nil -} - -type GenesisAccount struct { - authtypes.GenesisAccount - Coins sdk.Coins -} - // StartupConfig defines the startup configuration new a test application. // // ValidatorSet defines a custom validator set to be validating the app. @@ -143,41 +126,6 @@ func SetupAtGenesis( return SetupWithConfiguration(appConfig, cfg, extraOutputs...) } -var _ server.DynamicConfig = &dynamicConfigImpl{} - -type dynamicConfigImpl struct { - homeDir string -} - -func (d *dynamicConfigImpl) Get(key string) any { - return d.GetString(key) -} - -func (d *dynamicConfigImpl) GetString(key string) string { - switch key { - case runtime.FlagHome: - return d.homeDir - case "store.app-db-backend": - return "goleveldb" - case "server.minimum-gas-prices": - return "0stake" - default: - panic(fmt.Sprintf("unknown key: %s", key)) - } -} - -func (d *dynamicConfigImpl) UnmarshalSub(string, any) (bool, error) { - return false, nil -} - -var _ comet.Service = &cometServiceImpl{} - -type cometServiceImpl struct{} - -func (c cometServiceImpl) CometInfo(context.Context) comet.Info { - return comet.Info{} -} - // SetupWithConfiguration initializes a new runtime.App. A Nop logger is set in runtime.App. // appConfig defines the application configuration (f.e. app_config.go). // extraOutputs defines the extra outputs to be assigned by the dependency injector (depinject). @@ -191,6 +139,7 @@ func SetupWithConfiguration( app *runtime.App[stateMachineTx] appBuilder *runtime.AppBuilder[stateMachineTx] storeBuilder *runtime.StoreBuilder + txConfig client.TxConfig txConfigOptions tx.ConfigOptions cometService comet.Service = &cometServiceImpl{} kvFactory corestore.KVStoreServiceFactory = func(actor []byte) corestore.KVStoreService { @@ -215,7 +164,7 @@ func SetupWithConfiguration( std.RegisterInterfaces, ), ), - append(extraOutputs, &appBuilder, &cdc, &txConfigOptions, &storeBuilder)...); err != nil { + append(extraOutputs, &appBuilder, &cdc, &txConfigOptions, &txConfig, &storeBuilder)...); err != nil { return nil, fmt.Errorf("failed to inject dependencies: %w", err) } @@ -289,7 +238,7 @@ func SetupWithConfiguration( if err != nil { return nil, fmt.Errorf("failed to set initial version: %w", err) } - integrationApp := &App{App: app, Store: store} + integrationApp := &App{App: app, Store: store, txConfig: txConfig} emptyHash := sha256.Sum256(nil) _, genesisState, err := app.InitGenesis( @@ -303,26 +252,13 @@ func SetupWithConfiguration( IsGenesis: true, }, genesisJSONBytes, - &genericTxDecoder{txConfigOptions}, + &genesisTxCodec{txConfigOptions}, ) if err != nil { return nil, fmt.Errorf("failed init genesiss: %w", err) } - genesisChanges, err := genesisState.GetStateChanges() - if err != nil { - return nil, fmt.Errorf("failed to get genesis state changes: %w", err) - } - cs := &corestore.Changeset{Changes: genesisChanges} - for _, change := range genesisChanges { - if !bytes.Equal(change.Actor, []byte("acc")) { - continue - } - for _, kv := range change.StateChanges { - fmt.Printf("actor: %s, key: %x, value: %x\n", change.Actor, kv.Key, kv.Value) - } - } - _, err = store.Commit(cs) + _, err = integrationApp.Commit(genesisState) if err != nil { return nil, fmt.Errorf("failed to commit initial version: %w", err) } @@ -330,210 +266,135 @@ func SetupWithConfiguration( return integrationApp, nil } -// genesisStateWithValSet returns a new genesis state with the validator set -func genesisStateWithValSet( - codec codec.Codec, - genesisState map[string]json.RawMessage, - valSet *cmttypes.ValidatorSet, - genAccs []authtypes.GenesisAccount, - balances ...banktypes.Balance, -) (map[string]json.RawMessage, error) { - // set genesis accounts - authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs) - genesisState[authtypes.ModuleName] = codec.MustMarshalJSON(authGenesis) - - validators := make([]stakingtypes.Validator, 0, len(valSet.Validators)) - delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators)) - - bondAmt := sdk.DefaultPowerReduction - - for _, val := range valSet.Validators { - pk, err := cryptocodec.FromCmtPubKeyInterface(val.PubKey) - if err != nil { - return nil, fmt.Errorf("failed to convert pubkey: %w", err) - } - - pkAny, err := codectypes.NewAnyWithValue(pk) - if err != nil { - return nil, fmt.Errorf("failed to create new any: %w", err) - } - - validator := stakingtypes.Validator{ - OperatorAddress: sdk.ValAddress(val.Address).String(), - ConsensusPubkey: pkAny, - Jailed: false, - Status: stakingtypes.Bonded, - Tokens: bondAmt, - DelegatorShares: sdkmath.LegacyOneDec(), - Description: stakingtypes.Description{}, - UnbondingHeight: int64(0), - UnbondingTime: time.Unix(0, 0).UTC(), - Commission: stakingtypes.NewCommission( - sdkmath.LegacyZeroDec(), - sdkmath.LegacyZeroDec(), - sdkmath.LegacyZeroDec(), - ), - MinSelfDelegation: sdkmath.ZeroInt(), - } - validators = append(validators, validator) - delegations = append( - delegations, - stakingtypes.NewDelegation( - genAccs[0].GetAddress().String(), - sdk.ValAddress(val.Address).String(), - sdkmath.LegacyOneDec(), - ), - ) - - } - - // set validators and delegations - stakingGenesis := stakingtypes.NewGenesisState( - stakingtypes.DefaultParams(), - validators, - delegations, - ) - genesisState[stakingtypes.ModuleName] = codec.MustMarshalJSON( - stakingGenesis, - ) - - totalSupply := sdk.NewCoins() - for _, b := range balances { - // add genesis acc tokens to total supply - totalSupply = totalSupply.Add(b.Coins...) - } - - for range delegations { - // add delegated tokens to total supply - totalSupply = totalSupply.Add( - sdk.NewCoin(sdk.DefaultBondDenom, bondAmt), - ) - } - - // add bonded amount to bonded pool module account - balances = append(balances, banktypes.Balance{ - Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName). - String(), - Coins: sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, bondAmt)}, - }) - - // update total supply - bankGenesis := banktypes.NewGenesisState( - banktypes.DefaultGenesisState().Params, - balances, - totalSupply, - []banktypes.Metadata{}, - []banktypes.SendEnabled{}, - ) - genesisState[banktypes.ModuleName] = codec.MustMarshalJSON(bankGenesis) - - return genesisState, nil -} - -type genericTxDecoder struct { - tx.ConfigOptions +type App struct { + *runtime.App[stateMachineTx] + Store runtime.Store + txConfig client.TxConfig } -// Decode implements transaction.Codec. -func (t *genericTxDecoder) Decode(bz []byte) (stateMachineTx, error) { - var out stateMachineTx - tx, err := t.ProtoDecoder(bz) +func (a *App) Run( + ctx context.Context, + state corestore.ReaderMap, + fn func(ctx context.Context) error, +) (corestore.ReaderMap, error) { + nextState := branch.DefaultNewWriterMap(state) + iCtx := integrationContext{state: nextState} + ctx = context.WithValue(ctx, contextKey, iCtx) + err := fn(ctx) if err != nil { - return out, err - } - - var ok bool - out, ok = tx.(stateMachineTx) - if !ok { - return out, errors.New("unexpected Tx type") + return nil, err } - - return out, nil + return nextState, nil } -// DecodeJSON implements transaction.Codec. -func (t *genericTxDecoder) DecodeJSON(bz []byte) (stateMachineTx, error) { - var out stateMachineTx - tx, err := t.JSONDecoder(bz) +func (a *App) Commit(state corestore.WriterMap) ([]byte, error) { + changes, err := state.GetStateChanges() if err != nil { - return out, err + return nil, fmt.Errorf("failed to get state changes: %w", err) } - - var ok bool - out, ok = tx.(stateMachineTx) - if !ok { - return out, errors.New("unexpected Tx type") - } - - return out, nil -} - -type App struct { - *runtime.App[stateMachineTx] - Store runtime.Store -} - -type storeService struct { - actor []byte - executionService corestore.KVStoreService -} - -type contextKeyType struct{} - -var contextKey = contextKeyType{} - -type integrationContext struct { - state corestore.WriterMap + cs := &corestore.Changeset{Changes: changes} + //for _, change := range changes { + // if !bytes.Equal(change.Actor, []byte("acc")) { + // continue + // } + // for _, kv := range change.StateChanges { + // fmt.Printf("actor: %s, key: %x, value: %x\n", change.Actor, kv.Key, kv.Value) + // } + //} + return a.Store.Commit(cs) } -func (s storeService) OpenKVStore(ctx context.Context) corestore.KVStore { - iCtx, ok := ctx.Value(contextKey).(integrationContext) - if !ok { - return s.executionService.OpenKVStore(ctx) - } - - state, err := iCtx.state.GetWriter(s.actor) - if err != nil { - panic(err) +func (a *App) SignCheckDeliver( + t *testing.T, ctx context.Context, height uint64, msgs []sdk.Msg, + chainID string, accNums, accSeqs []uint64, privateKeys []cryptotypes.PrivKey, + txErrString string, +) server.TxResult { + t.Helper() + + r := rand.New(rand.NewSource(time.Now().UnixNano())) + sigs := make([]signing.SignatureV2, len(privateKeys)) + + // create a random length memo + memo := simulation.RandStringOfLength(r, simulation.RandIntBetween(r, 0, 100)) + + signMode, err := authsign.APISignModeToInternal(a.txConfig.SignModeHandler().DefaultMode()) + require.NoError(t, err) + + // 1st round: set SignatureV2 with empty signatures, to set correct + // signer infos. + for i, p := range privateKeys { + sigs[i] = signing.SignatureV2{ + PubKey: p.PubKey(), + Data: &signing.SingleSignatureData{ + SignMode: signMode, + }, + Sequence: accSeqs[i], + } } - return state -} -var ( - _ event.Service = &eventService{} - _ event.Manager = &eventManager{} -) + txBuilder := a.txConfig.NewTxBuilder() + err = txBuilder.SetMsgs(msgs...) + require.NoError(t, err) + err = txBuilder.SetSignatures(sigs...) + require.NoError(t, err) + txBuilder.SetMemo(memo) + txBuilder.SetFeeAmount(sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)}) + txBuilder.SetGasLimit(DefaultGenTxGas) + + // 2nd round: once all signer infos are set, every signer can sign. + for i, p := range privateKeys { + signerData := authsign.SignerData{ + Address: sdk.AccAddress(p.PubKey().Address()).String(), + ChainID: chainID, + AccountNumber: accNums[i], + Sequence: accSeqs[i], + PubKey: p.PubKey(), + } -type eventService struct{} + signBytes, err := authsign.GetSignBytesAdapter( + ctx, a.txConfig.SignModeHandler(), signMode, signerData, + // todo why fetch twice? + txBuilder.GetTx()) + require.NoError(t, err) + sig, err := p.Sign(signBytes) + require.NoError(t, err) + sigs[i].Data.(*signing.SingleSignatureData).Signature = sig + } + err = txBuilder.SetSignatures(sigs...) + require.NoError(t, err) -// EventManager implements event.Service. -func (e *eventService) EventManager(context.Context) event.Manager { - return &eventManager{} -} + builtTx := txBuilder.GetTx() + require.NoError(t, err) -type eventManager struct{} + blockResponse, blockState, err := a.DeliverBlock(ctx, &server.BlockRequest[stateMachineTx]{ + Height: height, + Txs: []stateMachineTx{builtTx}, + Hash: make([]byte, 32), + AppHash: make([]byte, 32), + }) + require.NoError(t, err) + + require.Equal(t, 1, len(blockResponse.TxResults)) + txResult := blockResponse.TxResults[0] + finalizeSuccess := txResult.Code == 0 + if txErrString != "" { + require.False(t, finalizeSuccess) + require.ErrorContains(t, txResult.Error, txErrString) + } else { + require.True(t, finalizeSuccess) + require.NoError(t, txResult.Error) + } -// Emit implements event.Manager. -func (e *eventManager) Emit(event transaction.Msg) error { - return nil -} + _, err = a.Commit(blockState) + require.NoError(t, err) -// EmitKV implements event.Manager. -func (e *eventManager) EmitKV(eventType string, attrs ...event.Attribute) error { - return nil + return txResult } -func (a *App) Run( - ctx context.Context, - state corestore.ReaderMap, - fn func(ctx context.Context) error, -) (corestore.ReaderMap, error) { - nextState := branch.DefaultNewWriterMap(state) - iCtx := integrationContext{state: nextState} - ctx = context.WithValue(ctx, contextKey, iCtx) - err := fn(ctx) - if err != nil { - return nil, err - } - return nextState, nil +func (a *App) CheckBalance( + ctx context.Context, t *testing.T, addr sdk.AccAddress, expected sdk.Coins, keeper bankkeeper.Keeper, +) { + t.Helper() + balances := keeper.GetAllBalances(ctx, addr) + require.Equal(t, expected, balances) } diff --git a/tests/integration/v2/genesis.go b/tests/integration/v2/genesis.go new file mode 100644 index 000000000000..c4c7f91aec49 --- /dev/null +++ b/tests/integration/v2/genesis.go @@ -0,0 +1,176 @@ +package integration + +import ( + sdkmath "cosmossdk.io/math" + banktypes "cosmossdk.io/x/bank/types" + stakingtypes "cosmossdk.io/x/staking/types" + "encoding/json" + "errors" + "fmt" + cmttypes "github.com/cometbft/cometbft/types" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + "github.com/cosmos/cosmos-sdk/testutil/mock" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/tx" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "time" +) + +// genesisStateWithValSet returns a new genesis state with the validator set +func genesisStateWithValSet( + codec codec.Codec, + genesisState map[string]json.RawMessage, + valSet *cmttypes.ValidatorSet, + genAccs []authtypes.GenesisAccount, + balances ...banktypes.Balance, +) (map[string]json.RawMessage, error) { + // set genesis accounts + authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs) + genesisState[authtypes.ModuleName] = codec.MustMarshalJSON(authGenesis) + + validators := make([]stakingtypes.Validator, 0, len(valSet.Validators)) + delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators)) + + bondAmt := sdk.DefaultPowerReduction + + for _, val := range valSet.Validators { + pk, err := cryptocodec.FromCmtPubKeyInterface(val.PubKey) + if err != nil { + return nil, fmt.Errorf("failed to convert pubkey: %w", err) + } + + pkAny, err := codectypes.NewAnyWithValue(pk) + if err != nil { + return nil, fmt.Errorf("failed to create new any: %w", err) + } + + validator := stakingtypes.Validator{ + OperatorAddress: sdk.ValAddress(val.Address).String(), + ConsensusPubkey: pkAny, + Jailed: false, + Status: stakingtypes.Bonded, + Tokens: bondAmt, + DelegatorShares: sdkmath.LegacyOneDec(), + Description: stakingtypes.Description{}, + UnbondingHeight: int64(0), + UnbondingTime: time.Unix(0, 0).UTC(), + Commission: stakingtypes.NewCommission( + sdkmath.LegacyZeroDec(), + sdkmath.LegacyZeroDec(), + sdkmath.LegacyZeroDec(), + ), + MinSelfDelegation: sdkmath.ZeroInt(), + } + validators = append(validators, validator) + delegations = append( + delegations, + stakingtypes.NewDelegation( + genAccs[0].GetAddress().String(), + sdk.ValAddress(val.Address).String(), + sdkmath.LegacyOneDec(), + ), + ) + + } + + // set validators and delegations + stakingGenesis := stakingtypes.NewGenesisState( + stakingtypes.DefaultParams(), + validators, + delegations, + ) + genesisState[stakingtypes.ModuleName] = codec.MustMarshalJSON( + stakingGenesis, + ) + + totalSupply := sdk.NewCoins() + for _, b := range balances { + // add genesis acc tokens to total supply + totalSupply = totalSupply.Add(b.Coins...) + } + + for range delegations { + // add delegated tokens to total supply + totalSupply = totalSupply.Add( + sdk.NewCoin(sdk.DefaultBondDenom, bondAmt), + ) + } + + // add bonded amount to bonded pool module account + balances = append(balances, banktypes.Balance{ + Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName). + String(), + Coins: sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, bondAmt)}, + }) + + // update total supply + bankGenesis := banktypes.NewGenesisState( + banktypes.DefaultGenesisState().Params, + balances, + totalSupply, + []banktypes.Metadata{}, + []banktypes.SendEnabled{}, + ) + genesisState[banktypes.ModuleName] = codec.MustMarshalJSON(bankGenesis) + + return genesisState, nil +} + +// CreateRandomValidatorSet creates a validator set with one random validator +func CreateRandomValidatorSet() (*cmttypes.ValidatorSet, error) { + privVal := mock.NewPV() + pubKey, err := privVal.GetPubKey() + if err != nil { + return nil, fmt.Errorf("failed to get pub key: %w", err) + } + + // create validator set with single validator + validator := cmttypes.NewValidator(pubKey, 1) + + return cmttypes.NewValidatorSet([]*cmttypes.Validator{validator}), nil +} + +type GenesisAccount struct { + authtypes.GenesisAccount + Coins sdk.Coins +} + +type genesisTxCodec struct { + tx.ConfigOptions +} + +// Decode implements transaction.Codec. +func (t *genesisTxCodec) Decode(bz []byte) (stateMachineTx, error) { + var out stateMachineTx + tx, err := t.ProtoDecoder(bz) + if err != nil { + return out, err + } + + var ok bool + out, ok = tx.(stateMachineTx) + if !ok { + return out, errors.New("unexpected Tx type") + } + + return out, nil +} + +// DecodeJSON implements transaction.Codec. +func (t *genesisTxCodec) DecodeJSON(bz []byte) (stateMachineTx, error) { + var out stateMachineTx + tx, err := t.JSONDecoder(bz) + if err != nil { + return out, err + } + + var ok bool + out, ok = tx.(stateMachineTx) + if !ok { + return out, errors.New("unexpected Tx type") + } + + return out, nil +} diff --git a/tests/integration/v2/services.go b/tests/integration/v2/services.go new file mode 100644 index 000000000000..64ccd21c2d2a --- /dev/null +++ b/tests/integration/v2/services.go @@ -0,0 +1,99 @@ +package integration + +import ( + "context" + "cosmossdk.io/core/comet" + "cosmossdk.io/core/event" + "cosmossdk.io/core/server" + corestore "cosmossdk.io/core/store" + "cosmossdk.io/core/transaction" + "cosmossdk.io/runtime/v2" + "fmt" +) + +func (c cometServiceImpl) CometInfo(context.Context) comet.Info { + return comet.Info{} +} + +// Services + +var _ server.DynamicConfig = &dynamicConfigImpl{} + +type dynamicConfigImpl struct { + homeDir string +} + +func (d *dynamicConfigImpl) Get(key string) any { + return d.GetString(key) +} + +func (d *dynamicConfigImpl) GetString(key string) string { + switch key { + case runtime.FlagHome: + return d.homeDir + case "store.app-db-backend": + return "goleveldb" + case "server.minimum-gas-prices": + return "0stake" + default: + panic(fmt.Sprintf("unknown key: %s", key)) + } +} + +func (d *dynamicConfigImpl) UnmarshalSub(string, any) (bool, error) { + return false, nil +} + +var _ comet.Service = &cometServiceImpl{} + +type cometServiceImpl struct{} + +type storeService struct { + actor []byte + executionService corestore.KVStoreService +} + +type contextKeyType struct{} + +var contextKey = contextKeyType{} + +type integrationContext struct { + state corestore.WriterMap +} + +func (s storeService) OpenKVStore(ctx context.Context) corestore.KVStore { + iCtx, ok := ctx.Value(contextKey).(integrationContext) + if !ok { + return s.executionService.OpenKVStore(ctx) + } + + state, err := iCtx.state.GetWriter(s.actor) + if err != nil { + panic(err) + } + return state +} + +var ( + _ event.Service = &eventService{} + _ event.Manager = &eventManager{} +) + +type eventService struct{} + +// EventManager implements event.Service. +func (e *eventService) EventManager(context.Context) event.Manager { + return &eventManager{} +} + +type eventManager struct{} + +// Emit implements event.Manager. +func (e *eventManager) Emit(event transaction.Msg) error { + return nil +} + +// EmitKV implements event.Manager. +func (e *eventManager) EmitKV(eventType string, attrs ...event.Attribute) error { + return nil +} From 710a1aae1dd0206c5e6ce5d7352081f559474b2b Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Tue, 24 Sep 2024 12:40:40 -0500 Subject: [PATCH 41/57] clean up --- tests/integration/bank/app_test.go | 133 ++------ tests/integration/v2-audit.md | 43 --- tests/integration/v2/app.go | 420 +++++++++++++++++++++++--- tests/integration/v2/app_helpers.go | 400 ------------------------ tests/integration/v2/bank/app_test.go | 134 ++++++++ 5 files changed, 546 insertions(+), 584 deletions(-) delete mode 100644 tests/integration/v2-audit.md delete mode 100644 tests/integration/v2/app_helpers.go create mode 100644 tests/integration/v2/bank/app_test.go diff --git a/tests/integration/bank/app_test.go b/tests/integration/bank/app_test.go index 48aa35bd7de7..bc6cbf6d8a5c 100644 --- a/tests/integration/bank/app_test.go +++ b/tests/integration/bank/app_test.go @@ -1,15 +1,11 @@ package bank_test import ( - "context" - "fmt" "testing" abci "github.com/cometbft/cometbft/api/cometbft/abci/v1" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - secp256k1_internal "gitlab.com/yawning/secp256k1-voi" - "gitlab.com/yawning/secp256k1-voi/secec" "cosmossdk.io/core/header" "cosmossdk.io/depinject" @@ -33,7 +29,6 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/runtime" - integrationv2 "github.com/cosmos/cosmos-sdk/tests/integration/v2" "github.com/cosmos/cosmos-sdk/testutil/configurator" simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" @@ -63,10 +58,7 @@ type ( ) var ( - stablePrivateKey, _ = secec.NewPrivateKeyFromScalar(secp256k1_internal.NewScalarFromUint64(100)) - stablePriv1 = &secp256k1.PrivKey{Key: stablePrivateKey.Bytes()} - //priv1 = secp256k1.GenPrivKey() - priv1 = stablePriv1 + priv1 = secp256k1.GenPrivKey() addr1 = sdk.AccAddress(priv1.PubKey().Address()) priv2 = secp256k1.GenPrivKey() addr2 = sdk.AccAddress(priv2.PubKey().Address()) @@ -83,63 +75,47 @@ type suite struct { AccountKeeper types.AccountKeeper DistributionKeeper distrkeeper.Keeper App *runtime.App - AppV2 *integrationv2.App TxConfig client.TxConfig } -// TODO move to param -var testAppV2 = false - func createTestSuite(t *testing.T, genesisAccounts []authtypes.GenesisAccount) suite { t.Helper() res := suite{} - moduleConfigs := []configurator.ModuleOption{ - configurator.AccountsModule(), - configurator.AuthModule(), - configurator.StakingModule(), - configurator.TxModule(), - configurator.ValidateModule(), - configurator.ConsensusModule(), - configurator.BankModule(), - configurator.GovModule(), - configurator.DistributionModule(), - configurator.ProtocolPoolModule(), - } - var err error - if testAppV2 { - startupCfg := integrationv2.DefaultStartUpConfig() - var genAccounts []integrationv2.GenesisAccount - for _, acc := range genesisAccounts { - genAccounts = append(genAccounts, integrationv2.GenesisAccount{GenesisAccount: acc}) - } - startupCfg.GenesisAccounts = genAccounts - startupCfg.HomeDir = t.TempDir() - res.AppV2, err = integrationv2.SetupWithConfiguration( - depinject.Configs(configurator.NewAppV2Config(moduleConfigs...), depinject.Supply(log.NewNopLogger())), - startupCfg, - &res.BankKeeper, &res.AccountKeeper, &res.DistributionKeeper, &res.TxConfig) - require.NoError(t, err) - } else { - var genAccounts []simtestutil.GenesisAccount - for _, acc := range genesisAccounts { - genAccounts = append(genAccounts, simtestutil.GenesisAccount{GenesisAccount: acc}) - } - startupCfg := simtestutil.DefaultStartUpConfig() - startupCfg.GenesisAccounts = genAccounts - res.App, err = simtestutil.SetupWithConfiguration( - depinject.Configs(configurator.NewAppConfig(moduleConfigs...), depinject.Supply(log.NewNopLogger())), - startupCfg, &res.BankKeeper, &res.AccountKeeper, &res.DistributionKeeper, &res.TxConfig) - require.NoError(t, err) + var genAccounts []simtestutil.GenesisAccount + for _, acc := range genesisAccounts { + genAccounts = append(genAccounts, simtestutil.GenesisAccount{GenesisAccount: acc}) } + startupCfg := simtestutil.DefaultStartUpConfig() + startupCfg.GenesisAccounts = genAccounts + + app, err := simtestutil.SetupWithConfiguration( + depinject.Configs( + configurator.NewAppConfig( + configurator.AccountsModule(), + configurator.AuthModule(), + configurator.StakingModule(), + configurator.TxModule(), + configurator.ValidateModule(), + configurator.ConsensusModule(), + configurator.BankModule(), + configurator.GovModule(), + configurator.DistributionModule(), + configurator.ProtocolPoolModule(), + ), + depinject.Supply(log.NewNopLogger()), + ), + startupCfg, &res.BankKeeper, &res.AccountKeeper, &res.DistributionKeeper, &res.TxConfig) + + res.App = app + + require.NoError(t, err) return res } // CheckBalance checks the balance of an account. -func checkBalance( - t *testing.T, baseApp *baseapp.BaseApp, addr sdk.AccAddress, balances sdk.Coins, keeper bankkeeper.Keeper, -) { +func checkBalance(t *testing.T, baseApp *baseapp.BaseApp, addr sdk.AccAddress, balances sdk.Coins, keeper bankkeeper.Keeper) { t.Helper() ctxCheck := baseApp.NewContext(true) keeperBalances := keeper.GetAllBalances(ctxCheck, addr) @@ -147,7 +123,6 @@ func checkBalance( } func TestSendNotEnoughBalance(t *testing.T) { - testAppV2 = false acc := &authtypes.BaseAccount{ Address: addr1.String(), } @@ -156,8 +131,6 @@ func TestSendNotEnoughBalance(t *testing.T) { s := createTestSuite(t, genAccs) baseApp := s.App.BaseApp ctx := baseApp.NewContext(false) - fmt.Printf("*** presence test\n") - require.NotNil(t, s.AccountKeeper.GetAccount(ctx, addr1)) require.NoError(t, testutil.FundAccount(ctx, s.BankKeeper, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67)))) _, err := baseApp.FinalizeBlock(&abci.FinalizeBlockRequest{Height: baseApp.LastBlockHeight() + 1}) @@ -192,54 +165,6 @@ func TestSendNotEnoughBalance(t *testing.T) { require.Equal(t, origSeq+1, res2.GetSequence()) } -func TestSendNotEnoughBalance_v2(t *testing.T) { - testAppV2 = true - acc := &authtypes.BaseAccount{ - Address: addr1.String(), - } - - genAccs := []authtypes.GenesisAccount{acc} - s := createTestSuite(t, genAccs) - ctx := context.Background() - - _, state, storeErr := s.AppV2.Store.StateLatest() - require.NoError(t, storeErr) - - _, err := s.AppV2.Run(ctx, state, func(ctx context.Context) error { - err := testutil.FundAccount( - ctx, s.BankKeeper, addr1, - sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67))) - require.NoError(t, err) - res1 := s.AccountKeeper.GetAccount(ctx, addr1) - require.NotNil(t, res1) - require.Equal(t, acc, res1.(*authtypes.BaseAccount)) - - origAccNum := res1.GetAccountNumber() - origSeq := res1.GetSequence() - addr1Str, err := s.AccountKeeper.AddressCodec().BytesToString(addr1) - require.NoError(t, err) - addr2Str, err := s.AccountKeeper.AddressCodec().BytesToString(addr2) - require.NoError(t, err) - sendMsg := types.NewMsgSend(addr1Str, addr2Str, sdk.Coins{sdk.NewInt64Coin("foocoin", 100)}) - - // TODO how to auto-advance height with app v2 interface? - s.AppV2.SignCheckDeliver( - t, ctx, 2, []sdk.Msg{sendMsg}, "", []uint64{origAccNum}, []uint64{origSeq}, - []cryptotypes.PrivKey{priv1}, - "spendable balance 67foocoin is smaller than 100foocoin", - ) - s.AppV2.CheckBalance(ctx, t, addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 67)}, s.BankKeeper) - res2 := s.AccountKeeper.GetAccount(ctx, addr1) - require.NotNil(t, res2) - - require.Equal(t, origAccNum, res2.GetAccountNumber()) - require.Equal(t, origSeq+1, res2.GetSequence()) - - return nil - }) - require.NoError(t, err) -} - func TestMsgMultiSendWithAccounts(t *testing.T) { addr1Str, err := cdctestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr1) require.NoError(t, err) diff --git a/tests/integration/v2-audit.md b/tests/integration/v2-audit.md deleted file mode 100644 index 6cfe9c89386d..000000000000 --- a/tests/integration/v2-audit.md +++ /dev/null @@ -1,43 +0,0 @@ -# server v2 integration tests - -## audit usages of [NewIntegrationApp](../../testutil/integration/router.go#L46) - - -* x/* - * create and register query and message servers - * call `App.QueryHelper` in setup, and may call in test - * make use of `sdk.Context`. a `context.Context` could be substituted except where otherwise noted -* [x/auth](./auth/keeper/msg_server_test.go#L122) - * calls `App.RunMsg` in test - * calls `sdk.Context` `GasMeter()` through [testdata.DeterministicIterations](../../testutil/testdata/grpc_query.go#L73) -* [x/bank](./bank/keeper/deterministic_test.go#L122) - * calls `sdk.Context` `GasMeter()` through [testdata.DeterministicIterations](../../testutil/testdata/grpc_query.go#L73) -* [x/distribution](./distribution/keeper/msg_server_test.go#L170) - * calls `App.RunMsg` in test - * calls `BaseApp.LastBlockHeight()`. delegates to store/v1 meta info store. - * calls `sdk.Context.CometInfo()`. can be replaced with `CometInfoService` -* [x/evidence](./evidence//keeper/infraction_test.go#L164) - * calls `BaseApp.StoreConsenusParams`, `BaseApp.GetConsensusParams` in test. - * mutates `sdk.Context` with `WithIsCheckTx`, `WithBlockHeight`, `WithHeaderInfo` - * calls `sdk.Context` `GetBlockHeight()` -* [x/gov](./gov/keeper/keeper_test.go#L150) -* x/slashing - * calls `App.RunMsg` in test - * calls `sdk.Context` `BlockHeight()` - * mutates `sdk.Context` with `WithBlockHeight`, `WithHeaderInfo` -* x/staking - * calls `sdk.Context` `GasMeter()` through [testdata.DeterministicIterations](../../testutil/testdata/grpc_query.go#L73) - -## poc notes - -testutil/integration can (and should) be moved to tests/integration. - -## differences from v1 - -- a v1 app calls commit only after cometbft has committed a block and calls the ABCI life cycle function Commit() -- a v2 app calls commit within FinalizeBlock. - -## simulations - -In addition to `NewIntegrationApp` many modules also make use of [testutil/sims.SetupWithConfiguration](../../testutil/sims/app_helpers.go#L145) to create a `runtime.App` for simulation testing. For example -[createTestSuite in bank](bank/app_test.go#L81) diff --git a/tests/integration/v2/app.go b/tests/integration/v2/app.go index 251280afb6b2..adefff6787cb 100644 --- a/tests/integration/v2/app.go +++ b/tests/integration/v2/app.go @@ -1,55 +1,401 @@ +// this file is a port of testutil/sims/app_helpers.go from v1 to v2 architecture package integration import ( + "context" + "crypto/sha256" + "errors" "fmt" + "math/rand" + "testing" + "time" - runtimev2 "cosmossdk.io/api/cosmos/app/runtime/v2" - "cosmossdk.io/core/address" - "cosmossdk.io/core/appmodule" + "github.com/cosmos/cosmos-sdk/client" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + authsign "github.com/cosmos/cosmos-sdk/x/auth/signing" + "github.com/stretchr/testify/require" + + "cosmossdk.io/core/comet" + corecontext "cosmossdk.io/core/context" + "cosmossdk.io/core/server" + corestore "cosmossdk.io/core/store" "cosmossdk.io/core/transaction" - "cosmossdk.io/log" + "cosmossdk.io/depinject" + sdkmath "cosmossdk.io/math" "cosmossdk.io/runtime/v2" + "cosmossdk.io/runtime/v2/services" + "cosmossdk.io/server/v2/stf" + "cosmossdk.io/server/v2/stf/branch" + bankkeeper "cosmossdk.io/x/bank/keeper" + banktypes "cosmossdk.io/x/bank/types" + consensustypes "cosmossdk.io/x/consensus/types" + cmtproto "github.com/cometbft/cometbft/api/cometbft/types/v1" + cmtjson "github.com/cometbft/cometbft/libs/json" + cmttypes "github.com/cometbft/cometbft/types" "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/std" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/tx" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) -func NewIntegrationApp( - logger log.Logger, - addressCodec address.Codec, - validatorCodec address.ValidatorAddressCodec, - modules map[string]appmodule.AppModule, -) { - interfaceRegistry, _, err := codec.ProvideInterfaceRegistry( - addressCodec, - validatorCodec, - nil, +const DefaultGenTxGas = 10000000 + +type stateMachineTx = transaction.Tx + +// DefaultConsensusParams defines the default CometBFT consensus params used in +// SimApp testing. +var DefaultConsensusParams = &cmtproto.ConsensusParams{ + Version: &cmtproto.VersionParams{ + App: 1, + }, + Block: &cmtproto.BlockParams{ + MaxBytes: 200000, + MaxGas: 100_000_000, + }, + Evidence: &cmtproto.EvidenceParams{ + MaxAgeNumBlocks: 302400, + MaxAgeDuration: 504 * time.Hour, // 3 weeks is the max duration + MaxBytes: 10000, + }, + Validator: &cmtproto.ValidatorParams{ + PubKeyTypes: []string{ + cmttypes.ABCIPubKeyTypeEd25519, + cmttypes.ABCIPubKeyTypeSecp256k1, + }, + }, +} + +// StartupConfig defines the startup configuration new a test application. +// +// ValidatorSet defines a custom validator set to be validating the app. +// BaseAppOption defines the additional operations that must be run on baseapp before app start. +// AtGenesis defines if the app started should already have produced block or not. +type StartupConfig struct { + ValidatorSet func() (*cmttypes.ValidatorSet, error) + AppOption runtime.AppBuilderOption[stateMachineTx] + AtGenesis bool + GenesisAccounts []GenesisAccount + HomeDir string +} + +func DefaultStartUpConfig() StartupConfig { + priv := secp256k1.GenPrivKey() + ba := authtypes.NewBaseAccount( + priv.PubKey().Address().Bytes(), + priv.PubKey(), + 0, + 0, ) + ga := GenesisAccount{ + ba, + sdk.NewCoins( + sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100000000000000)), + ), + } + return StartupConfig{ + ValidatorSet: CreateRandomValidatorSet, + AtGenesis: false, + GenesisAccounts: []GenesisAccount{ga}, + } +} + +// Setup initializes a new runtime.App and can inject values into extraOutputs. +// It uses SetupWithConfiguration under the hood. +func Setup( + appConfig depinject.Config, + extraOutputs ...interface{}, +) (*App, error) { + return SetupWithConfiguration( + appConfig, + DefaultStartUpConfig(), + extraOutputs...) +} + +// SetupAtGenesis initializes a new runtime.App at genesis and can inject values into extraOutputs. +// It uses SetupWithConfiguration under the hood. +func SetupAtGenesis( + appConfig depinject.Config, + extraOutputs ...interface{}, +) (*App, error) { + cfg := DefaultStartUpConfig() + cfg.AtGenesis = true + return SetupWithConfiguration(appConfig, cfg, extraOutputs...) +} + +// SetupWithConfiguration initializes a new runtime.App. A Nop logger is set in runtime.App. +// appConfig defines the application configuration (f.e. app_config.go). +// extraOutputs defines the extra outputs to be assigned by the dependency injector (depinject). +func SetupWithConfiguration( + appConfig depinject.Config, + startupConfig StartupConfig, + extraOutputs ...interface{}, +) (*App, error) { + // create the app with depinject + var ( + app *runtime.App[stateMachineTx] + appBuilder *runtime.AppBuilder[stateMachineTx] + storeBuilder *runtime.StoreBuilder + txConfig client.TxConfig + txConfigOptions tx.ConfigOptions + cometService comet.Service = &cometServiceImpl{} + kvFactory corestore.KVStoreServiceFactory = func(actor []byte) corestore.KVStoreService { + return services.NewGenesisKVService(actor, &storeService{actor, stf.NewKVStoreService(actor)}) + } + cdc codec.Codec + err error + ) + + if err := depinject.Inject( + depinject.Configs( + appConfig, + codec.DefaultProviders, + depinject.Supply( + services.NewGenesisHeaderService(stf.HeaderService{}), + &dynamicConfigImpl{startupConfig.HomeDir}, + cometService, + kvFactory, + &eventService{}, + ), + depinject.Invoke( + std.RegisterInterfaces, + ), + ), + append(extraOutputs, &appBuilder, &cdc, &txConfigOptions, &txConfig, &storeBuilder)...); err != nil { + return nil, fmt.Errorf("failed to inject dependencies: %w", err) + } + + app, err = appBuilder.Build() + if err != nil { + return nil, fmt.Errorf("failed to build app: %w", err) + } + if err := app.LoadLatest(); err != nil { + return nil, fmt.Errorf("failed to load app: %w", err) + } + + // create validator set + valSet, err := startupConfig.ValidatorSet() + if err != nil { + return nil, errors.New("failed to create validator set") + } + + var ( + balances []banktypes.Balance + genAccounts []authtypes.GenesisAccount + ) + for _, ga := range startupConfig.GenesisAccounts { + genAccounts = append(genAccounts, ga.GenesisAccount) + balances = append( + balances, + banktypes.Balance{ + Address: ga.GenesisAccount.GetAddress().String(), + Coins: ga.Coins, + }, + ) + } + + genesisJSON, err := genesisStateWithValSet( + cdc, + app.DefaultGenesis(), + valSet, + genAccounts, + balances...) + if err != nil { + return nil, fmt.Errorf("failed to create genesis state: %w", err) + } + + // init chain must be called to stop deliverState from being nil + genesisJSONBytes, err := cmtjson.MarshalIndent(genesisJSON, "", " ") if err != nil { - panic(err) + return nil, fmt.Errorf( + "failed to marshal default genesis state: %w", + err, + ) } - legacyAmino := codec.ProvideLegacyAmino() - appBuilder, routerBuilder, _, _, _ := runtime.ProvideAppBuilder[transaction.Tx]( - interfaceRegistry, - legacyAmino, + ctx := context.WithValue( + context.Background(), + corecontext.CometParamsInitInfoKey, + &consensustypes.MsgUpdateParams{ + Authority: "consensus", + Block: DefaultConsensusParams.Block, + Evidence: DefaultConsensusParams.Evidence, + Validator: DefaultConsensusParams.Validator, + Abci: DefaultConsensusParams.Abci, + Synchrony: DefaultConsensusParams.Synchrony, + Feature: DefaultConsensusParams.Feature, + }, ) - mm := runtime.NewModuleManager[transaction.Tx]( - logger, - &runtimev2.Module{}, - modules, + + store := storeBuilder.Get() + if store == nil { + return nil, fmt.Errorf("failed to build store: %w", err) + } + err = store.SetInitialVersion(1) + if err != nil { + return nil, fmt.Errorf("failed to set initial version: %w", err) + } + integrationApp := &App{App: app, Store: store, txConfig: txConfig} + + emptyHash := sha256.Sum256(nil) + _, genesisState, err := app.InitGenesis( + ctx, + &server.BlockRequest[stateMachineTx]{ + Height: 1, + Time: time.Now(), + Hash: emptyHash[:], + ChainId: "test-chain", + AppHash: emptyHash[:], + IsGenesis: true, + }, + genesisJSONBytes, + &genesisTxCodec{txConfigOptions}, ) - // appBuilder.RegisterModules(mm) - fmt.Printf("appBuilder: %v\nrouterBuilder: %v\nmodule manager: %v", - appBuilder, - routerBuilder, - mm) - app, err := appBuilder.Build() - if err != nil { - panic(err) - } - fmt.Printf("appBuilder: %v\nrouterBuilder: %v\nmodule manager: %v\napp: %v", - appBuilder, - routerBuilder, - mm, - app) + if err != nil { + return nil, fmt.Errorf("failed init genesiss: %w", err) + } + + _, err = integrationApp.Commit(genesisState) + if err != nil { + return nil, fmt.Errorf("failed to commit initial version: %w", err) + } + + return integrationApp, nil +} + +type App struct { + *runtime.App[stateMachineTx] + Store runtime.Store + txConfig client.TxConfig +} + +func (a *App) Run( + ctx context.Context, + state corestore.ReaderMap, + fn func(ctx context.Context) error, +) (corestore.ReaderMap, error) { + nextState := branch.DefaultNewWriterMap(state) + iCtx := integrationContext{state: nextState} + ctx = context.WithValue(ctx, contextKey, iCtx) + err := fn(ctx) + if err != nil { + return nil, err + } + return nextState, nil +} + +func (a *App) Commit(state corestore.WriterMap) ([]byte, error) { + changes, err := state.GetStateChanges() + if err != nil { + return nil, fmt.Errorf("failed to get state changes: %w", err) + } + cs := &corestore.Changeset{Changes: changes} + //for _, change := range changes { + // if !bytes.Equal(change.Actor, []byte("acc")) { + // continue + // } + // for _, kv := range change.StateChanges { + // fmt.Printf("actor: %s, key: %x, value: %x\n", change.Actor, kv.Key, kv.Value) + // } + //} + return a.Store.Commit(cs) +} + +func (a *App) SignCheckDeliver( + t *testing.T, ctx context.Context, height uint64, msgs []sdk.Msg, + chainID string, accNums, accSeqs []uint64, privateKeys []cryptotypes.PrivKey, + txErrString string, +) server.TxResult { + t.Helper() + + r := rand.New(rand.NewSource(time.Now().UnixNano())) + sigs := make([]signing.SignatureV2, len(privateKeys)) + + // create a random length memo + memo := simulation.RandStringOfLength(r, simulation.RandIntBetween(r, 0, 100)) + + signMode, err := authsign.APISignModeToInternal(a.txConfig.SignModeHandler().DefaultMode()) + require.NoError(t, err) + + // 1st round: set SignatureV2 with empty signatures, to set correct + // signer infos. + for i, p := range privateKeys { + sigs[i] = signing.SignatureV2{ + PubKey: p.PubKey(), + Data: &signing.SingleSignatureData{ + SignMode: signMode, + }, + Sequence: accSeqs[i], + } + } + + txBuilder := a.txConfig.NewTxBuilder() + err = txBuilder.SetMsgs(msgs...) + require.NoError(t, err) + err = txBuilder.SetSignatures(sigs...) + require.NoError(t, err) + txBuilder.SetMemo(memo) + txBuilder.SetFeeAmount(sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)}) + txBuilder.SetGasLimit(DefaultGenTxGas) + + // 2nd round: once all signer infos are set, every signer can sign. + for i, p := range privateKeys { + signerData := authsign.SignerData{ + Address: sdk.AccAddress(p.PubKey().Address()).String(), + ChainID: chainID, + AccountNumber: accNums[i], + Sequence: accSeqs[i], + PubKey: p.PubKey(), + } + + signBytes, err := authsign.GetSignBytesAdapter( + ctx, a.txConfig.SignModeHandler(), signMode, signerData, + // todo why fetch twice? + txBuilder.GetTx()) + require.NoError(t, err) + sig, err := p.Sign(signBytes) + require.NoError(t, err) + sigs[i].Data.(*signing.SingleSignatureData).Signature = sig + } + err = txBuilder.SetSignatures(sigs...) + require.NoError(t, err) + + builtTx := txBuilder.GetTx() + require.NoError(t, err) + + blockResponse, blockState, err := a.DeliverBlock(ctx, &server.BlockRequest[stateMachineTx]{ + Height: height, + Txs: []stateMachineTx{builtTx}, + Hash: make([]byte, 32), + AppHash: make([]byte, 32), + }) + require.NoError(t, err) + + require.Equal(t, 1, len(blockResponse.TxResults)) + txResult := blockResponse.TxResults[0] + finalizeSuccess := txResult.Code == 0 + if txErrString != "" { + require.False(t, finalizeSuccess) + require.ErrorContains(t, txResult.Error, txErrString) + } else { + require.True(t, finalizeSuccess) + require.NoError(t, txResult.Error) + } + + _, err = a.Commit(blockState) + require.NoError(t, err) + + return txResult +} + +func (a *App) CheckBalance( + ctx context.Context, t *testing.T, addr sdk.AccAddress, expected sdk.Coins, keeper bankkeeper.Keeper, +) { + t.Helper() + balances := keeper.GetAllBalances(ctx, addr) + require.Equal(t, expected, balances) } diff --git a/tests/integration/v2/app_helpers.go b/tests/integration/v2/app_helpers.go deleted file mode 100644 index 226a547e8707..000000000000 --- a/tests/integration/v2/app_helpers.go +++ /dev/null @@ -1,400 +0,0 @@ -// this file is a port of testutil/sims/app_helpers.go from v1 to v2 architecture -package integration - -import ( - "context" - "crypto/sha256" - "errors" - "fmt" - "github.com/cosmos/cosmos-sdk/client" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/types/tx/signing" - authsign "github.com/cosmos/cosmos-sdk/x/auth/signing" - "github.com/stretchr/testify/require" - "math/rand" - "testing" - "time" - - "cosmossdk.io/core/comet" - corecontext "cosmossdk.io/core/context" - "cosmossdk.io/core/server" - corestore "cosmossdk.io/core/store" - "cosmossdk.io/core/transaction" - "cosmossdk.io/depinject" - sdkmath "cosmossdk.io/math" - "cosmossdk.io/runtime/v2" - "cosmossdk.io/runtime/v2/services" - "cosmossdk.io/server/v2/stf" - "cosmossdk.io/server/v2/stf/branch" - bankkeeper "cosmossdk.io/x/bank/keeper" - banktypes "cosmossdk.io/x/bank/types" - consensustypes "cosmossdk.io/x/consensus/types" - cmtproto "github.com/cometbft/cometbft/api/cometbft/types/v1" - cmtjson "github.com/cometbft/cometbft/libs/json" - cmttypes "github.com/cometbft/cometbft/types" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - "github.com/cosmos/cosmos-sdk/std" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/tx" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" -) - -const DefaultGenTxGas = 10000000 - -type stateMachineTx = transaction.Tx - -// DefaultConsensusParams defines the default CometBFT consensus params used in -// SimApp testing. -var DefaultConsensusParams = &cmtproto.ConsensusParams{ - Version: &cmtproto.VersionParams{ - App: 1, - }, - Block: &cmtproto.BlockParams{ - MaxBytes: 200000, - MaxGas: 100_000_000, - }, - Evidence: &cmtproto.EvidenceParams{ - MaxAgeNumBlocks: 302400, - MaxAgeDuration: 504 * time.Hour, // 3 weeks is the max duration - MaxBytes: 10000, - }, - Validator: &cmtproto.ValidatorParams{ - PubKeyTypes: []string{ - cmttypes.ABCIPubKeyTypeEd25519, - cmttypes.ABCIPubKeyTypeSecp256k1, - }, - }, -} - -// StartupConfig defines the startup configuration new a test application. -// -// ValidatorSet defines a custom validator set to be validating the app. -// BaseAppOption defines the additional operations that must be run on baseapp before app start. -// AtGenesis defines if the app started should already have produced block or not. -type StartupConfig struct { - ValidatorSet func() (*cmttypes.ValidatorSet, error) - AppOption runtime.AppBuilderOption[stateMachineTx] - AtGenesis bool - GenesisAccounts []GenesisAccount - HomeDir string -} - -func DefaultStartUpConfig() StartupConfig { - priv := secp256k1.GenPrivKey() - ba := authtypes.NewBaseAccount( - priv.PubKey().Address().Bytes(), - priv.PubKey(), - 0, - 0, - ) - ga := GenesisAccount{ - ba, - sdk.NewCoins( - sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100000000000000)), - ), - } - return StartupConfig{ - ValidatorSet: CreateRandomValidatorSet, - AtGenesis: false, - GenesisAccounts: []GenesisAccount{ga}, - } -} - -// Setup initializes a new runtime.App and can inject values into extraOutputs. -// It uses SetupWithConfiguration under the hood. -func Setup( - appConfig depinject.Config, - extraOutputs ...interface{}, -) (*App, error) { - return SetupWithConfiguration( - appConfig, - DefaultStartUpConfig(), - extraOutputs...) -} - -// SetupAtGenesis initializes a new runtime.App at genesis and can inject values into extraOutputs. -// It uses SetupWithConfiguration under the hood. -func SetupAtGenesis( - appConfig depinject.Config, - extraOutputs ...interface{}, -) (*App, error) { - cfg := DefaultStartUpConfig() - cfg.AtGenesis = true - return SetupWithConfiguration(appConfig, cfg, extraOutputs...) -} - -// SetupWithConfiguration initializes a new runtime.App. A Nop logger is set in runtime.App. -// appConfig defines the application configuration (f.e. app_config.go). -// extraOutputs defines the extra outputs to be assigned by the dependency injector (depinject). -func SetupWithConfiguration( - appConfig depinject.Config, - startupConfig StartupConfig, - extraOutputs ...interface{}, -) (*App, error) { - // create the app with depinject - var ( - app *runtime.App[stateMachineTx] - appBuilder *runtime.AppBuilder[stateMachineTx] - storeBuilder *runtime.StoreBuilder - txConfig client.TxConfig - txConfigOptions tx.ConfigOptions - cometService comet.Service = &cometServiceImpl{} - kvFactory corestore.KVStoreServiceFactory = func(actor []byte) corestore.KVStoreService { - return services.NewGenesisKVService(actor, &storeService{actor, stf.NewKVStoreService(actor)}) - } - cdc codec.Codec - err error - ) - - if err := depinject.Inject( - depinject.Configs( - appConfig, - codec.DefaultProviders, - depinject.Supply( - services.NewGenesisHeaderService(stf.HeaderService{}), - &dynamicConfigImpl{startupConfig.HomeDir}, - cometService, - kvFactory, - &eventService{}, - ), - depinject.Invoke( - std.RegisterInterfaces, - ), - ), - append(extraOutputs, &appBuilder, &cdc, &txConfigOptions, &txConfig, &storeBuilder)...); err != nil { - return nil, fmt.Errorf("failed to inject dependencies: %w", err) - } - - app, err = appBuilder.Build() - if err != nil { - return nil, fmt.Errorf("failed to build app: %w", err) - } - if err := app.LoadLatest(); err != nil { - return nil, fmt.Errorf("failed to load app: %w", err) - } - - // create validator set - valSet, err := startupConfig.ValidatorSet() - if err != nil { - return nil, errors.New("failed to create validator set") - } - - var ( - balances []banktypes.Balance - genAccounts []authtypes.GenesisAccount - ) - for _, ga := range startupConfig.GenesisAccounts { - genAccounts = append(genAccounts, ga.GenesisAccount) - balances = append( - balances, - banktypes.Balance{ - Address: ga.GenesisAccount.GetAddress().String(), - Coins: ga.Coins, - }, - ) - } - - genesisJSON, err := genesisStateWithValSet( - cdc, - app.DefaultGenesis(), - valSet, - genAccounts, - balances...) - if err != nil { - return nil, fmt.Errorf("failed to create genesis state: %w", err) - } - - // init chain must be called to stop deliverState from being nil - genesisJSONBytes, err := cmtjson.MarshalIndent(genesisJSON, "", " ") - if err != nil { - return nil, fmt.Errorf( - "failed to marshal default genesis state: %w", - err, - ) - } - - ctx := context.WithValue( - context.Background(), - corecontext.CometParamsInitInfoKey, - &consensustypes.MsgUpdateParams{ - Authority: "consensus", - Block: DefaultConsensusParams.Block, - Evidence: DefaultConsensusParams.Evidence, - Validator: DefaultConsensusParams.Validator, - Abci: DefaultConsensusParams.Abci, - Synchrony: DefaultConsensusParams.Synchrony, - Feature: DefaultConsensusParams.Feature, - }, - ) - - store := storeBuilder.Get() - if store == nil { - return nil, fmt.Errorf("failed to build store: %w", err) - } - err = store.SetInitialVersion(1) - if err != nil { - return nil, fmt.Errorf("failed to set initial version: %w", err) - } - integrationApp := &App{App: app, Store: store, txConfig: txConfig} - - emptyHash := sha256.Sum256(nil) - _, genesisState, err := app.InitGenesis( - ctx, - &server.BlockRequest[stateMachineTx]{ - Height: 1, - Time: time.Now(), - Hash: emptyHash[:], - ChainId: "test-chain", - AppHash: emptyHash[:], - IsGenesis: true, - }, - genesisJSONBytes, - &genesisTxCodec{txConfigOptions}, - ) - if err != nil { - return nil, fmt.Errorf("failed init genesiss: %w", err) - } - - _, err = integrationApp.Commit(genesisState) - if err != nil { - return nil, fmt.Errorf("failed to commit initial version: %w", err) - } - - return integrationApp, nil -} - -type App struct { - *runtime.App[stateMachineTx] - Store runtime.Store - txConfig client.TxConfig -} - -func (a *App) Run( - ctx context.Context, - state corestore.ReaderMap, - fn func(ctx context.Context) error, -) (corestore.ReaderMap, error) { - nextState := branch.DefaultNewWriterMap(state) - iCtx := integrationContext{state: nextState} - ctx = context.WithValue(ctx, contextKey, iCtx) - err := fn(ctx) - if err != nil { - return nil, err - } - return nextState, nil -} - -func (a *App) Commit(state corestore.WriterMap) ([]byte, error) { - changes, err := state.GetStateChanges() - if err != nil { - return nil, fmt.Errorf("failed to get state changes: %w", err) - } - cs := &corestore.Changeset{Changes: changes} - //for _, change := range changes { - // if !bytes.Equal(change.Actor, []byte("acc")) { - // continue - // } - // for _, kv := range change.StateChanges { - // fmt.Printf("actor: %s, key: %x, value: %x\n", change.Actor, kv.Key, kv.Value) - // } - //} - return a.Store.Commit(cs) -} - -func (a *App) SignCheckDeliver( - t *testing.T, ctx context.Context, height uint64, msgs []sdk.Msg, - chainID string, accNums, accSeqs []uint64, privateKeys []cryptotypes.PrivKey, - txErrString string, -) server.TxResult { - t.Helper() - - r := rand.New(rand.NewSource(time.Now().UnixNano())) - sigs := make([]signing.SignatureV2, len(privateKeys)) - - // create a random length memo - memo := simulation.RandStringOfLength(r, simulation.RandIntBetween(r, 0, 100)) - - signMode, err := authsign.APISignModeToInternal(a.txConfig.SignModeHandler().DefaultMode()) - require.NoError(t, err) - - // 1st round: set SignatureV2 with empty signatures, to set correct - // signer infos. - for i, p := range privateKeys { - sigs[i] = signing.SignatureV2{ - PubKey: p.PubKey(), - Data: &signing.SingleSignatureData{ - SignMode: signMode, - }, - Sequence: accSeqs[i], - } - } - - txBuilder := a.txConfig.NewTxBuilder() - err = txBuilder.SetMsgs(msgs...) - require.NoError(t, err) - err = txBuilder.SetSignatures(sigs...) - require.NoError(t, err) - txBuilder.SetMemo(memo) - txBuilder.SetFeeAmount(sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)}) - txBuilder.SetGasLimit(DefaultGenTxGas) - - // 2nd round: once all signer infos are set, every signer can sign. - for i, p := range privateKeys { - signerData := authsign.SignerData{ - Address: sdk.AccAddress(p.PubKey().Address()).String(), - ChainID: chainID, - AccountNumber: accNums[i], - Sequence: accSeqs[i], - PubKey: p.PubKey(), - } - - signBytes, err := authsign.GetSignBytesAdapter( - ctx, a.txConfig.SignModeHandler(), signMode, signerData, - // todo why fetch twice? - txBuilder.GetTx()) - require.NoError(t, err) - sig, err := p.Sign(signBytes) - require.NoError(t, err) - sigs[i].Data.(*signing.SingleSignatureData).Signature = sig - } - err = txBuilder.SetSignatures(sigs...) - require.NoError(t, err) - - builtTx := txBuilder.GetTx() - require.NoError(t, err) - - blockResponse, blockState, err := a.DeliverBlock(ctx, &server.BlockRequest[stateMachineTx]{ - Height: height, - Txs: []stateMachineTx{builtTx}, - Hash: make([]byte, 32), - AppHash: make([]byte, 32), - }) - require.NoError(t, err) - - require.Equal(t, 1, len(blockResponse.TxResults)) - txResult := blockResponse.TxResults[0] - finalizeSuccess := txResult.Code == 0 - if txErrString != "" { - require.False(t, finalizeSuccess) - require.ErrorContains(t, txResult.Error, txErrString) - } else { - require.True(t, finalizeSuccess) - require.NoError(t, txResult.Error) - } - - _, err = a.Commit(blockState) - require.NoError(t, err) - - return txResult -} - -func (a *App) CheckBalance( - ctx context.Context, t *testing.T, addr sdk.AccAddress, expected sdk.Coins, keeper bankkeeper.Keeper, -) { - t.Helper() - balances := keeper.GetAllBalances(ctx, addr) - require.Equal(t, expected, balances) -} diff --git a/tests/integration/v2/bank/app_test.go b/tests/integration/v2/bank/app_test.go new file mode 100644 index 000000000000..26f43bf2e076 --- /dev/null +++ b/tests/integration/v2/bank/app_test.go @@ -0,0 +1,134 @@ +package bank + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + secp256k1_internal "gitlab.com/yawning/secp256k1-voi" + "gitlab.com/yawning/secp256k1-voi/secec" + + "cosmossdk.io/depinject" + "cosmossdk.io/log" + _ "cosmossdk.io/x/accounts" + _ "cosmossdk.io/x/bank" + bankkeeper "cosmossdk.io/x/bank/keeper" + "cosmossdk.io/x/bank/testutil" + "cosmossdk.io/x/bank/types" + _ "cosmossdk.io/x/consensus" + _ "cosmossdk.io/x/distribution" + distrkeeper "cosmossdk.io/x/distribution/keeper" + _ "cosmossdk.io/x/gov" + _ "cosmossdk.io/x/protocolpool" + _ "cosmossdk.io/x/staking" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/tests/integration/v2" + "github.com/cosmos/cosmos-sdk/testutil/configurator" + sdk "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/cosmos-sdk/x/auth" + _ "github.com/cosmos/cosmos-sdk/x/auth/tx/config" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" +) + +var ( + stablePrivateKey, _ = secec.NewPrivateKeyFromScalar(secp256k1_internal.NewScalarFromUint64(100)) + priv1 = &secp256k1.PrivKey{Key: stablePrivateKey.Bytes()} + addr1 = sdk.AccAddress(priv1.PubKey().Address()) + priv2 = secp256k1.GenPrivKey() + addr2 = sdk.AccAddress(priv2.PubKey().Address()) + addr3 = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + coins = sdk.Coins{sdk.NewInt64Coin("foocoin", 10)} + halfCoins = sdk.Coins{sdk.NewInt64Coin("foocoin", 5)} + sendMsg1 = types.NewMsgSend(addr1.String(), addr2.String(), coins) +) + +type suite struct { + BankKeeper bankkeeper.Keeper + AccountKeeper types.AccountKeeper + DistributionKeeper distrkeeper.Keeper + App *integration.App + TxConfig client.TxConfig +} + +func createTestSuite(t *testing.T, genesisAccounts []authtypes.GenesisAccount) suite { + t.Helper() + res := suite{} + + moduleConfigs := []configurator.ModuleOption{ + configurator.AccountsModule(), + configurator.AuthModule(), + configurator.StakingModule(), + configurator.TxModule(), + configurator.ValidateModule(), + configurator.ConsensusModule(), + configurator.BankModule(), + configurator.GovModule(), + configurator.DistributionModule(), + configurator.ProtocolPoolModule(), + } + var err error + startupCfg := integration.DefaultStartUpConfig() + var genAccounts []integration.GenesisAccount + for _, acc := range genesisAccounts { + genAccounts = append(genAccounts, integration.GenesisAccount{GenesisAccount: acc}) + } + startupCfg.GenesisAccounts = genAccounts + startupCfg.HomeDir = t.TempDir() + res.App, err = integration.SetupWithConfiguration( + depinject.Configs(configurator.NewAppV2Config(moduleConfigs...), depinject.Supply(log.NewNopLogger())), + startupCfg, + &res.BankKeeper, &res.AccountKeeper, &res.DistributionKeeper, &res.TxConfig) + require.NoError(t, err) + + return res +} + +func TestSendNotEnoughBalance(t *testing.T) { + acc := &authtypes.BaseAccount{ + Address: addr1.String(), + } + + genAccs := []authtypes.GenesisAccount{acc} + s := createTestSuite(t, genAccs) + ctx := context.Background() + + _, state, storeErr := s.App.Store.StateLatest() + require.NoError(t, storeErr) + + _, err := s.App.Run(ctx, state, func(ctx context.Context) error { + err := testutil.FundAccount( + ctx, s.BankKeeper, addr1, + sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67))) + require.NoError(t, err) + res1 := s.AccountKeeper.GetAccount(ctx, addr1) + require.NotNil(t, res1) + require.Equal(t, acc, res1.(*authtypes.BaseAccount)) + + origAccNum := res1.GetAccountNumber() + origSeq := res1.GetSequence() + addr1Str, err := s.AccountKeeper.AddressCodec().BytesToString(addr1) + require.NoError(t, err) + addr2Str, err := s.AccountKeeper.AddressCodec().BytesToString(addr2) + require.NoError(t, err) + sendMsg := types.NewMsgSend(addr1Str, addr2Str, sdk.Coins{sdk.NewInt64Coin("foocoin", 100)}) + + // TODO how to auto-advance height with app v2 interface? + s.App.SignCheckDeliver( + t, ctx, 2, []sdk.Msg{sendMsg}, "", []uint64{origAccNum}, []uint64{origSeq}, + []cryptotypes.PrivKey{priv1}, + "spendable balance 67foocoin is smaller than 100foocoin", + ) + s.App.CheckBalance(ctx, t, addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 67)}, s.BankKeeper) + res2 := s.AccountKeeper.GetAccount(ctx, addr1) + require.NotNil(t, res2) + + require.Equal(t, origAccNum, res2.GetAccountNumber()) + require.Equal(t, origSeq+1, res2.GetSequence()) + + return nil + }) + require.NoError(t, err) +} From ae35d88bfc46fa9bf8366247db66bf6328218d12 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Tue, 24 Sep 2024 15:32:20 -0500 Subject: [PATCH 42/57] port another test --- server/v2/stf/stf.go | 14 +- tests/integration/v2/app.go | 56 ++++---- tests/integration/v2/bank/app_test.go | 181 ++++++++++++++++++++------ tests/integration/v2/services.go | 3 +- 4 files changed, 181 insertions(+), 73 deletions(-) diff --git a/server/v2/stf/stf.go b/server/v2/stf/stf.go index b72e788caa62..497b3d389085 100644 --- a/server/v2/stf/stf.go +++ b/server/v2/stf/stf.go @@ -204,21 +204,13 @@ func (s STF[T]) deliverTx( } execResp, execGas, execEvents, err := s.execTx(ctx, state, gasLimit-validateGas, tx, execMode, hi) - res := server.TxResult{ + return server.TxResult{ Events: append(validationEvents, execEvents...), GasUsed: execGas + validateGas, GasWanted: gasLimit, Resp: execResp, Error: err, } - // TODO - // we should be using cosmossdk.io/errors here, but that dependency brings in - // grpc, which we want to avoid. can the error matching code be pulled out? - // below is a temporary solution. - if err != nil { - res.Code = 1 - } - return res } // validateTx validates a transaction given the provided WritableState and gas limit. @@ -537,7 +529,7 @@ func (e *executionContext) Value(key any) any { func (s STF[T]) makeContext( ctx context.Context, sender transaction.Identity, - state store.WriterMap, + store store.WriterMap, execMode transaction.ExecMode, ) *executionContext { valuedCtx := context.WithValue(ctx, corecontext.ExecModeKey, execMode) @@ -547,7 +539,7 @@ func (s STF[T]) makeContext( s.makeGasMeteredState, s.branchFn, sender, - state, + store, execMode, s.msgRouter, s.queryRouter, diff --git a/tests/integration/v2/app.go b/tests/integration/v2/app.go index adefff6787cb..84ce9047424b 100644 --- a/tests/integration/v2/app.go +++ b/tests/integration/v2/app.go @@ -239,7 +239,7 @@ func SetupWithConfiguration( if err != nil { return nil, fmt.Errorf("failed to set initial version: %w", err) } - integrationApp := &App{App: app, Store: store, txConfig: txConfig} + integrationApp := &App{App: app, Store: store, txConfig: txConfig, lastHeight: 1} emptyHash := sha256.Sum256(nil) _, genesisState, err := app.InitGenesis( @@ -269,8 +269,9 @@ func SetupWithConfiguration( type App struct { *runtime.App[stateMachineTx] - Store runtime.Store - txConfig client.TxConfig + lastHeight uint64 + Store runtime.Store + txConfig client.TxConfig } func (a *App) Run( @@ -288,25 +289,43 @@ func (a *App) Run( return nextState, nil } +func (a *App) Deliver( + t *testing.T, ctx context.Context, txs []stateMachineTx, +) (*server.BlockResponse, corestore.WriterMap) { + t.Helper() + req := &server.BlockRequest[stateMachineTx]{ + Height: a.lastHeight + 1, + Txs: txs, + Hash: make([]byte, 32), + AppHash: make([]byte, 32), + } + resp, state, err := a.DeliverBlock(ctx, req) + require.NoError(t, err) + a.lastHeight++ + return resp, state +} + +// StateLatestContext creates returns a new context from context.Background() with the latest state. +func (a *App) StateLatestContext(t *testing.T) context.Context { + t.Helper() + _, state, err := a.Store.StateLatest() + require.NoError(t, err) + writeableState := branch.DefaultNewWriterMap(state) + iCtx := integrationContext{state: writeableState} + return context.WithValue(context.Background(), contextKey, iCtx) +} + func (a *App) Commit(state corestore.WriterMap) ([]byte, error) { changes, err := state.GetStateChanges() if err != nil { return nil, fmt.Errorf("failed to get state changes: %w", err) } cs := &corestore.Changeset{Changes: changes} - //for _, change := range changes { - // if !bytes.Equal(change.Actor, []byte("acc")) { - // continue - // } - // for _, kv := range change.StateChanges { - // fmt.Printf("actor: %s, key: %x, value: %x\n", change.Actor, kv.Key, kv.Value) - // } - //} return a.Store.Commit(cs) } func (a *App) SignCheckDeliver( - t *testing.T, ctx context.Context, height uint64, msgs []sdk.Msg, + t *testing.T, ctx context.Context, msgs []sdk.Msg, chainID string, accNums, accSeqs []uint64, privateKeys []cryptotypes.PrivKey, txErrString string, ) server.TxResult { @@ -367,22 +386,13 @@ func (a *App) SignCheckDeliver( builtTx := txBuilder.GetTx() require.NoError(t, err) - blockResponse, blockState, err := a.DeliverBlock(ctx, &server.BlockRequest[stateMachineTx]{ - Height: height, - Txs: []stateMachineTx{builtTx}, - Hash: make([]byte, 32), - AppHash: make([]byte, 32), - }) - require.NoError(t, err) + blockResponse, blockState := a.Deliver(t, ctx, []stateMachineTx{builtTx}) require.Equal(t, 1, len(blockResponse.TxResults)) txResult := blockResponse.TxResults[0] - finalizeSuccess := txResult.Code == 0 if txErrString != "" { - require.False(t, finalizeSuccess) require.ErrorContains(t, txResult.Error, txErrString) } else { - require.True(t, finalizeSuccess) require.NoError(t, txResult.Error) } @@ -393,7 +403,7 @@ func (a *App) SignCheckDeliver( } func (a *App) CheckBalance( - ctx context.Context, t *testing.T, addr sdk.AccAddress, expected sdk.Coins, keeper bankkeeper.Keeper, + t *testing.T, ctx context.Context, addr sdk.AccAddress, expected sdk.Coins, keeper bankkeeper.Keeper, ) { t.Helper() balances := keeper.GetAllBalances(ctx, addr) diff --git a/tests/integration/v2/bank/app_test.go b/tests/integration/v2/bank/app_test.go index 26f43bf2e076..21983e1d4c6b 100644 --- a/tests/integration/v2/bank/app_test.go +++ b/tests/integration/v2/bank/app_test.go @@ -1,7 +1,6 @@ package bank import ( - "context" "testing" "github.com/stretchr/testify/require" @@ -21,8 +20,10 @@ import ( _ "cosmossdk.io/x/gov" _ "cosmossdk.io/x/protocolpool" _ "cosmossdk.io/x/staking" + stakingtypes "cosmossdk.io/x/staking/types" "github.com/cosmos/cosmos-sdk/client" + cdctestutil "github.com/cosmos/cosmos-sdk/codec/testutil" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/tests/integration/v2" @@ -43,6 +44,7 @@ var ( coins = sdk.Coins{sdk.NewInt64Coin("foocoin", 10)} halfCoins = sdk.Coins{sdk.NewInt64Coin("foocoin", 5)} sendMsg1 = types.NewMsgSend(addr1.String(), addr2.String(), coins) + moduleAccAddr = authtypes.NewModuleAddress(stakingtypes.BondedPoolName) ) type suite struct { @@ -53,6 +55,21 @@ type suite struct { TxConfig client.TxConfig } +type expectedBalance struct { + addr sdk.AccAddress + coins sdk.Coins +} + +type appTestCase struct { + desc string + msgs []sdk.Msg + accNums []uint64 + accSeqs []uint64 + privKeys []cryptotypes.PrivKey + expectedBalances []expectedBalance + expInError []string +} + func createTestSuite(t *testing.T, genesisAccounts []authtypes.GenesisAccount) suite { t.Helper() res := suite{} @@ -93,42 +110,130 @@ func TestSendNotEnoughBalance(t *testing.T) { genAccs := []authtypes.GenesisAccount{acc} s := createTestSuite(t, genAccs) - ctx := context.Background() - - _, state, storeErr := s.App.Store.StateLatest() - require.NoError(t, storeErr) - - _, err := s.App.Run(ctx, state, func(ctx context.Context) error { - err := testutil.FundAccount( - ctx, s.BankKeeper, addr1, - sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67))) - require.NoError(t, err) - res1 := s.AccountKeeper.GetAccount(ctx, addr1) - require.NotNil(t, res1) - require.Equal(t, acc, res1.(*authtypes.BaseAccount)) - - origAccNum := res1.GetAccountNumber() - origSeq := res1.GetSequence() - addr1Str, err := s.AccountKeeper.AddressCodec().BytesToString(addr1) - require.NoError(t, err) - addr2Str, err := s.AccountKeeper.AddressCodec().BytesToString(addr2) - require.NoError(t, err) - sendMsg := types.NewMsgSend(addr1Str, addr2Str, sdk.Coins{sdk.NewInt64Coin("foocoin", 100)}) - - // TODO how to auto-advance height with app v2 interface? - s.App.SignCheckDeliver( - t, ctx, 2, []sdk.Msg{sendMsg}, "", []uint64{origAccNum}, []uint64{origSeq}, - []cryptotypes.PrivKey{priv1}, - "spendable balance 67foocoin is smaller than 100foocoin", - ) - s.App.CheckBalance(ctx, t, addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 67)}, s.BankKeeper) - res2 := s.AccountKeeper.GetAccount(ctx, addr1) - require.NotNil(t, res2) - - require.Equal(t, origAccNum, res2.GetAccountNumber()) - require.Equal(t, origSeq+1, res2.GetSequence()) - - return nil - }) + ctx := s.App.StateLatestContext(t) + + err := testutil.FundAccount( + ctx, s.BankKeeper, addr1, + sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67))) + require.NoError(t, err) + res1 := s.AccountKeeper.GetAccount(ctx, addr1) + require.NotNil(t, res1) + require.Equal(t, acc, res1.(*authtypes.BaseAccount)) + + origAccNum := res1.GetAccountNumber() + origSeq := res1.GetSequence() + addr1Str, err := s.AccountKeeper.AddressCodec().BytesToString(addr1) + require.NoError(t, err) + addr2Str, err := s.AccountKeeper.AddressCodec().BytesToString(addr2) require.NoError(t, err) + sendMsg := types.NewMsgSend(addr1Str, addr2Str, sdk.Coins{sdk.NewInt64Coin("foocoin", 100)}) + + // TODO how to auto-advance height with app v2 interface? + s.App.SignCheckDeliver( + t, ctx, []sdk.Msg{sendMsg}, "", []uint64{origAccNum}, []uint64{origSeq}, + []cryptotypes.PrivKey{priv1}, + "spendable balance 67foocoin is smaller than 100foocoin", + ) + s.App.CheckBalance(t, ctx, addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 67)}, s.BankKeeper) + res2 := s.AccountKeeper.GetAccount(ctx, addr1) + require.NotNil(t, res2) + + require.Equal(t, origAccNum, res2.GetAccountNumber()) + require.Equal(t, origSeq+1, res2.GetSequence()) + + require.NoError(t, err) +} + +func TestMsgMultiSendWithAccounts(t *testing.T) { + addr1Str, err := cdctestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr1) + require.NoError(t, err) + acc := &authtypes.BaseAccount{ + Address: addr1Str, + } + + addr2Str, err := cdctestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr2) + require.NoError(t, err) + + moduleStrAddr, err := cdctestutil.CodecOptions{}.GetAddressCodec().BytesToString(moduleAccAddr) + require.NoError(t, err) + + genAccs := []authtypes.GenesisAccount{acc} + s := createTestSuite(t, genAccs) + ctx := s.App.StateLatestContext(t) + + require.NoError(t, testutil.FundAccount(ctx, s.BankKeeper, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67)))) + + _, state := s.App.Deliver(t, ctx, nil) + _, err = s.App.Commit(state) + require.NoError(t, err) + + res1 := s.AccountKeeper.GetAccount(ctx, addr1) + require.NotNil(t, res1) + require.Equal(t, acc, res1.(*authtypes.BaseAccount)) + + testCases := []appTestCase{ + { + desc: "make a valid tx", + msgs: []sdk.Msg{&types.MsgMultiSend{ + Inputs: []types.Input{types.NewInput(addr1Str, coins)}, + Outputs: []types.Output{types.NewOutput(addr2Str, coins)}, + }}, + accNums: []uint64{0}, + accSeqs: []uint64{0}, + privKeys: []cryptotypes.PrivKey{priv1}, + expectedBalances: []expectedBalance{ + {addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 57)}}, + {addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}}, + }, + }, + { + desc: "wrong accNum should pass Simulate, but not Deliver", + msgs: []sdk.Msg{&types.MsgMultiSend{ + Inputs: []types.Input{types.NewInput(addr1Str, coins)}, + Outputs: []types.Output{types.NewOutput(addr2Str, coins)}, + }}, + accNums: []uint64{1}, // wrong account number + accSeqs: []uint64{1}, + expInError: []string{"signature verification failed; please verify account number"}, + privKeys: []cryptotypes.PrivKey{priv1}, + }, + { + desc: "wrong accSeq should not pass Simulate", + msgs: []sdk.Msg{&types.MsgMultiSend{ + Inputs: []types.Input{types.NewInput(addr1Str, coins)}, + Outputs: []types.Output{ + types.NewOutput(moduleStrAddr, coins), + }, + }}, + accNums: []uint64{0}, + accSeqs: []uint64{0}, // wrong account sequence + expInError: []string{"account sequence mismatch"}, + privKeys: []cryptotypes.PrivKey{priv1}, + }, + { + desc: "multiple inputs not allowed", + msgs: []sdk.Msg{&types.MsgMultiSend{ + Inputs: []types.Input{types.NewInput(addr1Str, coins), types.NewInput(addr2Str, coins)}, + Outputs: []types.Output{}, + }}, + accNums: []uint64{0}, + accSeqs: []uint64{0}, + expInError: []string{"invalid number of signatures"}, + privKeys: []cryptotypes.PrivKey{priv1}, + }, + } + + for _, tc := range testCases { + t.Run(tc.desc, func(t *testing.T) { + var errString string + if len(tc.expInError) > 0 { + errString = tc.expInError[0] + } + s.App.SignCheckDeliver(t, ctx, tc.msgs, "", tc.accNums, tc.accSeqs, tc.privKeys, errString) + + for _, eb := range tc.expectedBalances { + s.App.CheckBalance(t, ctx, eb.addr, eb.coins, s.BankKeeper) + } + }) + } } diff --git a/tests/integration/v2/services.go b/tests/integration/v2/services.go index 64ccd21c2d2a..b1ef3b2760c9 100644 --- a/tests/integration/v2/services.go +++ b/tests/integration/v2/services.go @@ -2,13 +2,14 @@ package integration import ( "context" + "fmt" + "cosmossdk.io/core/comet" "cosmossdk.io/core/event" "cosmossdk.io/core/server" corestore "cosmossdk.io/core/store" "cosmossdk.io/core/transaction" "cosmossdk.io/runtime/v2" - "fmt" ) func (c cometServiceImpl) CometInfo(context.Context) comet.Info { From eb1f49e2965173864be30a540ca97d24c76690de Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Wed, 25 Sep 2024 09:39:15 -0500 Subject: [PATCH 43/57] port remaining bank tests --- tests/integration/v2/bank/app_test.go | 234 ++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) diff --git a/tests/integration/v2/bank/app_test.go b/tests/integration/v2/bank/app_test.go index 21983e1d4c6b..23d9e1ff5f47 100644 --- a/tests/integration/v2/bank/app_test.go +++ b/tests/integration/v2/bank/app_test.go @@ -9,6 +9,7 @@ import ( "cosmossdk.io/depinject" "cosmossdk.io/log" + sdkmath "cosmossdk.io/math" _ "cosmossdk.io/x/accounts" _ "cosmossdk.io/x/bank" bankkeeper "cosmossdk.io/x/bank/keeper" @@ -18,6 +19,7 @@ import ( _ "cosmossdk.io/x/distribution" distrkeeper "cosmossdk.io/x/distribution/keeper" _ "cosmossdk.io/x/gov" + govv1 "cosmossdk.io/x/gov/types/v1" _ "cosmossdk.io/x/protocolpool" _ "cosmossdk.io/x/staking" stakingtypes "cosmossdk.io/x/staking/types" @@ -237,3 +239,235 @@ func TestMsgMultiSendWithAccounts(t *testing.T) { }) } } + +func TestMsgMultiSendMultipleOut(t *testing.T) { + ac := cdctestutil.CodecOptions{}.GetAddressCodec() + addr1Str, err := ac.BytesToString(addr1) + require.NoError(t, err) + acc1 := &authtypes.BaseAccount{ + Address: addr1Str, + } + addr2Str, err := ac.BytesToString(addr2) + require.NoError(t, err) + acc2 := &authtypes.BaseAccount{ + Address: addr2Str, + } + addr3Str, err := ac.BytesToString(addr3) + require.NoError(t, err) + + genAccs := []authtypes.GenesisAccount{acc1, acc2} + s := createTestSuite(t, genAccs) + ctx := s.App.StateLatestContext(t) + + require.NoError(t, testutil.FundAccount(ctx, s.BankKeeper, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42)))) + require.NoError(t, testutil.FundAccount(ctx, s.BankKeeper, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42)))) + _, state := s.App.Deliver(t, ctx, nil) + _, err = s.App.Commit(state) + require.NoError(t, err) + + testCases := []appTestCase{ + { + msgs: []sdk.Msg{&types.MsgMultiSend{ + Inputs: []types.Input{types.NewInput(addr1Str, coins)}, + Outputs: []types.Output{ + types.NewOutput(addr2Str, halfCoins), + types.NewOutput(addr3Str, halfCoins), + }, + }}, + accNums: []uint64{0}, + accSeqs: []uint64{0}, + privKeys: []cryptotypes.PrivKey{priv1}, + expectedBalances: []expectedBalance{ + {addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}}, + {addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 47)}}, + {addr3, sdk.Coins{sdk.NewInt64Coin("foocoin", 5)}}, + }, + }, + } + + for _, tc := range testCases { + s.App.SignCheckDeliver(t, ctx, tc.msgs, "", tc.accNums, tc.accSeqs, tc.privKeys, "") + + for _, eb := range tc.expectedBalances { + s.App.CheckBalance(t, ctx, eb.addr, eb.coins, s.BankKeeper) + } + } +} + +func TestMsgMultiSendDependent(t *testing.T) { + ac := cdctestutil.CodecOptions{}.GetAddressCodec() + addr1Str, err := ac.BytesToString(addr1) + require.NoError(t, err) + addr2Str, err := ac.BytesToString(addr2) + require.NoError(t, err) + + acc1 := authtypes.NewBaseAccountWithAddress(addr1) + acc2 := authtypes.NewBaseAccountWithAddress(addr2) + err = acc2.SetAccountNumber(1) + require.NoError(t, err) + + genAccs := []authtypes.GenesisAccount{acc1, acc2} + s := createTestSuite(t, genAccs) + ctx := s.App.StateLatestContext(t) + + require.NoError(t, testutil.FundAccount(ctx, s.BankKeeper, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42)))) + _, state := s.App.Deliver(t, ctx, nil) + _, err = s.App.Commit(state) + require.NoError(t, err) + + testCases := []appTestCase{ + { + msgs: []sdk.Msg{&types.MsgMultiSend{ + Inputs: []types.Input{types.NewInput(addr1Str, coins)}, + Outputs: []types.Output{types.NewOutput(addr2Str, coins)}, + }}, + accNums: []uint64{0}, + accSeqs: []uint64{0}, + privKeys: []cryptotypes.PrivKey{priv1}, + expectedBalances: []expectedBalance{ + {addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}}, + {addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}}, + }, + }, + { + msgs: []sdk.Msg{&types.MsgMultiSend{ + Inputs: []types.Input{types.NewInput(addr2Str, coins)}, + Outputs: []types.Output{ + types.NewOutput(addr1Str, coins), + }, + }}, + accNums: []uint64{1}, + accSeqs: []uint64{0}, + privKeys: []cryptotypes.PrivKey{priv2}, + expectedBalances: []expectedBalance{ + {addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 42)}}, + }, + }, + } + + for _, tc := range testCases { + s.App.SignCheckDeliver(t, ctx, tc.msgs, "", tc.accNums, tc.accSeqs, tc.privKeys, "") + + for _, eb := range tc.expectedBalances { + s.App.CheckBalance(t, ctx, eb.addr, eb.coins, s.BankKeeper) + } + } +} + +func TestMsgSetSendEnabled(t *testing.T) { + acc1 := authtypes.NewBaseAccountWithAddress(addr1) + + genAccs := []authtypes.GenesisAccount{acc1} + s := createTestSuite(t, genAccs) + + ctx := s.App.StateLatestContext(t) + require.NoError(t, testutil.FundAccount(ctx, s.BankKeeper, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 101)))) + require.NoError(t, testutil.FundAccount(ctx, s.BankKeeper, addr1, sdk.NewCoins(sdk.NewInt64Coin("stake", 100000)))) + addr1Str := addr1.String() + govAddr := s.BankKeeper.GetAuthority() + goodGovProp, err := govv1.NewMsgSubmitProposal( + []sdk.Msg{ + types.NewMsgSetSendEnabled(govAddr, nil, nil), + }, + sdk.Coins{{Denom: "stake", Amount: sdkmath.NewInt(100000)}}, + addr1Str, + "set default send enabled to true", + "Change send enabled", + "Modify send enabled and set to true", + govv1.ProposalType_PROPOSAL_TYPE_STANDARD, + ) + require.NoError(t, err, "making goodGovProp") + + testCases := []appTestCase{ + { + desc: "wrong authority", + msgs: []sdk.Msg{ + types.NewMsgSetSendEnabled(addr1Str, nil, nil), + }, + accSeqs: []uint64{0}, + expInError: []string{ + "invalid authority", + "cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn", + addr1Str, + "expected authority account as only signer for proposal message", + }, + }, + { + desc: "right authority wrong signer", + msgs: []sdk.Msg{ + types.NewMsgSetSendEnabled(govAddr, nil, nil), + }, + accSeqs: []uint64{1}, // wrong signer, so this sequence doesn't actually get used. + expInError: []string{ + "cannot be claimed by public key with address", + govAddr, + }, + }, + { + desc: "submitted good as gov prop", + msgs: []sdk.Msg{ + goodGovProp, + }, + accSeqs: []uint64{1}, + expInError: nil, + }, + } + + for _, tc := range testCases { + t.Run(tc.desc, func(tt *testing.T) { + var errString string + if len(tc.expInError) > 0 { + errString = tc.expInError[0] + } + txResult := s.App.SignCheckDeliver( + tt, ctx, tc.msgs, "", []uint64{0}, tc.accSeqs, []cryptotypes.PrivKey{priv1}, errString) + if len(tc.expInError) > 0 { + require.Error(tt, txResult.Error) + for _, exp := range tc.expInError { + require.ErrorContains(tt, txResult.Error, exp) + } + } else { + require.NoError(tt, txResult.Error) + } + }) + } +} + +// TestSendToNonExistingAccount tests sending coins to an account that does not exist, and this account +// must not be created. +func TestSendToNonExistingAccount(t *testing.T) { + acc1 := authtypes.NewBaseAccountWithAddress(addr1) + genAccs := []authtypes.GenesisAccount{acc1} + s := createTestSuite(t, genAccs) + ctx := s.App.StateLatestContext(t) + + require.NoError(t, testutil.FundAccount(ctx, s.BankKeeper, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42)))) + _, state := s.App.Deliver(t, ctx, nil) + _, err := s.App.Commit(state) + require.NoError(t, err) + + addr2Str, err := s.AccountKeeper.AddressCodec().BytesToString(addr2) + require.NoError(t, err) + sendMsg := types.NewMsgSend(addr1.String(), addr2Str, coins) + res := s.App.SignCheckDeliver(t, ctx, []sdk.Msg{sendMsg}, "", []uint64{0}, []uint64{0}, []cryptotypes.PrivKey{priv1}, "") + require.NoError(t, res.Error) + + // Check that the account was not created + acc2 := s.AccountKeeper.GetAccount(ctx, addr2) + require.Nil(t, acc2) + + // But it does have a balance + s.App.CheckBalance(t, ctx, addr2, coins, s.BankKeeper) + + // Now we send coins back and the account should be created + sendMsg = types.NewMsgSend(addr2Str, addr1.String(), coins) + res = s.App.SignCheckDeliver(t, ctx, []sdk.Msg{sendMsg}, "", []uint64{0}, []uint64{0}, []cryptotypes.PrivKey{priv2}, "") + require.NoError(t, res.Error) + + // Balance has been reduced + s.App.CheckBalance(t, ctx, addr2, sdk.NewCoins(), s.BankKeeper) + + // Check that the account was created + acc2 = s.AccountKeeper.GetAccount(ctx, addr2) + require.NotNil(t, acc2, "account should have been created %s", addr2.String()) +} From e37ff14c356f4a06b6bd155d94c16c23e764695f Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Wed, 25 Sep 2024 09:46:36 -0500 Subject: [PATCH 44/57] revert whitespace changes --- collections/map.go | 4 +- core/header/service.go | 2 - core/store/service.go | 2 - runtime/v2/builder.go | 16 +- server/v2/appmanager/appmanager.go | 57 +- simapp/v2/simdv2/cmd/root_di.go | 16 +- store/cachekv/store.go | 4 +- tests/integration/gov/keeper/tally_test.go | 868 +++++---------------- 8 files changed, 196 insertions(+), 773 deletions(-) diff --git a/collections/map.go b/collections/map.go index b9fcd93b4ac3..360d96feafa3 100644 --- a/collections/map.go +++ b/collections/map.go @@ -131,9 +131,7 @@ func (m Map[K, V]) Iterate(ctx context.Context, ranger Ranger[K]) (Iterator[K, V // walk function with the decoded key and value. If the callback function // returns true then the walking is stopped. // A nil ranger equals to walking over the entire key and value set. -func (m Map[K, V]) Walk( - ctx context.Context, ranger Ranger[K], walkFunc func(key K, value V) (stop bool, err error), -) error { +func (m Map[K, V]) Walk(ctx context.Context, ranger Ranger[K], walkFunc func(key K, value V) (stop bool, err error)) error { iter, err := m.Iterate(ctx, ranger) if err != nil { return err diff --git a/core/header/service.go b/core/header/service.go index 29ee248f1389..8d36087a059c 100644 --- a/core/header/service.go +++ b/core/header/service.go @@ -13,8 +13,6 @@ type Service interface { HeaderInfo(context.Context) Info } -type HeaderServiceFactory func() Service - // Info defines a struct that contains information about the header type Info struct { Height int64 // Height returns the height of the block diff --git a/core/store/service.go b/core/store/service.go index 3f8c3d52b068..6faec8bdb0ce 100644 --- a/core/store/service.go +++ b/core/store/service.go @@ -23,8 +23,6 @@ type MemoryStoreService interface { OpenMemoryStore(context.Context) KVStore } -type MemoryStoreServiceFactory func([]byte) MemoryStoreService - // TransientStoreService represents a unique, non-forgeable handle to a memory-backed // KVStore which is reset at the start of every block. It should be provided as // a module-scoped dependency by the runtime module being used to build the app. diff --git a/runtime/v2/builder.go b/runtime/v2/builder.go index 7610c979eccc..1dd1ab47fef3 100644 --- a/runtime/v2/builder.go +++ b/runtime/v2/builder.go @@ -203,9 +203,7 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { type AppBuilderOption[T transaction.Tx] func(*AppBuilder[T]) // AppBuilderWithBranch sets a custom branch implementation for the app. -func AppBuilderWithBranch[T transaction.Tx]( - branch func(state store.ReaderMap) store.WriterMap, -) AppBuilderOption[T] { +func AppBuilderWithBranch[T transaction.Tx](branch func(state store.ReaderMap) store.WriterMap) AppBuilderOption[T] { return func(a *AppBuilder[T]) { a.branch = branch } @@ -213,11 +211,7 @@ func AppBuilderWithBranch[T transaction.Tx]( // AppBuilderWithTxValidator sets the tx validator for the app. // It overrides all default tx validators defined by modules. -func AppBuilderWithTxValidator[T transaction.Tx]( - txValidators func( - ctx context.Context, tx T, - ) error, -) AppBuilderOption[T] { +func AppBuilderWithTxValidator[T transaction.Tx](txValidators func(ctx context.Context, tx T) error) AppBuilderOption[T] { return func(a *AppBuilder[T]) { a.txValidator = txValidators } @@ -225,11 +219,7 @@ func AppBuilderWithTxValidator[T transaction.Tx]( // AppBuilderWithPostTxExec sets logic that will be executed after each transaction. // When not provided, a no-op function will be used. -func AppBuilderWithPostTxExec[T transaction.Tx]( - postTxExec func( - ctx context.Context, tx T, success bool, - ) error, -) AppBuilderOption[T] { +func AppBuilderWithPostTxExec[T transaction.Tx](postTxExec func(ctx context.Context, tx T, success bool) error) AppBuilderOption[T] { return func(a *AppBuilder[T]) { a.postTxExec = postTxExec } diff --git a/server/v2/appmanager/appmanager.go b/server/v2/appmanager/appmanager.go index d5a0606aa000..6a5f96ec5fa9 100644 --- a/server/v2/appmanager/appmanager.go +++ b/server/v2/appmanager/appmanager.go @@ -62,34 +62,20 @@ func (a AppManager[T]) InitGenesis( // run block blockRequest.Txs = genTxs - blockResponse, blockZeroState, err := a.stf.DeliverBlock( - ctx, - blockRequest, - genesisState, - ) + blockResponse, blockZeroState, err := a.stf.DeliverBlock(ctx, blockRequest, genesisState) if err != nil { - return blockResponse, nil, fmt.Errorf( - "failed to deliver block %d: %w", - blockRequest.Height, - err, - ) + return blockResponse, nil, fmt.Errorf("failed to deliver block %d: %w", blockRequest.Height, err) } // after executing block 0, we extract the changes and apply them to the genesis state. stateChanges, err := blockZeroState.GetStateChanges() if err != nil { - return nil, nil, fmt.Errorf( - "failed to get block zero state changes: %w", - err, - ) + return nil, nil, fmt.Errorf("failed to get block zero state changes: %w", err) } err = genesisState.ApplyStateChanges(stateChanges) if err != nil { - return nil, nil, fmt.Errorf( - "failed to apply block zero state changes to genesis state: %w", - err, - ) + return nil, nil, fmt.Errorf("failed to apply block zero state changes to genesis state: %w", err) } return blockResponse, genesisState, err @@ -110,19 +96,11 @@ func (a AppManager[T]) DeliverBlock( ) (*server.BlockResponse, corestore.WriterMap, error) { latestVersion, currentState, err := a.db.StateLatest() if err != nil { - return nil, nil, fmt.Errorf( - "unable to create new state for height %d: %w", - block.Height, - err, - ) + return nil, nil, fmt.Errorf("unable to create new state for height %d: %w", block.Height, err) } if latestVersion+1 != block.Height { - return nil, nil, fmt.Errorf( - "invalid DeliverBlock height wanted %d, got %d", - latestVersion+1, - block.Height, - ) + return nil, nil, fmt.Errorf("invalid DeliverBlock height wanted %d, got %d", latestVersion+1, block.Height) } blockResponse, newState, err := a.stf.DeliverBlock(ctx, block, currentState) @@ -136,10 +114,7 @@ func (a AppManager[T]) DeliverBlock( // ValidateTx will validate the tx against the latest storage state. This means that // only the stateful validation will be run, not the execution portion of the tx. // If full execution is needed, Simulate must be used. -func (a AppManager[T]) ValidateTx( - ctx context.Context, - tx T, -) (server.TxResult, error) { +func (a AppManager[T]) ValidateTx(ctx context.Context, tx T) (server.TxResult, error) { _, latestState, err := a.db.StateLatest() if err != nil { return server.TxResult{}, err @@ -149,30 +124,18 @@ func (a AppManager[T]) ValidateTx( } // Simulate runs validation and execution flow of a Tx. -func (a AppManager[T]) Simulate( - ctx context.Context, - tx T, -) (server.TxResult, corestore.WriterMap, error) { +func (a AppManager[T]) Simulate(ctx context.Context, tx T) (server.TxResult, corestore.WriterMap, error) { _, state, err := a.db.StateLatest() if err != nil { return server.TxResult{}, nil, err } - result, cs := a.stf.Simulate( - ctx, - state, - a.config.SimulationGasLimit, - tx, - ) // TODO: check if this is done in the antehandler + result, cs := a.stf.Simulate(ctx, state, a.config.SimulationGasLimit, tx) // TODO: check if this is done in the antehandler return result, cs, nil } // Query queries the application at the provided version. // CONTRACT: Version must always be provided, if 0, get latest -func (a AppManager[T]) Query( - ctx context.Context, - version uint64, - request transaction.Msg, -) (transaction.Msg, error) { +func (a AppManager[T]) Query(ctx context.Context, version uint64, request transaction.Msg) (transaction.Msg, error) { // if version is provided attempt to do a height query. if version != 0 { queryState, err := a.db.StateAt(version) diff --git a/simapp/v2/simdv2/cmd/root_di.go b/simapp/v2/simdv2/cmd/root_di.go index 130130b8e57f..1ad834b53a5a 100644 --- a/simapp/v2/simdv2/cmd/root_di.go +++ b/simapp/v2/simdv2/cmd/root_di.go @@ -70,11 +70,7 @@ func NewRootCmd[T transaction.Tx]() *cobra.Command { } customClientTemplate, customClientConfig := initClientConfig() - clientCtx, err = config.CreateClientConfig( - clientCtx, - customClientTemplate, - customClientConfig, - ) + clientCtx, err = config.CreateClientConfig(clientCtx, customClientTemplate, customClientConfig) if err != nil { return err } @@ -113,9 +109,7 @@ func ProvideClientContext( amino, ok := legacyAmino.(*codec.LegacyAmino) if !ok { - panic( - "registry.AminoRegistrar must be an *codec.LegacyAmino instance for legacy ClientContext", - ) + panic("registry.AminoRegistrar must be an *codec.LegacyAmino instance for legacy ClientContext") } clientCtx := client.Context{}. @@ -132,11 +126,7 @@ func ProvideClientContext( // Read the config to overwrite the default values with the values from the config file customClientTemplate, customClientConfig := initClientConfig() - clientCtx, err = config.CreateClientConfig( - clientCtx, - customClientTemplate, - customClientConfig, - ) + clientCtx, err = config.CreateClientConfig(clientCtx, customClientTemplate, customClientConfig) if err != nil { panic(err) } diff --git a/store/cachekv/store.go b/store/cachekv/store.go index c0798455aba8..3509cef6aee3 100644 --- a/store/cachekv/store.go +++ b/store/cachekv/store.go @@ -366,9 +366,7 @@ func (store *Store) dirtyItems(start, end []byte) { store.clearUnsortedCacheSubset(kvL, stateAlreadySorted) } -func (store *Store) clearUnsortedCacheSubset( - unsorted []*kv.Pair, sortState sortState, -) { //nolint:staticcheck // We are in store v1. +func (store *Store) clearUnsortedCacheSubset(unsorted []*kv.Pair, sortState sortState) { //nolint:staticcheck // We are in store v1. n := len(store.unsortedCache) if len(unsorted) == n { // This pattern allows the Go compiler to emit the map clearing idiom for the entire map. for key := range store.unsortedCache { diff --git a/tests/integration/gov/keeper/tally_test.go b/tests/integration/gov/keeper/tally_test.go index 965b0ec29216..f2b952076285 100644 --- a/tests/integration/gov/keeper/tally_test.go +++ b/tests/integration/gov/keeper/tally_test.go @@ -17,26 +17,20 @@ func TestTallyNoOneVotes(t *testing.T) { t.Parallel() f := initFixture(t) + ctx := f.ctx + createValidators(t, f, []int64{5, 5, 5}) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal( - f.ctx, - tp, - "", - "test", - "description", - sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"), - v1.ProposalType_PROPOSAL_TYPE_STANDARD, - ) + proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"), v1.ProposalType_PROPOSAL_TYPE_STANDARD) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) assert.NilError(t, err) - proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) + proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) assert.Assert(t, passes == false) assert.Assert(t, burnDeposits == false) @@ -48,43 +42,25 @@ func TestTallyNoQuorum(t *testing.T) { f := initFixture(t) + ctx := f.ctx + createValidators(t, f, []int64{2, 5, 0}) - addrs := simtestutil.AddTestAddrsIncremental( - f.bankKeeper, - f.stakingKeeper, - f.ctx, - 1, - math.NewInt(10000000), - ) + addrs := simtestutil.AddTestAddrsIncremental(f.bankKeeper, f.stakingKeeper, ctx, 1, math.NewInt(10000000)) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal( - f.ctx, - tp, - "", - "test", - "description", - addrs[0], - v1.ProposalType_PROPOSAL_TYPE_STANDARD, - ) + proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", addrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) assert.NilError(t, err) - err = f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[0], - v1.NewNonSplitVoteOption(v1.OptionYes), - "", - ) + err = f.govKeeper.AddVote(ctx, proposalID, addrs[0], v1.NewNonSplitVoteOption(v1.OptionYes), "") assert.NilError(t, err) - proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) + proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, _, _ := f.govKeeper.Tally(f.ctx, proposal) + passes, burnDeposits, _, _ := f.govKeeper.Tally(ctx, proposal) assert.Assert(t, passes == false) assert.Assert(t, burnDeposits == false) } @@ -94,57 +70,24 @@ func TestTallyOnlyValidatorsAllYes(t *testing.T) { f := initFixture(t) + ctx := f.ctx + addrs, _ := createValidators(t, f, []int64{5, 5, 5}) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal( - f.ctx, - tp, - "", - "test", - "description", - addrs[0], - v1.ProposalType_PROPOSAL_TYPE_STANDARD, - ) + proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", addrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[0], - v1.NewNonSplitVoteOption(v1.OptionYes), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[1], - v1.NewNonSplitVoteOption(v1.OptionYes), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[2], - v1.NewNonSplitVoteOption(v1.OptionYes), - "", - ), - ) - - proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[0], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[1], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[2], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + + proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) assert.Assert(t, passes) assert.Assert(t, burnDeposits == false) @@ -156,47 +99,23 @@ func TestTallyOnlyValidators51No(t *testing.T) { f := initFixture(t) + ctx := f.ctx + valAccAddrs, _ := createValidators(t, f, []int64{5, 6, 0}) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal( - f.ctx, - tp, - "", - "test", - "description", - valAccAddrs[0], - v1.ProposalType_PROPOSAL_TYPE_STANDARD, - ) + proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", valAccAddrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - valAccAddrs[0], - v1.NewNonSplitVoteOption(v1.OptionYes), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - valAccAddrs[1], - v1.NewNonSplitVoteOption(v1.OptionNo), - "", - ), - ) - - proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[0], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[1], v1.NewNonSplitVoteOption(v1.OptionNo), "")) + + proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, _, _ := f.govKeeper.Tally(f.ctx, proposal) + passes, burnDeposits, _, _ := f.govKeeper.Tally(ctx, proposal) assert.Assert(t, passes == false) assert.Assert(t, burnDeposits == false) @@ -207,47 +126,23 @@ func TestTallyOnlyValidators51Yes(t *testing.T) { f := initFixture(t) + ctx := f.ctx + valAccAddrs, _ := createValidators(t, f, []int64{5, 6, 0}) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal( - f.ctx, - tp, - "", - "test", - "description", - valAccAddrs[0], - v1.ProposalType_PROPOSAL_TYPE_STANDARD, - ) + proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", valAccAddrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - valAccAddrs[0], - v1.NewNonSplitVoteOption(v1.OptionNo), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - valAccAddrs[1], - v1.NewNonSplitVoteOption(v1.OptionYes), - "", - ), - ) - - proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[0], v1.NewNonSplitVoteOption(v1.OptionNo), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[1], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + + proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) assert.Assert(t, passes) assert.Assert(t, burnDeposits == false) @@ -259,57 +154,24 @@ func TestTallyOnlyValidatorsVetoed(t *testing.T) { f := initFixture(t) + ctx := f.ctx + valAccAddrs, _ := createValidators(t, f, []int64{6, 6, 7}) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal( - f.ctx, - tp, - "", - "test", - "description", - valAccAddrs[0], - v1.ProposalType_PROPOSAL_TYPE_STANDARD, - ) + proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", valAccAddrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - valAccAddrs[0], - v1.NewNonSplitVoteOption(v1.OptionYes), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - valAccAddrs[1], - v1.NewNonSplitVoteOption(v1.OptionYes), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - valAccAddrs[2], - v1.NewNonSplitVoteOption(v1.OptionNoWithVeto), - "", - ), - ) - - proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[0], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[1], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[2], v1.NewNonSplitVoteOption(v1.OptionNoWithVeto), "")) + + proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) assert.Assert(t, passes == false) assert.Assert(t, burnDeposits) @@ -321,57 +183,24 @@ func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) { f := initFixture(t) + ctx := f.ctx + valAccAddrs, _ := createValidators(t, f, []int64{6, 6, 7}) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal( - f.ctx, - tp, - "", - "test", - "description", - valAccAddrs[0], - v1.ProposalType_PROPOSAL_TYPE_STANDARD, - ) + proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", valAccAddrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - valAccAddrs[0], - v1.NewNonSplitVoteOption(v1.OptionAbstain), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - valAccAddrs[1], - v1.NewNonSplitVoteOption(v1.OptionNo), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - valAccAddrs[2], - v1.NewNonSplitVoteOption(v1.OptionYes), - "", - ), - ) - - proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[0], v1.NewNonSplitVoteOption(v1.OptionAbstain), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[1], v1.NewNonSplitVoteOption(v1.OptionNo), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[2], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + + proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) assert.Assert(t, passes) assert.Assert(t, burnDeposits == false) @@ -383,57 +212,24 @@ func TestTallyOnlyValidatorsAbstainFails(t *testing.T) { f := initFixture(t) + ctx := f.ctx + valAccAddrs, _ := createValidators(t, f, []int64{6, 6, 7}) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal( - f.ctx, - tp, - "", - "test", - "description", - valAccAddrs[0], - v1.ProposalType_PROPOSAL_TYPE_STANDARD, - ) + proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", valAccAddrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - valAccAddrs[0], - v1.NewNonSplitVoteOption(v1.OptionAbstain), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - valAccAddrs[1], - v1.NewNonSplitVoteOption(v1.OptionYes), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - valAccAddrs[2], - v1.NewNonSplitVoteOption(v1.OptionNo), - "", - ), - ) - - proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[0], v1.NewNonSplitVoteOption(v1.OptionAbstain), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[1], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddrs[2], v1.NewNonSplitVoteOption(v1.OptionNo), "")) + + proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) assert.Assert(t, passes == false) assert.Assert(t, burnDeposits == false) @@ -445,48 +241,24 @@ func TestTallyOnlyValidatorsNonVoter(t *testing.T) { f := initFixture(t) + ctx := f.ctx + valAccAddrs, _ := createValidators(t, f, []int64{5, 6, 7}) valAccAddr1, valAccAddr2 := valAccAddrs[0], valAccAddrs[1] tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal( - f.ctx, - tp, - "", - "test", - "description", - valAccAddrs[0], - v1.ProposalType_PROPOSAL_TYPE_STANDARD, - ) + proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", valAccAddrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - valAccAddr1, - v1.NewNonSplitVoteOption(v1.OptionYes), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - valAccAddr2, - v1.NewNonSplitVoteOption(v1.OptionNo), - "", - ), - ) - - proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddr1, v1.NewNonSplitVoteOption(v1.OptionYes), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, valAccAddr2, v1.NewNonSplitVoteOption(v1.OptionNo), "")) + + proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) assert.Assert(t, passes == false) assert.Assert(t, burnDeposits == false) @@ -498,83 +270,34 @@ func TestTallyDelgatorOverride(t *testing.T) { f := initFixture(t) + ctx := f.ctx + addrs, valAddrs := createValidators(t, f, []int64{5, 6, 7}) - delTokens := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 30) - val1, found := f.stakingKeeper.GetValidator(f.ctx, valAddrs[0]) + delTokens := f.stakingKeeper.TokensFromConsensusPower(ctx, 30) + val1, found := f.stakingKeeper.GetValidator(ctx, valAddrs[0]) assert.Assert(t, found) - _, err := f.stakingKeeper.Delegate( - f.ctx, - addrs[4], - delTokens, - stakingtypes.Unbonded, - val1, - true, - ) + _, err := f.stakingKeeper.Delegate(ctx, addrs[4], delTokens, stakingtypes.Unbonded, val1, true) assert.NilError(t, err) - _, err = f.stakingKeeper.EndBlocker(f.ctx) + _, err = f.stakingKeeper.EndBlocker(ctx) assert.NilError(t, err) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal( - f.ctx, - tp, - "", - "test", - "description", - addrs[0], - v1.ProposalType_PROPOSAL_TYPE_STANDARD, - ) + proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", addrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[1], - v1.NewNonSplitVoteOption(v1.OptionYes), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[2], - v1.NewNonSplitVoteOption(v1.OptionYes), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[3], - v1.NewNonSplitVoteOption(v1.OptionYes), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[4], - v1.NewNonSplitVoteOption(v1.OptionNo), - "", - ), - ) - - proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[1], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[2], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[3], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[4], v1.NewNonSplitVoteOption(v1.OptionNo), "")) + + proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) assert.Assert(t, passes == false) assert.Assert(t, burnDeposits == false) @@ -586,73 +309,33 @@ func TestTallyDelgatorInherit(t *testing.T) { f := initFixture(t) + ctx := f.ctx + addrs, vals := createValidators(t, f, []int64{5, 6, 7}) - delTokens := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 30) - val3, found := f.stakingKeeper.GetValidator(f.ctx, vals[2]) + delTokens := f.stakingKeeper.TokensFromConsensusPower(ctx, 30) + val3, found := f.stakingKeeper.GetValidator(ctx, vals[2]) assert.Assert(t, found) - _, err := f.stakingKeeper.Delegate( - f.ctx, - addrs[3], - delTokens, - stakingtypes.Unbonded, - val3, - true, - ) + _, err := f.stakingKeeper.Delegate(ctx, addrs[3], delTokens, stakingtypes.Unbonded, val3, true) assert.NilError(t, err) - _, err = f.stakingKeeper.EndBlocker(f.ctx) + _, err = f.stakingKeeper.EndBlocker(ctx) assert.NilError(t, err) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal( - f.ctx, - tp, - "", - "test", - "description", - addrs[0], - v1.ProposalType_PROPOSAL_TYPE_STANDARD, - ) + proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", addrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[0], - v1.NewNonSplitVoteOption(v1.OptionNo), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[1], - v1.NewNonSplitVoteOption(v1.OptionNo), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[2], - v1.NewNonSplitVoteOption(v1.OptionYes), - "", - ), - ) - - proposal, err = f.govKeeper.Proposals.Get(f.ctx, proposalID) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[0], v1.NewNonSplitVoteOption(v1.OptionNo), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[1], v1.NewNonSplitVoteOption(v1.OptionNo), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[2], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + + proposal, err = f.govKeeper.Proposals.Get(ctx, proposalID) assert.NilError(t, err) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) assert.Assert(t, passes) assert.Assert(t, burnDeposits == false) @@ -664,93 +347,37 @@ func TestTallyDelgatorMultipleOverride(t *testing.T) { f := initFixture(t) + ctx := f.ctx + addrs, vals := createValidators(t, f, []int64{5, 6, 7}) - delTokens := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 10) - val1, found := f.stakingKeeper.GetValidator(f.ctx, vals[0]) + delTokens := f.stakingKeeper.TokensFromConsensusPower(ctx, 10) + val1, found := f.stakingKeeper.GetValidator(ctx, vals[0]) assert.Assert(t, found) - val2, found := f.stakingKeeper.GetValidator(f.ctx, vals[1]) + val2, found := f.stakingKeeper.GetValidator(ctx, vals[1]) assert.Assert(t, found) - _, err := f.stakingKeeper.Delegate( - f.ctx, - addrs[3], - delTokens, - stakingtypes.Unbonded, - val1, - true, - ) + _, err := f.stakingKeeper.Delegate(ctx, addrs[3], delTokens, stakingtypes.Unbonded, val1, true) assert.NilError(t, err) - _, err = f.stakingKeeper.Delegate( - f.ctx, - addrs[3], - delTokens, - stakingtypes.Unbonded, - val2, - true, - ) + _, err = f.stakingKeeper.Delegate(ctx, addrs[3], delTokens, stakingtypes.Unbonded, val2, true) assert.NilError(t, err) - _, err = f.stakingKeeper.EndBlocker(f.ctx) + _, err = f.stakingKeeper.EndBlocker(ctx) assert.NilError(t, err) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal( - f.ctx, - tp, - "", - "test", - "description", - addrs[0], - v1.ProposalType_PROPOSAL_TYPE_STANDARD, - ) + proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", addrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[0], - v1.NewNonSplitVoteOption(v1.OptionYes), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[1], - v1.NewNonSplitVoteOption(v1.OptionYes), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[2], - v1.NewNonSplitVoteOption(v1.OptionYes), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[3], - v1.NewNonSplitVoteOption(v1.OptionNo), - "", - ), - ) - - proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[0], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[1], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[2], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[3], v1.NewNonSplitVoteOption(v1.OptionNo), "")) + + proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) assert.Assert(t, passes == false) assert.Assert(t, burnDeposits == false) @@ -762,86 +389,39 @@ func TestTallyDelgatorMultipleInherit(t *testing.T) { f := initFixture(t) + ctx := f.ctx + createValidators(t, f, []int64{25, 6, 7}) addrs, vals := createValidators(t, f, []int64{5, 6, 7}) - delTokens := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 10) - val2, found := f.stakingKeeper.GetValidator(f.ctx, vals[1]) + delTokens := f.stakingKeeper.TokensFromConsensusPower(ctx, 10) + val2, found := f.stakingKeeper.GetValidator(ctx, vals[1]) assert.Assert(t, found) - val3, found := f.stakingKeeper.GetValidator(f.ctx, vals[2]) + val3, found := f.stakingKeeper.GetValidator(ctx, vals[2]) assert.Assert(t, found) - _, err := f.stakingKeeper.Delegate( - f.ctx, - addrs[3], - delTokens, - stakingtypes.Unbonded, - val2, - true, - ) + _, err := f.stakingKeeper.Delegate(ctx, addrs[3], delTokens, stakingtypes.Unbonded, val2, true) assert.NilError(t, err) - _, err = f.stakingKeeper.Delegate( - f.ctx, - addrs[3], - delTokens, - stakingtypes.Unbonded, - val3, - true, - ) + _, err = f.stakingKeeper.Delegate(ctx, addrs[3], delTokens, stakingtypes.Unbonded, val3, true) assert.NilError(t, err) - _, err = f.stakingKeeper.EndBlocker(f.ctx) + _, err = f.stakingKeeper.EndBlocker(ctx) assert.NilError(t, err) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal( - f.ctx, - tp, - "", - "test", - "description", - addrs[0], - v1.ProposalType_PROPOSAL_TYPE_STANDARD, - ) + proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", addrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[0], - v1.NewNonSplitVoteOption(v1.OptionYes), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[1], - v1.NewNonSplitVoteOption(v1.OptionNo), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[2], - v1.NewNonSplitVoteOption(v1.OptionNo), - "", - ), - ) - - proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[0], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[1], v1.NewNonSplitVoteOption(v1.OptionNo), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[2], v1.NewNonSplitVoteOption(v1.OptionNo), "")) + + proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) assert.Assert(t, passes == false) assert.Assert(t, burnDeposits == false) @@ -853,87 +433,41 @@ func TestTallyJailedValidator(t *testing.T) { f := initFixture(t) + ctx := f.ctx + addrs, valAddrs := createValidators(t, f, []int64{25, 6, 7}) - delTokens := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 10) - val2, found := f.stakingKeeper.GetValidator(f.ctx, valAddrs[1]) + delTokens := f.stakingKeeper.TokensFromConsensusPower(ctx, 10) + val2, found := f.stakingKeeper.GetValidator(ctx, valAddrs[1]) assert.Assert(t, found) - val3, found := f.stakingKeeper.GetValidator(f.ctx, valAddrs[2]) + val3, found := f.stakingKeeper.GetValidator(ctx, valAddrs[2]) assert.Assert(t, found) - _, err := f.stakingKeeper.Delegate( - f.ctx, - addrs[3], - delTokens, - stakingtypes.Unbonded, - val2, - true, - ) + _, err := f.stakingKeeper.Delegate(ctx, addrs[3], delTokens, stakingtypes.Unbonded, val2, true) assert.NilError(t, err) - _, err = f.stakingKeeper.Delegate( - f.ctx, - addrs[3], - delTokens, - stakingtypes.Unbonded, - val3, - true, - ) + _, err = f.stakingKeeper.Delegate(ctx, addrs[3], delTokens, stakingtypes.Unbonded, val3, true) assert.NilError(t, err) - _, err = f.stakingKeeper.EndBlocker(f.ctx) + _, err = f.stakingKeeper.EndBlocker(ctx) assert.NilError(t, err) consAddr, err := val2.GetConsAddr() assert.NilError(t, err) - assert.NilError(t, f.stakingKeeper.Jail(f.ctx, sdk.ConsAddress(consAddr))) + assert.NilError(t, f.stakingKeeper.Jail(ctx, sdk.ConsAddress(consAddr))) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal( - f.ctx, - tp, - "", - "test", - "description", - addrs[0], - v1.ProposalType_PROPOSAL_TYPE_STANDARD, - ) + proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", addrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[0], - v1.NewNonSplitVoteOption(v1.OptionYes), - "", - )) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[1], - v1.NewNonSplitVoteOption(v1.OptionNo), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[2], - v1.NewNonSplitVoteOption(v1.OptionNo), - "", - ), - ) - - proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[0], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[1], v1.NewNonSplitVoteOption(v1.OptionNo), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[2], v1.NewNonSplitVoteOption(v1.OptionNo), "")) + + proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) assert.Assert(t, passes) assert.Assert(t, burnDeposits == false) @@ -945,86 +479,40 @@ func TestTallyValidatorMultipleDelegations(t *testing.T) { f := initFixture(t) + ctx := f.ctx + addrs, valAddrs := createValidators(t, f, []int64{10, 10, 10}) - delTokens := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 10) - val2, found := f.stakingKeeper.GetValidator(f.ctx, valAddrs[1]) + delTokens := f.stakingKeeper.TokensFromConsensusPower(ctx, 10) + val2, found := f.stakingKeeper.GetValidator(ctx, valAddrs[1]) assert.Assert(t, found) - _, err := f.stakingKeeper.Delegate( - f.ctx, - addrs[0], - delTokens, - stakingtypes.Unbonded, - val2, - true, - ) + _, err := f.stakingKeeper.Delegate(ctx, addrs[0], delTokens, stakingtypes.Unbonded, val2, true) assert.NilError(t, err) tp := TestProposal - proposal, err := f.govKeeper.SubmitProposal( - f.ctx, - tp, - "", - "test", - "description", - addrs[0], - v1.ProposalType_PROPOSAL_TYPE_STANDARD, - ) + proposal, err := f.govKeeper.SubmitProposal(ctx, tp, "", "test", "description", addrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD) assert.NilError(t, err) proposalID := proposal.Id proposal.Status = v1.StatusVotingPeriod - err = f.govKeeper.Proposals.Set(f.ctx, proposal.Id, proposal) + err = f.govKeeper.Proposals.Set(ctx, proposal.Id, proposal) assert.NilError(t, err) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[0], - v1.NewNonSplitVoteOption(v1.OptionYes), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[1], - v1.NewNonSplitVoteOption(v1.OptionNo), - "", - ), - ) - assert.NilError( - t, - f.govKeeper.AddVote( - f.ctx, - proposalID, - addrs[2], - v1.NewNonSplitVoteOption(v1.OptionYes), - "", - ), - ) - - proposal, ok := f.govKeeper.Proposals.Get(f.ctx, proposalID) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[0], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[1], v1.NewNonSplitVoteOption(v1.OptionNo), "")) + assert.NilError(t, f.govKeeper.AddVote(ctx, proposalID, addrs[2], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + + proposal, ok := f.govKeeper.Proposals.Get(ctx, proposalID) assert.Assert(t, ok) - passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(f.ctx, proposal) + passes, burnDeposits, tallyResults, _ := f.govKeeper.Tally(ctx, proposal) assert.Assert(t, passes) assert.Assert(t, burnDeposits == false) - expectedYes := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 30) - expectedAbstain := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 0) - expectedNo := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 10) - expectedNoWithVeto := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 0) - expectedTallyResult := v1.NewTallyResult( - expectedYes, - expectedAbstain, - expectedNo, - expectedNoWithVeto, - math.ZeroInt(), - ) + expectedYes := f.stakingKeeper.TokensFromConsensusPower(ctx, 30) + expectedAbstain := f.stakingKeeper.TokensFromConsensusPower(ctx, 0) + expectedNo := f.stakingKeeper.TokensFromConsensusPower(ctx, 10) + expectedNoWithVeto := f.stakingKeeper.TokensFromConsensusPower(ctx, 0) + expectedTallyResult := v1.NewTallyResult(expectedYes, expectedAbstain, expectedNo, expectedNoWithVeto, math.ZeroInt()) assert.Assert(t, tallyResults.Equals(expectedTallyResult)) } From 7e6b4db70b5ca546c4fb2688eb75d63210186929 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Wed, 25 Sep 2024 09:48:11 -0500 Subject: [PATCH 45/57] moar whitespace --- runtime/v2/builder.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/runtime/v2/builder.go b/runtime/v2/builder.go index 1dd1ab47fef3..b28ddbc741b4 100644 --- a/runtime/v2/builder.go +++ b/runtime/v2/builder.go @@ -41,13 +41,7 @@ func (a *AppBuilder[T]) RegisterModules(modules map[string]appmodulev2.AppModule // if a (legacy) module implements the HasName interface, check that the name matches if mod, ok := appModule.(interface{ Name() string }); ok { if name != mod.Name() { - a.app.logger.Warn( - fmt.Sprintf( - "module name %q does not match name returned by HasName: %q", - name, - mod.Name(), - ), - ) + a.app.logger.Warn(fmt.Sprintf("module name %q does not match name returned by HasName: %q", name, mod.Name())) } } From d3e474c5116aa21d4b9266f56e49b3594bd099c1 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Wed, 25 Sep 2024 09:49:37 -0500 Subject: [PATCH 46/57] why did x/upgrade get touched? --- x/upgrade/go.mod | 1 - x/upgrade/go.sum | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/x/upgrade/go.mod b/x/upgrade/go.mod index 146b70db50a8..5fdfdd4154a2 100644 --- a/x/upgrade/go.mod +++ b/x/upgrade/go.mod @@ -202,7 +202,6 @@ replace github.com/cosmos/cosmos-sdk => ../../. replace ( cosmossdk.io/api => ../../api - cosmossdk.io/core => ../../core cosmossdk.io/store => ../../store cosmossdk.io/x/bank => ../bank cosmossdk.io/x/gov => ../gov diff --git a/x/upgrade/go.sum b/x/upgrade/go.sum index e9a0d8a3422c..6c3ffb2eec07 100644 --- a/x/upgrade/go.sum +++ b/x/upgrade/go.sum @@ -194,6 +194,8 @@ cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1V cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s= cosmossdk.io/collections v0.4.0/go.mod h1:oa5lUING2dP+gdDquow+QjlF45eL1t4TJDypgGd+tv0= +cosmossdk.io/core v1.0.0-alpha.3 h1:pnxaYAas7llXgVz1lM7X6De74nWrhNKnB3yMKe4OUUA= +cosmossdk.io/core v1.0.0-alpha.3/go.mod h1:3u9cWq1FAVtiiCrDPpo4LhR+9V6k/ycSG4/Y/tREWCY= cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29 h1:NxxUo0GMJUbIuVg0R70e3cbn9eFTEuMr7ev1AFvypdY= cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29/go.mod h1:8s2tPeJtSiQuoyPmr2Ag7meikonISO4Fv4MoO8+ORrs= cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050= From 8292c98a04a6a22012adaf699d9e99c2f88203fb Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Wed, 25 Sep 2024 09:55:48 -0500 Subject: [PATCH 47/57] godocs --- runtime/v2/store.go | 2 ++ tests/integration/v2/app.go | 20 +++++--------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/runtime/v2/store.go b/runtime/v2/store.go index 717f8a7dd138..08d86bfd2c82 100644 --- a/runtime/v2/store.go +++ b/runtime/v2/store.go @@ -64,10 +64,12 @@ type Store interface { LastCommitID() (proof.CommitID, error) } +// StoreBuilder is a builder for a store/v2 RootStore satisfying the Store interface. type StoreBuilder struct { store Store } +// Build creates a new store/v2 RootStore. func (sb *StoreBuilder) Build( logger log.Logger, storeKeys []string, diff --git a/tests/integration/v2/app.go b/tests/integration/v2/app.go index 84ce9047424b..e174669e83f9 100644 --- a/tests/integration/v2/app.go +++ b/tests/integration/v2/app.go @@ -267,6 +267,7 @@ func SetupWithConfiguration( return integrationApp, nil } +// App is a wrapper around runtime.App that provides additional testing utilities. type App struct { *runtime.App[stateMachineTx] lastHeight uint64 @@ -274,21 +275,7 @@ type App struct { txConfig client.TxConfig } -func (a *App) Run( - ctx context.Context, - state corestore.ReaderMap, - fn func(ctx context.Context) error, -) (corestore.ReaderMap, error) { - nextState := branch.DefaultNewWriterMap(state) - iCtx := integrationContext{state: nextState} - ctx = context.WithValue(ctx, contextKey, iCtx) - err := fn(ctx) - if err != nil { - return nil, err - } - return nextState, nil -} - +// Deliver delivers a block with the given transactions and returns the resulting state. func (a *App) Deliver( t *testing.T, ctx context.Context, txs []stateMachineTx, ) (*server.BlockResponse, corestore.WriterMap) { @@ -315,6 +302,7 @@ func (a *App) StateLatestContext(t *testing.T) context.Context { return context.WithValue(context.Background(), contextKey, iCtx) } +// Commit commits the given state and returns the new state hash. func (a *App) Commit(state corestore.WriterMap) ([]byte, error) { changes, err := state.GetStateChanges() if err != nil { @@ -324,6 +312,7 @@ func (a *App) Commit(state corestore.WriterMap) ([]byte, error) { return a.Store.Commit(cs) } +// SignCheckDeliver signs and checks the given messages and delivers them. func (a *App) SignCheckDeliver( t *testing.T, ctx context.Context, msgs []sdk.Msg, chainID string, accNums, accSeqs []uint64, privateKeys []cryptotypes.PrivKey, @@ -402,6 +391,7 @@ func (a *App) SignCheckDeliver( return txResult } +// CheckBalance checks the balance of the given address. func (a *App) CheckBalance( t *testing.T, ctx context.Context, addr sdk.AccAddress, expected sdk.Coins, keeper bankkeeper.Keeper, ) { From 706a5916d36fc8686f351ac43e5086112a05b285 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Fri, 27 Sep 2024 10:15:23 -0500 Subject: [PATCH 48/57] more cleanup but stuck on gas service --- tests/integration/v2/app.go | 87 +++++++-------- tests/integration/v2/bank/app_test.go | 5 +- .../v2/bank/determinisitic_test.go | 100 ++++++++++++++++++ testutil/testdata/grpc_query.go | 30 ++++++ 4 files changed, 172 insertions(+), 50 deletions(-) create mode 100644 tests/integration/v2/bank/determinisitic_test.go diff --git a/tests/integration/v2/app.go b/tests/integration/v2/app.go index e174669e83f9..98703e6f6fcd 100644 --- a/tests/integration/v2/app.go +++ b/tests/integration/v2/app.go @@ -1,4 +1,3 @@ -// this file is a port of testutil/sims/app_helpers.go from v1 to v2 architecture package integration import ( @@ -10,11 +9,9 @@ import ( "testing" "time" - "github.com/cosmos/cosmos-sdk/client" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/types/tx/signing" - authsign "github.com/cosmos/cosmos-sdk/x/auth/signing" + cmtproto "github.com/cometbft/cometbft/api/cometbft/types/v1" + cmtjson "github.com/cometbft/cometbft/libs/json" + cmttypes "github.com/cometbft/cometbft/types" "github.com/stretchr/testify/require" "cosmossdk.io/core/comet" @@ -31,19 +28,26 @@ import ( bankkeeper "cosmossdk.io/x/bank/keeper" banktypes "cosmossdk.io/x/bank/types" consensustypes "cosmossdk.io/x/consensus/types" - cmtproto "github.com/cometbft/cometbft/api/cometbft/types/v1" - cmtjson "github.com/cometbft/cometbft/libs/json" - cmttypes "github.com/cometbft/cometbft/types" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/std" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + authsign "github.com/cosmos/cosmos-sdk/x/auth/signing" "github.com/cosmos/cosmos-sdk/x/auth/tx" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) const DefaultGenTxGas = 10000000 +const ( + Genesis_COMMIT = iota + Genesis_NOCOMMIT + Genesis_SKIP +) type stateMachineTx = transaction.Tx @@ -78,12 +82,14 @@ var DefaultConsensusParams = &cmtproto.ConsensusParams{ type StartupConfig struct { ValidatorSet func() (*cmttypes.ValidatorSet, error) AppOption runtime.AppBuilderOption[stateMachineTx] - AtGenesis bool + GenesisBehavior int GenesisAccounts []GenesisAccount HomeDir string } -func DefaultStartUpConfig() StartupConfig { +func DefaultStartUpConfig(t *testing.T) StartupConfig { + t.Helper() + priv := secp256k1.GenPrivKey() ba := authtypes.NewBaseAccount( priv.PubKey().Address().Bytes(), @@ -99,38 +105,16 @@ func DefaultStartUpConfig() StartupConfig { } return StartupConfig{ ValidatorSet: CreateRandomValidatorSet, - AtGenesis: false, + GenesisBehavior: Genesis_COMMIT, GenesisAccounts: []GenesisAccount{ga}, + HomeDir: t.TempDir(), } } -// Setup initializes a new runtime.App and can inject values into extraOutputs. -// It uses SetupWithConfiguration under the hood. -func Setup( - appConfig depinject.Config, - extraOutputs ...interface{}, -) (*App, error) { - return SetupWithConfiguration( - appConfig, - DefaultStartUpConfig(), - extraOutputs...) -} - -// SetupAtGenesis initializes a new runtime.App at genesis and can inject values into extraOutputs. -// It uses SetupWithConfiguration under the hood. -func SetupAtGenesis( - appConfig depinject.Config, - extraOutputs ...interface{}, -) (*App, error) { - cfg := DefaultStartUpConfig() - cfg.AtGenesis = true - return SetupWithConfiguration(appConfig, cfg, extraOutputs...) -} - -// SetupWithConfiguration initializes a new runtime.App. A Nop logger is set in runtime.App. +// NewApp initializes a new runtime.App. A Nop logger is set in runtime.App. // appConfig defines the application configuration (f.e. app_config.go). // extraOutputs defines the extra outputs to be assigned by the dependency injector (depinject). -func SetupWithConfiguration( +func NewApp( appConfig depinject.Config, startupConfig StartupConfig, extraOutputs ...interface{}, @@ -177,6 +161,20 @@ func SetupWithConfiguration( return nil, fmt.Errorf("failed to load app: %w", err) } + store := storeBuilder.Get() + if store == nil { + return nil, fmt.Errorf("failed to build store: %w", err) + } + err = store.SetInitialVersion(1) + if err != nil { + return nil, fmt.Errorf("failed to set initial version: %w", err) + } + + integrationApp := &App{App: app, Store: store, txConfig: txConfig, lastHeight: 1} + if startupConfig.GenesisBehavior == Genesis_SKIP { + return integrationApp, nil + } + // create validator set valSet, err := startupConfig.ValidatorSet() if err != nil { @@ -231,16 +229,6 @@ func SetupWithConfiguration( }, ) - store := storeBuilder.Get() - if store == nil { - return nil, fmt.Errorf("failed to build store: %w", err) - } - err = store.SetInitialVersion(1) - if err != nil { - return nil, fmt.Errorf("failed to set initial version: %w", err) - } - integrationApp := &App{App: app, Store: store, txConfig: txConfig, lastHeight: 1} - emptyHash := sha256.Sum256(nil) _, genesisState, err := app.InitGenesis( ctx, @@ -259,6 +247,11 @@ func SetupWithConfiguration( return nil, fmt.Errorf("failed init genesiss: %w", err) } + if startupConfig.GenesisBehavior == Genesis_NOCOMMIT { + integrationApp.lastHeight = 0 + return integrationApp, nil + } + _, err = integrationApp.Commit(genesisState) if err != nil { return nil, fmt.Errorf("failed to commit initial version: %w", err) diff --git a/tests/integration/v2/bank/app_test.go b/tests/integration/v2/bank/app_test.go index 23d9e1ff5f47..c6aa89ab5e87 100644 --- a/tests/integration/v2/bank/app_test.go +++ b/tests/integration/v2/bank/app_test.go @@ -89,14 +89,13 @@ func createTestSuite(t *testing.T, genesisAccounts []authtypes.GenesisAccount) s configurator.ProtocolPoolModule(), } var err error - startupCfg := integration.DefaultStartUpConfig() + startupCfg := integration.DefaultStartUpConfig(t) var genAccounts []integration.GenesisAccount for _, acc := range genesisAccounts { genAccounts = append(genAccounts, integration.GenesisAccount{GenesisAccount: acc}) } startupCfg.GenesisAccounts = genAccounts - startupCfg.HomeDir = t.TempDir() - res.App, err = integration.SetupWithConfiguration( + res.App, err = integration.NewApp( depinject.Configs(configurator.NewAppV2Config(moduleConfigs...), depinject.Supply(log.NewNopLogger())), startupCfg, &res.BankKeeper, &res.AccountKeeper, &res.DistributionKeeper, &res.TxConfig) diff --git a/tests/integration/v2/bank/determinisitic_test.go b/tests/integration/v2/bank/determinisitic_test.go new file mode 100644 index 000000000000..26cf1344bbf8 --- /dev/null +++ b/tests/integration/v2/bank/determinisitic_test.go @@ -0,0 +1,100 @@ +package bank + +import ( + "context" + "testing" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + "pgregory.net/rapid" + + "cosmossdk.io/depinject" + "cosmossdk.io/log" + "cosmossdk.io/math" + bankkeeper "cosmossdk.io/x/bank/keeper" + banktestutil "cosmossdk.io/x/bank/testutil" + banktypes "cosmossdk.io/x/bank/types" + + codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil" + "github.com/cosmos/cosmos-sdk/tests/integration/v2" + "github.com/cosmos/cosmos-sdk/testutil/configurator" + "github.com/cosmos/cosmos-sdk/testutil/testdata" + sdk "github.com/cosmos/cosmos-sdk/types" + authtestutil "github.com/cosmos/cosmos-sdk/x/auth/testutil" +) + +var denomRegex = `[a-zA-Z][a-zA-Z0-9/:._-]{2,127}` + +type deterministicFixture struct { + *testing.T + ctx context.Context + app *integration.App + bankKeeper bankkeeper.Keeper +} + +func (f *deterministicFixture) QueryBalance( + ctx context.Context, req *banktypes.QueryBalanceRequest, +) (*banktypes.QueryBalanceResponse, error) { + res, err := f.app.Query(ctx, 0, req) + return res.(*banktypes.QueryBalanceResponse), err +} + +func fundAccount(f *deterministicFixture, addr sdk.AccAddress, coin ...sdk.Coin) { + err := banktestutil.FundAccount(f.ctx, f.bankKeeper, addr, sdk.NewCoins(coin...)) + require.NoError(f.T, err) +} + +func getCoin(rt *rapid.T) sdk.Coin { + return sdk.NewCoin( + rapid.StringMatching(denomRegex).Draw(rt, "denom"), + math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")), + ) +} + +func initDeterministicFixture(t *testing.T) *deterministicFixture { + t.Helper() + + ctrl := gomock.NewController(t) + acctsModKeeper := authtestutil.NewMockAccountsModKeeper(ctrl) + accNum := uint64(0) + acctsModKeeper.EXPECT().NextAccountNumber(gomock.Any()).AnyTimes().DoAndReturn(func(ctx context.Context) ( + uint64, error, + ) { + currentNum := accNum + accNum++ + return currentNum, nil + }) + + startupConfig := integration.DefaultStartUpConfig(t) + startupConfig.GenesisBehavior = integration.Genesis_SKIP + diConfig := configurator.NewAppV2Config( + configurator.TxModule(), + configurator.AuthModule(), + configurator.BankModule(), + ) + + var bankKeeper bankkeeper.Keeper + diConfig = depinject.Configs(diConfig, depinject.Supply(acctsModKeeper, log.NewNopLogger())) + app, err := integration.NewApp(diConfig, startupConfig, &bankKeeper) + require.NoError(t, err) + require.NotNil(t, app) + return &deterministicFixture{app: app, bankKeeper: bankKeeper, T: t} +} + +func TestGRPCQueryBalance(t *testing.T) { + f := initDeterministicFixture(t) + f.ctx = f.app.StateLatestContext(t) + + rapid.Check(t, func(rt *rapid.T) { + addr := testdata.AddressGenerator(rt).Draw(rt, "address") + coin := getCoin(rt) + fundAccount(f, addr, coin) + + addrStr, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr) + require.NoError(t, err) + + req := banktypes.NewQueryBalanceRequest(addrStr, coin.GetDenom()) + + testdata.DeterministicIterationsV2(t, f.ctx, nil, req, f.QueryBalance, 0, true) + }) +} diff --git a/testutil/testdata/grpc_query.go b/testutil/testdata/grpc_query.go index a8b4d75b0621..b4af37bfecbf 100644 --- a/testutil/testdata/grpc_query.go +++ b/testutil/testdata/grpc_query.go @@ -6,6 +6,7 @@ import ( "fmt" "testing" + "cosmossdk.io/core/gas" gogoprotoany "github.com/cosmos/gogoproto/types/any" "github.com/cosmos/gogoproto/types/any/test" @@ -94,3 +95,32 @@ func DeterministicIterations[request, response proto.Message]( assert.DeepEqual(t, res, prevRes) } } + +func DeterministicIterationsV2[request, response proto.Message]( + t *testing.T, + ctx context.Context, + gasService gas.Service, + req request, + grpcFn func(context.Context, request) (response, error), + gasConsumed uint64, + gasOverwrite bool, +) { + t.Helper() + consumed := func() uint64 { + return gasService.GasMeter(ctx).Consumed() + } + before := consumed() + prevRes, err := grpcFn(ctx, req) + assert.NilError(t, err) + if gasOverwrite { // to handle regressions, i.e. check that gas consumption didn't change + gasConsumed = consumed() - before + } + + for i := 0; i < iterCount; i++ { + before := consumed() + res, err := grpcFn(ctx, req) + assert.Equal(t, consumed()-before, gasConsumed) + assert.NilError(t, err) + assert.DeepEqual(t, res, prevRes) + } +} From db419845690d125fe7c4b8e5c6e25f0b1f49f06b Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Fri, 27 Sep 2024 14:27:30 -0500 Subject: [PATCH 49/57] tests passing --- server/v2/appmanager/appmanager.go | 26 +- server/v2/appmanager/types.go | 3 +- server/v2/cometbft/abci.go | 14 +- server/v2/cometbft/handlers/defaults.go | 25 +- server/v2/stf/stf.go | 7 +- tests/integration/v2/app.go | 2 +- .../v2/bank/determinisitic_test.go | 535 +++++++++++++++++- tests/integration/v2/services.go | 26 +- testutil/testdata/grpc_query.go | 43 +- 9 files changed, 626 insertions(+), 55 deletions(-) diff --git a/server/v2/appmanager/appmanager.go b/server/v2/appmanager/appmanager.go index 6a5f96ec5fa9..ea490a3e3f69 100644 --- a/server/v2/appmanager/appmanager.go +++ b/server/v2/appmanager/appmanager.go @@ -3,6 +3,7 @@ package appmanager import ( "bytes" "context" + "cosmossdk.io/core/gas" "encoding/json" "errors" "fmt" @@ -135,20 +136,21 @@ func (a AppManager[T]) Simulate(ctx context.Context, tx T) (server.TxResult, cor // Query queries the application at the provided version. // CONTRACT: Version must always be provided, if 0, get latest -func (a AppManager[T]) Query(ctx context.Context, version uint64, request transaction.Msg) (transaction.Msg, error) { +func (a AppManager[T]) Query( + ctx context.Context, version uint64, request transaction.Msg, +) (transaction.Msg, gas.Gas, error) { + var ( + queryState corestore.ReaderMap + err error + ) // if version is provided attempt to do a height query. if version != 0 { - queryState, err := a.db.StateAt(version) - if err != nil { - return nil, err - } - return a.stf.Query(ctx, queryState, a.config.QueryGasLimit, request) + queryState, err = a.db.StateAt(version) + } else { // otherwise rely on latest available state. + _, queryState, err = a.db.StateLatest() } - - // otherwise rely on latest available state. - _, queryState, err := a.db.StateLatest() if err != nil { - return nil, err + return nil, 0, err } return a.stf.Query(ctx, queryState, a.config.QueryGasLimit, request) } @@ -156,6 +158,8 @@ func (a AppManager[T]) Query(ctx context.Context, version uint64, request transa // QueryWithState executes a query with the provided state. This allows to process a query // independently of the db state. For example, it can be used to process a query with temporary // and uncommitted state -func (a AppManager[T]) QueryWithState(ctx context.Context, state corestore.ReaderMap, request transaction.Msg) (transaction.Msg, error) { +func (a AppManager[T]) QueryWithState( + ctx context.Context, state corestore.ReaderMap, request transaction.Msg, +) (transaction.Msg, gas.Gas, error) { return a.stf.Query(ctx, state, a.config.QueryGasLimit, request) } diff --git a/server/v2/appmanager/types.go b/server/v2/appmanager/types.go index 1e769c13ff9c..990911057342 100644 --- a/server/v2/appmanager/types.go +++ b/server/v2/appmanager/types.go @@ -3,6 +3,7 @@ package appmanager import ( "context" + "cosmossdk.io/core/gas" "cosmossdk.io/core/server" "cosmossdk.io/core/store" "cosmossdk.io/core/transaction" @@ -39,5 +40,5 @@ type StateTransitionFunction[T transaction.Tx] interface { state store.ReaderMap, gasLimit uint64, req transaction.Msg, - ) (transaction.Msg, error) + ) (transaction.Msg, gas.Gas, error) } diff --git a/server/v2/cometbft/abci.go b/server/v2/cometbft/abci.go index 85b38e4ccc65..e883852e38c2 100644 --- a/server/v2/cometbft/abci.go +++ b/server/v2/cometbft/abci.go @@ -189,7 +189,9 @@ func (c *Consensus[T]) Info(ctx context.Context, _ *abciproto.InfoRequest) (*abc // Query implements types.Application. // It is called by cometbft to query application state. -func (c *Consensus[T]) Query(ctx context.Context, req *abciproto.QueryRequest) (resp *abciproto.QueryResponse, err error) { +func (c *Consensus[T]) Query( + ctx context.Context, req *abciproto.QueryRequest, +) (resp *abciproto.QueryResponse, err error) { // check if it's a gRPC method makeGRPCRequest, isGRPC := c.grpcMethodsMap[req.Path] if isGRPC { @@ -198,7 +200,7 @@ func (c *Consensus[T]) Query(ctx context.Context, req *abciproto.QueryRequest) ( if err != nil { return nil, fmt.Errorf("unable to decode gRPC request with path %s from ABCI.Query: %w", req.Path, err) } - res, err := c.app.Query(ctx, uint64(req.Height), protoRequest) + res, _, err := c.app.Query(ctx, uint64(req.Height), protoRequest) if err != nil { resp := QueryResult(err, c.cfg.AppTomlConfig.Trace) resp.Height = req.Height @@ -238,7 +240,9 @@ func (c *Consensus[T]) Query(ctx context.Context, req *abciproto.QueryRequest) ( } // InitChain implements types.Application. -func (c *Consensus[T]) InitChain(ctx context.Context, req *abciproto.InitChainRequest) (*abciproto.InitChainResponse, error) { +func (c *Consensus[T]) InitChain(ctx context.Context, req *abciproto.InitChainRequest) ( + *abciproto.InitChainResponse, error, +) { c.logger.Info("InitChain", "initialHeight", req.InitialHeight, "chainID", req.ChainId) // store chainID to be used later on in execution @@ -554,7 +558,9 @@ func (c *Consensus[T]) VerifyVoteExtension( } // ExtendVote implements types.Application. -func (c *Consensus[T]) ExtendVote(ctx context.Context, req *abciproto.ExtendVoteRequest) (*abciproto.ExtendVoteResponse, error) { +func (c *Consensus[T]) ExtendVote(ctx context.Context, req *abciproto.ExtendVoteRequest) ( + *abciproto.ExtendVoteResponse, error, +) { // If vote extensions are not enabled, as a safety precaution, we return an // error. cp, err := c.GetConsensusParams(ctx) diff --git a/server/v2/cometbft/handlers/defaults.go b/server/v2/cometbft/handlers/defaults.go index d8f43bb2fd25..740c8ec46f20 100644 --- a/server/v2/cometbft/handlers/defaults.go +++ b/server/v2/cometbft/handlers/defaults.go @@ -2,6 +2,7 @@ package handlers import ( "context" + "cosmossdk.io/core/gas" "errors" "fmt" @@ -16,7 +17,9 @@ import ( type AppManager[T transaction.Tx] interface { ValidateTx(ctx context.Context, tx T) (server.TxResult, error) - Query(ctx context.Context, version uint64, request transaction.Msg) (response transaction.Msg, err error) + Query( + ctx context.Context, version uint64, request transaction.Msg, + ) (response transaction.Msg, gas gas.Gas, err error) } type DefaultProposalHandler[T transaction.Tx] struct { @@ -32,10 +35,12 @@ func NewDefaultProposalHandler[T transaction.Tx](mp mempool.Mempool[T]) *Default } func (h *DefaultProposalHandler[T]) PrepareHandler() PrepareHandler[T] { - return func(ctx context.Context, app AppManager[T], codec transaction.Codec[T], req *abci.PrepareProposalRequest) ([]T, error) { + return func( + ctx context.Context, app AppManager[T], codec transaction.Codec[T], req *abci.PrepareProposalRequest, + ) ([]T, error) { var maxBlockGas uint64 - res, err := app.Query(ctx, 0, &consensustypes.QueryParamsRequest{}) + res, _, err := app.Query(ctx, 0, &consensustypes.QueryParamsRequest{}) if err != nil { return nil, err } @@ -98,7 +103,9 @@ func (h *DefaultProposalHandler[T]) PrepareHandler() PrepareHandler[T] { } func (h *DefaultProposalHandler[T]) ProcessHandler() ProcessHandler[T] { - return func(ctx context.Context, app AppManager[T], codec transaction.Codec[T], req *abci.ProcessProposalRequest) error { + return func( + ctx context.Context, app AppManager[T], codec transaction.Codec[T], req *abci.ProcessProposalRequest, + ) error { // If the mempool is nil we simply return ACCEPT, // because PrepareProposal may have included txs that could fail verification. _, isNoOp := h.mempool.(mempool.NoOpMempool[T]) @@ -106,7 +113,7 @@ func (h *DefaultProposalHandler[T]) ProcessHandler() ProcessHandler[T] { return nil } - res, err := app.Query(ctx, 0, &consensustypes.QueryParamsRequest{}) + res, _, err := app.Query(ctx, 0, &consensustypes.QueryParamsRequest{}) if err != nil { return err } @@ -174,7 +181,9 @@ func decodeTxs[T transaction.Tx](codec transaction.Codec[T], txsBz [][]byte) []T // NoOpPrepareProposal defines a no-op PrepareProposal handler. It will always // return the transactions sent by the client's request. func NoOpPrepareProposal[T transaction.Tx]() PrepareHandler[T] { - return func(ctx context.Context, app AppManager[T], codec transaction.Codec[T], req *abci.PrepareProposalRequest) ([]T, error) { + return func( + ctx context.Context, app AppManager[T], codec transaction.Codec[T], req *abci.PrepareProposalRequest, + ) ([]T, error) { return decodeTxs(codec, req.Txs), nil } } @@ -198,7 +207,9 @@ func NoOpExtendVote() ExtendVoteHandler { // NoOpVerifyVoteExtensionHandler defines a no-op VerifyVoteExtension handler. It // will always return an ACCEPT status with no error. func NoOpVerifyVoteExtensionHandler() VerifyVoteExtensionhandler { - return func(context.Context, store.ReaderMap, *abci.VerifyVoteExtensionRequest) (*abci.VerifyVoteExtensionResponse, error) { + return func(context.Context, store.ReaderMap, *abci.VerifyVoteExtensionRequest) ( + *abci.VerifyVoteExtensionResponse, error, + ) { return &abci.VerifyVoteExtensionResponse{Status: abci.VERIFY_VOTE_EXTENSION_STATUS_ACCEPT}, nil } } diff --git a/server/v2/stf/stf.go b/server/v2/stf/stf.go index f8d69e972712..b7834acaf726 100644 --- a/server/v2/stf/stf.go +++ b/server/v2/stf/stf.go @@ -436,16 +436,17 @@ func (s STF[T]) Query( state store.ReaderMap, gasLimit uint64, req transaction.Msg, -) (transaction.Msg, error) { +) (transaction.Msg, gas.Gas, error) { queryState := s.branchFn(state) hi, err := s.getHeaderInfo(queryState) if err != nil { - return nil, err + return nil, 0, err } queryCtx := s.makeContext(ctx, nil, queryState, internal.ExecModeSimulate) queryCtx.setHeaderInfo(hi) queryCtx.setGasLimit(gasLimit) - return s.queryRouter.Invoke(queryCtx, req) + res, err := s.queryRouter.Invoke(queryCtx, req) + return res, queryCtx.meter.Consumed(), err } // clone clones STF. diff --git a/tests/integration/v2/app.go b/tests/integration/v2/app.go index 98703e6f6fcd..f7e956ec63bd 100644 --- a/tests/integration/v2/app.go +++ b/tests/integration/v2/app.go @@ -291,7 +291,7 @@ func (a *App) StateLatestContext(t *testing.T) context.Context { _, state, err := a.Store.StateLatest() require.NoError(t, err) writeableState := branch.DefaultNewWriterMap(state) - iCtx := integrationContext{state: writeableState} + iCtx := &integrationContext{state: writeableState} return context.WithValue(context.Background(), contextKey, iCtx) } diff --git a/tests/integration/v2/bank/determinisitic_test.go b/tests/integration/v2/bank/determinisitic_test.go index 26cf1344bbf8..59cca8789d21 100644 --- a/tests/integration/v2/bank/determinisitic_test.go +++ b/tests/integration/v2/bank/determinisitic_test.go @@ -2,6 +2,8 @@ package bank import ( "context" + "cosmossdk.io/core/gas" + minttypes "cosmossdk.io/x/mint/types" "testing" "github.com/golang/mock/gomock" @@ -23,7 +25,27 @@ import ( authtestutil "github.com/cosmos/cosmos-sdk/x/auth/testutil" ) -var denomRegex = `[a-zA-Z][a-zA-Z0-9/:._-]{2,127}` +var ( + denomRegex = `[a-zA-Z][a-zA-Z0-9/:._-]{2,127}` + coin1 = sdk.NewCoin("denom", math.NewInt(10)) + metadataAtom = banktypes.Metadata{ + Description: "The native staking token of the Cosmos Hub.", + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: "uatom", + Exponent: 0, + Aliases: []string{"microatom"}, + }, + { + Denom: "atom", + Exponent: 6, + Aliases: []string{"ATOM"}, + }, + }, + Base: "uatom", + Display: "atom", + } +) type deterministicFixture struct { *testing.T @@ -35,10 +57,73 @@ type deterministicFixture struct { func (f *deterministicFixture) QueryBalance( ctx context.Context, req *banktypes.QueryBalanceRequest, ) (*banktypes.QueryBalanceResponse, error) { - res, err := f.app.Query(ctx, 0, req) + res, _, err := f.app.Query(ctx, 0, req) return res.(*banktypes.QueryBalanceResponse), err } +func (f *deterministicFixture) QueryAllBalances( + ctx context.Context, req *banktypes.QueryAllBalancesRequest, +) (*banktypes.QueryAllBalancesResponse, error) { + res, _, err := f.app.Query(ctx, 0, req) + return res.(*banktypes.QueryAllBalancesResponse), err +} + +func (f *deterministicFixture) QuerySpendableBalances( + ctx context.Context, req *banktypes.QuerySpendableBalancesRequest, +) (*banktypes.QuerySpendableBalancesResponse, error) { + res, _, err := f.app.Query(ctx, 0, req) + return res.(*banktypes.QuerySpendableBalancesResponse), err +} + +func (f *deterministicFixture) QueryTotalSupply( + ctx context.Context, req *banktypes.QueryTotalSupplyRequest, +) (*banktypes.QueryTotalSupplyResponse, error) { + res, _, err := f.app.Query(ctx, 0, req) + return res.(*banktypes.QueryTotalSupplyResponse), err +} + +func (f *deterministicFixture) QuerySupplyOf( + ctx context.Context, req *banktypes.QuerySupplyOfRequest, +) (*banktypes.QuerySupplyOfResponse, error) { + res, _, err := f.app.Query(ctx, 0, req) + return res.(*banktypes.QuerySupplyOfResponse), err +} + +func (f *deterministicFixture) QueryParams( + ctx context.Context, req *banktypes.QueryParamsRequest, +) (*banktypes.QueryParamsResponse, error) { + res, _, err := f.app.Query(ctx, 0, req) + return res.(*banktypes.QueryParamsResponse), err +} + +func (f *deterministicFixture) QueryDenomsMetadata( + ctx context.Context, req *banktypes.QueryDenomsMetadataRequest, +) (*banktypes.QueryDenomsMetadataResponse, error) { + res, _, err := f.app.Query(ctx, 0, req) + return res.(*banktypes.QueryDenomsMetadataResponse), err +} + +func (f *deterministicFixture) QueryDenomMetadata( + ctx context.Context, req *banktypes.QueryDenomMetadataRequest, +) (*banktypes.QueryDenomMetadataResponse, error) { + res, _, err := f.app.Query(ctx, 0, req) + return res.(*banktypes.QueryDenomMetadataResponse), err +} + +func (f *deterministicFixture) QuerySendEnabled( + ctx context.Context, req *banktypes.QuerySendEnabledRequest, +) (*banktypes.QuerySendEnabledResponse, error) { + res, _, err := f.app.Query(ctx, 0, req) + return res.(*banktypes.QuerySendEnabledResponse), err +} + +func (f *deterministicFixture) QueryDenomOwners( + ctx context.Context, req *banktypes.QueryDenomOwnersRequest, +) (*banktypes.QueryDenomOwnersResponse, error) { + res, _, err := f.app.Query(ctx, 0, req) + return res.(*banktypes.QueryDenomOwnersResponse), err +} + func fundAccount(f *deterministicFixture, addr sdk.AccAddress, coin ...sdk.Coin) { err := banktestutil.FundAccount(f.ctx, f.bankKeeper, addr, sdk.NewCoins(coin...)) require.NoError(f.T, err) @@ -81,9 +166,23 @@ func initDeterministicFixture(t *testing.T) *deterministicFixture { return &deterministicFixture{app: app, bankKeeper: bankKeeper, T: t} } -func TestGRPCQueryBalance(t *testing.T) { +func assertNonZeroGas(t *testing.T, gasUsed gas.Gas) { + t.Helper() + require.NotZero(t, gasUsed) +} + +func TestQueryBalance(t *testing.T) { + t.Parallel() f := initDeterministicFixture(t) f.ctx = f.app.StateLatestContext(t) + gasMeterFactory := integration.GasMeterFactory(f.ctx) + assertBalance := func(coin sdk.Coin) func(t *testing.T, res *banktypes.QueryBalanceResponse) { + return func(t *testing.T, res *banktypes.QueryBalanceResponse) { + require.Equal(t, coin.Denom, res.Balance.Denom) + require.Truef(t, coin.Amount.Equal(res.Balance.Amount), + "expected %s, got %s", coin.Amount, res.Balance.Amount) + } + } rapid.Check(t, func(rt *rapid.T) { addr := testdata.AddressGenerator(rt).Draw(rt, "address") @@ -95,6 +194,434 @@ func TestGRPCQueryBalance(t *testing.T) { req := banktypes.NewQueryBalanceRequest(addrStr, coin.GetDenom()) - testdata.DeterministicIterationsV2(t, f.ctx, nil, req, f.QueryBalance, 0, true) + testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, + f.QueryBalance, assertNonZeroGas, assertBalance(coin)) + }) + + fundAccount(f, addr1, coin1) + addr1Str, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr1) + require.NoError(t, err) + req := banktypes.NewQueryBalanceRequest(addr1Str, coin1.GetDenom()) + testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, + f.QueryBalance, assertNonZeroGas, assertBalance(coin1)) +} + +func TestQueryAllBalances(t *testing.T) { + t.Parallel() + f := initDeterministicFixture(t) + f.ctx = f.app.StateLatestContext(t) + gasMeterFactory := integration.GasMeterFactory(f.ctx) + addressCodec := codectestutil.CodecOptions{}.GetAddressCodec() + + rapid.Check(t, func(rt *rapid.T) { + addr := testdata.AddressGenerator(rt).Draw(rt, "address") + numCoins := rapid.IntRange(1, 10).Draw(rt, "num-count") + coins := make(sdk.Coins, 0, numCoins) + + addrStr, err := addressCodec.BytesToString(addr) + require.NoError(t, err) + + for i := 0; i < numCoins; i++ { + coin := getCoin(rt) + if exists, _ := coins.Find(coin.Denom); exists { + t.Skip("duplicate denom") + } + // NewCoins sorts the denoms + coins = sdk.NewCoins(append(coins, coin)...) + } + + fundAccount(f, addr, coins...) + + req := banktypes.NewQueryAllBalancesRequest( + addrStr, testdata.PaginationGenerator(rt, uint64(numCoins)).Draw(rt, "pagination"), false) + testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, + f.QueryAllBalances, assertNonZeroGas, nil) + }) + + coins := sdk.NewCoins( + sdk.NewCoin("stake", math.NewInt(10)), + sdk.NewCoin("denom", math.NewInt(100)), + ) + + fundAccount(f, addr1, coins...) + addr1Str, err := addressCodec.BytesToString(addr1) + require.NoError(t, err) + + req := banktypes.NewQueryAllBalancesRequest(addr1Str, nil, false) + testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, + f.QueryAllBalances, assertNonZeroGas, nil) +} + +func TestQuerySpendableBalances(t *testing.T) { + t.Parallel() + f := initDeterministicFixture(t) + f.ctx = f.app.StateLatestContext(t) + gasMeterFactory := integration.GasMeterFactory(f.ctx) + + rapid.Check(t, func(rt *rapid.T) { + addr := testdata.AddressGenerator(rt).Draw(rt, "address") + addrStr, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr) + require.NoError(t, err) + + // Denoms must be unique, otherwise sdk.NewCoins will panic. + denoms := rapid.SliceOfNDistinct(rapid.StringMatching(denomRegex), 1, 10, rapid.ID[string]).Draw(rt, "denoms") + coins := make(sdk.Coins, 0, len(denoms)) + for _, denom := range denoms { + coin := sdk.NewCoin( + denom, + math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")), + ) + + // NewCoins sorts the denoms + coins = sdk.NewCoins(append(coins, coin)...) + } + + err = banktestutil.FundAccount(f.ctx, f.bankKeeper, addr, coins) + require.NoError(t, err) + + req := banktypes.NewQuerySpendableBalancesRequest(addrStr, testdata.PaginationGenerator(rt, uint64(len(denoms))).Draw(rt, "pagination")) + testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, + f.QuerySpendableBalances, assertNonZeroGas, nil) + }) + + coins := sdk.NewCoins( + sdk.NewCoin("stake", math.NewInt(10)), + sdk.NewCoin("denom", math.NewInt(100)), + ) + + err := banktestutil.FundAccount(f.ctx, f.bankKeeper, addr1, coins) + require.NoError(t, err) + + addr1Str, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr1) + require.NoError(t, err) + + req := banktypes.NewQuerySpendableBalancesRequest(addr1Str, nil) + testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, + f.QuerySpendableBalances, assertNonZeroGas, nil) +} + +func TestQueryTotalSupply(t *testing.T) { + t.Parallel() + f := initDeterministicFixture(t) + f.ctx = f.app.StateLatestContext(t) + gasMeterFactory := integration.GasMeterFactory(f.ctx) + + res, err := f.QueryTotalSupply(f.ctx, &banktypes.QueryTotalSupplyRequest{}) + require.NoError(t, err) + initialSupply := res.GetSupply() + + rapid.Check(t, func(rt *rapid.T) { + numCoins := rapid.IntRange(1, 3).Draw(rt, "num-count") + coins := make(sdk.Coins, 0, numCoins) + + for i := 0; i < numCoins; i++ { + coin := sdk.NewCoin( + rapid.StringMatching(denomRegex).Draw(rt, "denom"), + math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")), + ) + + coins = coins.Add(coin) + } + + require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, coins)) + + initialSupply = initialSupply.Add(coins...) + + req := &banktypes.QueryTotalSupplyRequest{ + Pagination: testdata.PaginationGenerator(rt, uint64(len(initialSupply))).Draw(rt, "pagination"), + } + + testdata.DeterministicIterationsV2( + t, f.ctx, req, gasMeterFactory, f.QueryTotalSupply, assertNonZeroGas, nil) + }) + + f = initDeterministicFixture(t) // reset + f.ctx = f.app.StateLatestContext(t) + gasMeterFactory = integration.GasMeterFactory(f.ctx) + + coins := sdk.NewCoins( + sdk.NewCoin("foo", math.NewInt(10)), + sdk.NewCoin("bar", math.NewInt(100)), + ) + + require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, coins)) + + req := &banktypes.QueryTotalSupplyRequest{} + testdata.DeterministicIterationsV2( + t, f.ctx, req, gasMeterFactory, f.QueryTotalSupply, assertNonZeroGas, nil) +} + +func TestQueryTotalSupplyOf(t *testing.T) { + t.Parallel() + f := initDeterministicFixture(t) + f.ctx = f.app.StateLatestContext(t) + gasMeterFactory := integration.GasMeterFactory(f.ctx) + + rapid.Check(t, func(rt *rapid.T) { + coin := sdk.NewCoin( + rapid.StringMatching(denomRegex).Draw(rt, "denom"), + math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")), + ) + + require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, sdk.NewCoins(coin))) + + req := &banktypes.QuerySupplyOfRequest{Denom: coin.GetDenom()} + testdata.DeterministicIterationsV2( + t, f.ctx, req, gasMeterFactory, f.QuerySupplyOf, assertNonZeroGas, nil) + }) + + coin := sdk.NewCoin("bar", math.NewInt(100)) + + require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, sdk.NewCoins(coin))) + req := &banktypes.QuerySupplyOfRequest{Denom: coin.GetDenom()} + testdata.DeterministicIterationsV2( + t, f.ctx, req, gasMeterFactory, f.QuerySupplyOf, assertNonZeroGas, nil) +} + +func TestQueryParams(t *testing.T) { + t.Parallel() + f := initDeterministicFixture(t) + f.ctx = f.app.StateLatestContext(t) + gasMeterFactory := integration.GasMeterFactory(f.ctx) + + rapid.Check(t, func(rt *rapid.T) { + enabledStatus := banktypes.SendEnabled{ + Denom: rapid.StringMatching(denomRegex).Draw(rt, "denom"), + Enabled: rapid.Bool().Draw(rt, "status"), + } + + params := banktypes.Params{ + SendEnabled: []*banktypes.SendEnabled{&enabledStatus}, + DefaultSendEnabled: rapid.Bool().Draw(rt, "send"), + } + + err := f.bankKeeper.SetParams(f.ctx, params) + require.NoError(t, err) + + req := &banktypes.QueryParamsRequest{} + testdata.DeterministicIterationsV2( + t, f.ctx, req, gasMeterFactory, f.QueryParams, assertNonZeroGas, nil) + }) + + enabledStatus := banktypes.SendEnabled{ + Denom: "denom", + Enabled: true, + } + + params := banktypes.Params{ + SendEnabled: []*banktypes.SendEnabled{&enabledStatus}, + DefaultSendEnabled: false, + } + + err := f.bankKeeper.SetParams(f.ctx, params) + require.NoError(t, err) + req := &banktypes.QueryParamsRequest{} + testdata.DeterministicIterationsV2( + t, f.ctx, req, gasMeterFactory, f.QueryParams, assertNonZeroGas, nil) +} + +func createAndReturnMetadatas(t *rapid.T, count int) []banktypes.Metadata { + denomsMetadata := make([]banktypes.Metadata, 0, count) + for i := 0; i < count; i++ { + + denom := rapid.StringMatching(denomRegex).Draw(t, "denom") + + aliases := rapid.SliceOf(rapid.String()).Draw(t, "aliases") + // In the GRPC server code, empty arrays are returned as nil + if len(aliases) == 0 { + aliases = nil + } + + metadata := banktypes.Metadata{ + Description: rapid.StringN(1, 100, 100).Draw(t, "desc"), + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: denom, + Exponent: rapid.Uint32().Draw(t, "exponent"), + Aliases: aliases, + }, + }, + Base: denom, + Display: denom, + Name: rapid.String().Draw(t, "name"), + Symbol: rapid.String().Draw(t, "symbol"), + URI: rapid.String().Draw(t, "uri"), + URIHash: rapid.String().Draw(t, "uri-hash"), + } + + denomsMetadata = append(denomsMetadata, metadata) + } + + return denomsMetadata +} + +func TestDenomsMetadata(t *testing.T) { + t.Parallel() + f := initDeterministicFixture(t) + f.ctx = f.app.StateLatestContext(t) + gasMeterFactory := integration.GasMeterFactory(f.ctx) + + rapid.Check(t, func(rt *rapid.T) { + count := rapid.IntRange(1, 3).Draw(rt, "count") + denomsMetadata := createAndReturnMetadatas(rt, count) + require.True(t, len(denomsMetadata) == count) + + for i := 0; i < count; i++ { + f.bankKeeper.SetDenomMetaData(f.ctx, denomsMetadata[i]) + } + + req := &banktypes.QueryDenomsMetadataRequest{ + Pagination: testdata.PaginationGenerator(rt, uint64(count)).Draw(rt, "pagination"), + } + + testdata.DeterministicIterationsV2( + t, f.ctx, req, gasMeterFactory, f.QueryDenomsMetadata, assertNonZeroGas, nil) + }) + + f = initDeterministicFixture(t) // reset + f.ctx = f.app.StateLatestContext(t) + gasMeterFactory = integration.GasMeterFactory(f.ctx) + + f.bankKeeper.SetDenomMetaData(f.ctx, metadataAtom) + + req := &banktypes.QueryDenomsMetadataRequest{} + testdata.DeterministicIterationsV2( + t, f.ctx, req, gasMeterFactory, f.QueryDenomsMetadata, assertNonZeroGas, nil) +} + +func TestDenomMetadata(t *testing.T) { + t.Parallel() + f := initDeterministicFixture(t) + f.ctx = f.app.StateLatestContext(t) + gasMeterFactory := integration.GasMeterFactory(f.ctx) + + rapid.Check(t, func(rt *rapid.T) { + denomMetadata := createAndReturnMetadatas(rt, 1) + require.True(t, len(denomMetadata) == 1) + f.bankKeeper.SetDenomMetaData(f.ctx, denomMetadata[0]) + + req := &banktypes.QueryDenomMetadataRequest{ + Denom: denomMetadata[0].Base, + } + + testdata.DeterministicIterationsV2( + t, f.ctx, req, gasMeterFactory, f.QueryDenomMetadata, assertNonZeroGas, nil) + }) + + f.bankKeeper.SetDenomMetaData(f.ctx, metadataAtom) + + req := &banktypes.QueryDenomMetadataRequest{ + Denom: metadataAtom.Base, + } + + testdata.DeterministicIterationsV2( + t, f.ctx, req, gasMeterFactory, f.QueryDenomMetadata, assertNonZeroGas, nil) +} + +func TestSendEnabled(t *testing.T) { + t.Parallel() + f := initDeterministicFixture(t) + f.ctx = f.app.StateLatestContext(t) + gasMeterFactory := integration.GasMeterFactory(f.ctx) + + allDenoms := []string{} + + rapid.Check(t, func(rt *rapid.T) { + count := rapid.IntRange(0, 10).Draw(rt, "count") + denoms := make([]string, 0, count) + + for i := 0; i < count; i++ { + coin := banktypes.SendEnabled{ + Denom: rapid.StringMatching(denomRegex).Draw(rt, "denom"), + Enabled: rapid.Bool().Draw(rt, "enabled-status"), + } + + f.bankKeeper.SetSendEnabled(f.ctx, coin.Denom, coin.Enabled) + denoms = append(denoms, coin.Denom) + } + + allDenoms = append(allDenoms, denoms...) + + req := &banktypes.QuerySendEnabledRequest{ + Denoms: denoms, + // Pagination is only taken into account when `denoms` is an empty array + Pagination: testdata.PaginationGenerator(rt, uint64(len(allDenoms))).Draw(rt, "pagination"), + } + testdata.DeterministicIterationsV2( + t, f.ctx, req, gasMeterFactory, f.QuerySendEnabled, assertNonZeroGas, nil) + }) + + coin1 := banktypes.SendEnabled{ + Denom: "falsecoin", + Enabled: false, + } + coin2 := banktypes.SendEnabled{ + Denom: "truecoin", + Enabled: true, + } + + f.bankKeeper.SetSendEnabled(f.ctx, coin1.Denom, false) + f.bankKeeper.SetSendEnabled(f.ctx, coin2.Denom, true) + + req := &banktypes.QuerySendEnabledRequest{ + Denoms: []string{coin1.GetDenom(), coin2.GetDenom()}, + } + + testdata.DeterministicIterationsV2( + t, f.ctx, req, gasMeterFactory, f.QuerySendEnabled, assertNonZeroGas, nil) +} + +func TestDenomOwners(t *testing.T) { + t.Parallel() + f := initDeterministicFixture(t) + f.ctx = f.app.StateLatestContext(t) + gasMeterFactory := integration.GasMeterFactory(f.ctx) + + rapid.Check(t, func(rt *rapid.T) { + denom := rapid.StringMatching(denomRegex).Draw(rt, "denom") + numAddr := rapid.IntRange(1, 10).Draw(rt, "number-address") + for i := 0; i < numAddr; i++ { + addr := testdata.AddressGenerator(rt).Draw(rt, "address") + + coin := sdk.NewCoin( + denom, + math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")), + ) + + err := banktestutil.FundAccount(f.ctx, f.bankKeeper, addr, sdk.NewCoins(coin)) + require.NoError(t, err) + } + + req := &banktypes.QueryDenomOwnersRequest{ + Denom: denom, + Pagination: testdata.PaginationGenerator(rt, uint64(numAddr)).Draw(rt, "pagination"), + } + testdata.DeterministicIterationsV2( + t, f.ctx, req, gasMeterFactory, f.QueryDenomOwners, assertNonZeroGas, nil) }) + + denomOwners := []*banktypes.DenomOwner{ + { + Address: "cosmos1qg65a9q6k2sqq7l3ycp428sqqpmqcucgzze299", + Balance: coin1, + }, + { + Address: "cosmos1qglnsqgpq48l7qqzgs8qdshr6fh3gqq9ej3qut", + Balance: coin1, + }, + } + + for i := 0; i < len(denomOwners); i++ { + addr, err := sdk.AccAddressFromBech32(denomOwners[i].Address) + require.NoError(t, err) + + err = banktestutil.FundAccount(f.ctx, f.bankKeeper, addr, sdk.NewCoins(coin1)) + require.NoError(t, err) + } + + req := &banktypes.QueryDenomOwnersRequest{ + Denom: coin1.GetDenom(), + } + testdata.DeterministicIterationsV2( + t, f.ctx, req, gasMeterFactory, f.QueryDenomOwners, assertNonZeroGas, nil) } diff --git a/tests/integration/v2/services.go b/tests/integration/v2/services.go index b1ef3b2760c9..d1af2986968f 100644 --- a/tests/integration/v2/services.go +++ b/tests/integration/v2/services.go @@ -2,6 +2,8 @@ package integration import ( "context" + "cosmossdk.io/core/gas" + stfgas "cosmossdk.io/server/v2/stf/gas" "fmt" "cosmossdk.io/core/comet" @@ -59,16 +61,34 @@ type contextKeyType struct{} var contextKey = contextKeyType{} type integrationContext struct { - state corestore.WriterMap + state corestore.WriterMap + gasMeter gas.Meter +} + +func GasMeterFromContext(ctx context.Context) gas.Meter { + iCtx, ok := ctx.Value(contextKey).(*integrationContext) + if !ok { + return nil + } + return iCtx.gasMeter +} + +func GasMeterFactory(ctx context.Context) func() gas.Meter { + return func() gas.Meter { + return GasMeterFromContext(ctx) + } } func (s storeService) OpenKVStore(ctx context.Context) corestore.KVStore { - iCtx, ok := ctx.Value(contextKey).(integrationContext) + const gasLimit = 100_000 + iCtx, ok := ctx.Value(contextKey).(*integrationContext) if !ok { return s.executionService.OpenKVStore(ctx) } - state, err := iCtx.state.GetWriter(s.actor) + iCtx.gasMeter = stfgas.NewMeter(gasLimit) + writerMap := stfgas.NewMeteredWriterMap(stfgas.DefaultConfig, iCtx.gasMeter, iCtx.state) + state, err := writerMap.GetWriter(s.actor) if err != nil { panic(err) } diff --git a/testutil/testdata/grpc_query.go b/testutil/testdata/grpc_query.go index b4af37bfecbf..973b653231fa 100644 --- a/testutil/testdata/grpc_query.go +++ b/testutil/testdata/grpc_query.go @@ -6,14 +6,15 @@ import ( "fmt" "testing" - "cosmossdk.io/core/gas" + "github.com/cosmos/gogoproto/proto" gogoprotoany "github.com/cosmos/gogoproto/types/any" "github.com/cosmos/gogoproto/types/any/test" - - "github.com/cosmos/gogoproto/proto" + "github.com/stretchr/testify/require" "google.golang.org/grpc" "gotest.tools/v3/assert" + "cosmossdk.io/core/gas" + "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -86,6 +87,7 @@ func DeterministicIterations[request, response proto.Message]( if gasOverwrite { // to handle regressions, i.e. check that gas consumption didn't change gasConsumed = ctx.GasMeter().GasConsumed() - before } + t.Logf("gas consumed: %d", gasConsumed) for i := 0; i < iterCount; i++ { before := ctx.GasMeter().GasConsumed() @@ -99,28 +101,27 @@ func DeterministicIterations[request, response proto.Message]( func DeterministicIterationsV2[request, response proto.Message]( t *testing.T, ctx context.Context, - gasService gas.Service, req request, - grpcFn func(context.Context, request) (response, error), - gasConsumed uint64, - gasOverwrite bool, + meterFn func() gas.Meter, + queryFn func(context.Context, request) (response, error), + assertGas func(*testing.T, gas.Gas), + assertResponse func(*testing.T, response), ) { t.Helper() - consumed := func() uint64 { - return gasService.GasMeter(ctx).Consumed() - } - before := consumed() - prevRes, err := grpcFn(ctx, req) - assert.NilError(t, err) - if gasOverwrite { // to handle regressions, i.e. check that gas consumption didn't change - gasConsumed = consumed() - before - } + prevRes, err := queryFn(ctx, req) + gasMeter := meterFn() + gasConsumed := gasMeter.Consumed() + require.NoError(t, err) + assertGas(t, gasConsumed) for i := 0; i < iterCount; i++ { - before := consumed() - res, err := grpcFn(ctx, req) - assert.Equal(t, consumed()-before, gasConsumed) - assert.NilError(t, err) - assert.DeepEqual(t, res, prevRes) + res, err := queryFn(ctx, req) + require.NoError(t, err) + sameGas := gasMeter.Consumed() + require.Equal(t, gasConsumed, sameGas) + require.Equal(t, res, prevRes) + if assertResponse != nil { + assertResponse(t, res) + } } } From 869a492169fc2295624c736aa14e6a8da1e5bf75 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Fri, 27 Sep 2024 14:32:05 -0500 Subject: [PATCH 50/57] rever gas addition to stf query return --- server/v2/appmanager/appmanager.go | 7 +++---- server/v2/appmanager/types.go | 3 +-- server/v2/stf/stf.go | 7 +++---- .../v2/bank/determinisitic_test.go | 20 +++++++++---------- 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/server/v2/appmanager/appmanager.go b/server/v2/appmanager/appmanager.go index ea490a3e3f69..b9de9d280c39 100644 --- a/server/v2/appmanager/appmanager.go +++ b/server/v2/appmanager/appmanager.go @@ -3,7 +3,6 @@ package appmanager import ( "bytes" "context" - "cosmossdk.io/core/gas" "encoding/json" "errors" "fmt" @@ -138,7 +137,7 @@ func (a AppManager[T]) Simulate(ctx context.Context, tx T) (server.TxResult, cor // CONTRACT: Version must always be provided, if 0, get latest func (a AppManager[T]) Query( ctx context.Context, version uint64, request transaction.Msg, -) (transaction.Msg, gas.Gas, error) { +) (transaction.Msg, error) { var ( queryState corestore.ReaderMap err error @@ -150,7 +149,7 @@ func (a AppManager[T]) Query( _, queryState, err = a.db.StateLatest() } if err != nil { - return nil, 0, err + return nil, err } return a.stf.Query(ctx, queryState, a.config.QueryGasLimit, request) } @@ -160,6 +159,6 @@ func (a AppManager[T]) Query( // and uncommitted state func (a AppManager[T]) QueryWithState( ctx context.Context, state corestore.ReaderMap, request transaction.Msg, -) (transaction.Msg, gas.Gas, error) { +) (transaction.Msg, error) { return a.stf.Query(ctx, state, a.config.QueryGasLimit, request) } diff --git a/server/v2/appmanager/types.go b/server/v2/appmanager/types.go index 990911057342..1e769c13ff9c 100644 --- a/server/v2/appmanager/types.go +++ b/server/v2/appmanager/types.go @@ -3,7 +3,6 @@ package appmanager import ( "context" - "cosmossdk.io/core/gas" "cosmossdk.io/core/server" "cosmossdk.io/core/store" "cosmossdk.io/core/transaction" @@ -40,5 +39,5 @@ type StateTransitionFunction[T transaction.Tx] interface { state store.ReaderMap, gasLimit uint64, req transaction.Msg, - ) (transaction.Msg, gas.Gas, error) + ) (transaction.Msg, error) } diff --git a/server/v2/stf/stf.go b/server/v2/stf/stf.go index b7834acaf726..f8d69e972712 100644 --- a/server/v2/stf/stf.go +++ b/server/v2/stf/stf.go @@ -436,17 +436,16 @@ func (s STF[T]) Query( state store.ReaderMap, gasLimit uint64, req transaction.Msg, -) (transaction.Msg, gas.Gas, error) { +) (transaction.Msg, error) { queryState := s.branchFn(state) hi, err := s.getHeaderInfo(queryState) if err != nil { - return nil, 0, err + return nil, err } queryCtx := s.makeContext(ctx, nil, queryState, internal.ExecModeSimulate) queryCtx.setHeaderInfo(hi) queryCtx.setGasLimit(gasLimit) - res, err := s.queryRouter.Invoke(queryCtx, req) - return res, queryCtx.meter.Consumed(), err + return s.queryRouter.Invoke(queryCtx, req) } // clone clones STF. diff --git a/tests/integration/v2/bank/determinisitic_test.go b/tests/integration/v2/bank/determinisitic_test.go index 59cca8789d21..63e1bcd08391 100644 --- a/tests/integration/v2/bank/determinisitic_test.go +++ b/tests/integration/v2/bank/determinisitic_test.go @@ -57,70 +57,70 @@ type deterministicFixture struct { func (f *deterministicFixture) QueryBalance( ctx context.Context, req *banktypes.QueryBalanceRequest, ) (*banktypes.QueryBalanceResponse, error) { - res, _, err := f.app.Query(ctx, 0, req) + res, err := f.app.Query(ctx, 0, req) return res.(*banktypes.QueryBalanceResponse), err } func (f *deterministicFixture) QueryAllBalances( ctx context.Context, req *banktypes.QueryAllBalancesRequest, ) (*banktypes.QueryAllBalancesResponse, error) { - res, _, err := f.app.Query(ctx, 0, req) + res, err := f.app.Query(ctx, 0, req) return res.(*banktypes.QueryAllBalancesResponse), err } func (f *deterministicFixture) QuerySpendableBalances( ctx context.Context, req *banktypes.QuerySpendableBalancesRequest, ) (*banktypes.QuerySpendableBalancesResponse, error) { - res, _, err := f.app.Query(ctx, 0, req) + res, err := f.app.Query(ctx, 0, req) return res.(*banktypes.QuerySpendableBalancesResponse), err } func (f *deterministicFixture) QueryTotalSupply( ctx context.Context, req *banktypes.QueryTotalSupplyRequest, ) (*banktypes.QueryTotalSupplyResponse, error) { - res, _, err := f.app.Query(ctx, 0, req) + res, err := f.app.Query(ctx, 0, req) return res.(*banktypes.QueryTotalSupplyResponse), err } func (f *deterministicFixture) QuerySupplyOf( ctx context.Context, req *banktypes.QuerySupplyOfRequest, ) (*banktypes.QuerySupplyOfResponse, error) { - res, _, err := f.app.Query(ctx, 0, req) + res, err := f.app.Query(ctx, 0, req) return res.(*banktypes.QuerySupplyOfResponse), err } func (f *deterministicFixture) QueryParams( ctx context.Context, req *banktypes.QueryParamsRequest, ) (*banktypes.QueryParamsResponse, error) { - res, _, err := f.app.Query(ctx, 0, req) + res, err := f.app.Query(ctx, 0, req) return res.(*banktypes.QueryParamsResponse), err } func (f *deterministicFixture) QueryDenomsMetadata( ctx context.Context, req *banktypes.QueryDenomsMetadataRequest, ) (*banktypes.QueryDenomsMetadataResponse, error) { - res, _, err := f.app.Query(ctx, 0, req) + res, err := f.app.Query(ctx, 0, req) return res.(*banktypes.QueryDenomsMetadataResponse), err } func (f *deterministicFixture) QueryDenomMetadata( ctx context.Context, req *banktypes.QueryDenomMetadataRequest, ) (*banktypes.QueryDenomMetadataResponse, error) { - res, _, err := f.app.Query(ctx, 0, req) + res, err := f.app.Query(ctx, 0, req) return res.(*banktypes.QueryDenomMetadataResponse), err } func (f *deterministicFixture) QuerySendEnabled( ctx context.Context, req *banktypes.QuerySendEnabledRequest, ) (*banktypes.QuerySendEnabledResponse, error) { - res, _, err := f.app.Query(ctx, 0, req) + res, err := f.app.Query(ctx, 0, req) return res.(*banktypes.QuerySendEnabledResponse), err } func (f *deterministicFixture) QueryDenomOwners( ctx context.Context, req *banktypes.QueryDenomOwnersRequest, ) (*banktypes.QueryDenomOwnersResponse, error) { - res, _, err := f.app.Query(ctx, 0, req) + res, err := f.app.Query(ctx, 0, req) return res.(*banktypes.QueryDenomOwnersResponse), err } From a8f7d8ebb60ade0c55f219abf40c0102992b03ec Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Fri, 27 Sep 2024 15:18:48 -0500 Subject: [PATCH 51/57] clean up --- server/v2/cometbft/abci.go | 2 +- server/v2/cometbft/handlers/defaults.go | 25 +-- .../v2/bank/determinisitic_test.go | 151 +++++------------- testutil/testdata/grpc_query.go | 7 +- 4 files changed, 52 insertions(+), 133 deletions(-) diff --git a/server/v2/cometbft/abci.go b/server/v2/cometbft/abci.go index e883852e38c2..18ba8dcebf9c 100644 --- a/server/v2/cometbft/abci.go +++ b/server/v2/cometbft/abci.go @@ -200,7 +200,7 @@ func (c *Consensus[T]) Query( if err != nil { return nil, fmt.Errorf("unable to decode gRPC request with path %s from ABCI.Query: %w", req.Path, err) } - res, _, err := c.app.Query(ctx, uint64(req.Height), protoRequest) + res, err := c.app.Query(ctx, uint64(req.Height), protoRequest) if err != nil { resp := QueryResult(err, c.cfg.AppTomlConfig.Trace) resp.Height = req.Height diff --git a/server/v2/cometbft/handlers/defaults.go b/server/v2/cometbft/handlers/defaults.go index 740c8ec46f20..d8f43bb2fd25 100644 --- a/server/v2/cometbft/handlers/defaults.go +++ b/server/v2/cometbft/handlers/defaults.go @@ -2,7 +2,6 @@ package handlers import ( "context" - "cosmossdk.io/core/gas" "errors" "fmt" @@ -17,9 +16,7 @@ import ( type AppManager[T transaction.Tx] interface { ValidateTx(ctx context.Context, tx T) (server.TxResult, error) - Query( - ctx context.Context, version uint64, request transaction.Msg, - ) (response transaction.Msg, gas gas.Gas, err error) + Query(ctx context.Context, version uint64, request transaction.Msg) (response transaction.Msg, err error) } type DefaultProposalHandler[T transaction.Tx] struct { @@ -35,12 +32,10 @@ func NewDefaultProposalHandler[T transaction.Tx](mp mempool.Mempool[T]) *Default } func (h *DefaultProposalHandler[T]) PrepareHandler() PrepareHandler[T] { - return func( - ctx context.Context, app AppManager[T], codec transaction.Codec[T], req *abci.PrepareProposalRequest, - ) ([]T, error) { + return func(ctx context.Context, app AppManager[T], codec transaction.Codec[T], req *abci.PrepareProposalRequest) ([]T, error) { var maxBlockGas uint64 - res, _, err := app.Query(ctx, 0, &consensustypes.QueryParamsRequest{}) + res, err := app.Query(ctx, 0, &consensustypes.QueryParamsRequest{}) if err != nil { return nil, err } @@ -103,9 +98,7 @@ func (h *DefaultProposalHandler[T]) PrepareHandler() PrepareHandler[T] { } func (h *DefaultProposalHandler[T]) ProcessHandler() ProcessHandler[T] { - return func( - ctx context.Context, app AppManager[T], codec transaction.Codec[T], req *abci.ProcessProposalRequest, - ) error { + return func(ctx context.Context, app AppManager[T], codec transaction.Codec[T], req *abci.ProcessProposalRequest) error { // If the mempool is nil we simply return ACCEPT, // because PrepareProposal may have included txs that could fail verification. _, isNoOp := h.mempool.(mempool.NoOpMempool[T]) @@ -113,7 +106,7 @@ func (h *DefaultProposalHandler[T]) ProcessHandler() ProcessHandler[T] { return nil } - res, _, err := app.Query(ctx, 0, &consensustypes.QueryParamsRequest{}) + res, err := app.Query(ctx, 0, &consensustypes.QueryParamsRequest{}) if err != nil { return err } @@ -181,9 +174,7 @@ func decodeTxs[T transaction.Tx](codec transaction.Codec[T], txsBz [][]byte) []T // NoOpPrepareProposal defines a no-op PrepareProposal handler. It will always // return the transactions sent by the client's request. func NoOpPrepareProposal[T transaction.Tx]() PrepareHandler[T] { - return func( - ctx context.Context, app AppManager[T], codec transaction.Codec[T], req *abci.PrepareProposalRequest, - ) ([]T, error) { + return func(ctx context.Context, app AppManager[T], codec transaction.Codec[T], req *abci.PrepareProposalRequest) ([]T, error) { return decodeTxs(codec, req.Txs), nil } } @@ -207,9 +198,7 @@ func NoOpExtendVote() ExtendVoteHandler { // NoOpVerifyVoteExtensionHandler defines a no-op VerifyVoteExtension handler. It // will always return an ACCEPT status with no error. func NoOpVerifyVoteExtensionHandler() VerifyVoteExtensionhandler { - return func(context.Context, store.ReaderMap, *abci.VerifyVoteExtensionRequest) ( - *abci.VerifyVoteExtensionResponse, error, - ) { + return func(context.Context, store.ReaderMap, *abci.VerifyVoteExtensionRequest) (*abci.VerifyVoteExtensionResponse, error) { return &abci.VerifyVoteExtensionResponse{Status: abci.VERIFY_VOTE_EXTENSION_STATUS_ACCEPT}, nil } } diff --git a/tests/integration/v2/bank/determinisitic_test.go b/tests/integration/v2/bank/determinisitic_test.go index 63e1bcd08391..9a59325d8461 100644 --- a/tests/integration/v2/bank/determinisitic_test.go +++ b/tests/integration/v2/bank/determinisitic_test.go @@ -4,6 +4,7 @@ import ( "context" "cosmossdk.io/core/gas" minttypes "cosmossdk.io/x/mint/types" + "github.com/cosmos/gogoproto/proto" "testing" "github.com/golang/mock/gomock" @@ -54,74 +55,13 @@ type deterministicFixture struct { bankKeeper bankkeeper.Keeper } -func (f *deterministicFixture) QueryBalance( - ctx context.Context, req *banktypes.QueryBalanceRequest, -) (*banktypes.QueryBalanceResponse, error) { - res, err := f.app.Query(ctx, 0, req) - return res.(*banktypes.QueryBalanceResponse), err -} - -func (f *deterministicFixture) QueryAllBalances( - ctx context.Context, req *banktypes.QueryAllBalancesRequest, -) (*banktypes.QueryAllBalancesResponse, error) { - res, err := f.app.Query(ctx, 0, req) - return res.(*banktypes.QueryAllBalancesResponse), err -} - -func (f *deterministicFixture) QuerySpendableBalances( - ctx context.Context, req *banktypes.QuerySpendableBalancesRequest, -) (*banktypes.QuerySpendableBalancesResponse, error) { - res, err := f.app.Query(ctx, 0, req) - return res.(*banktypes.QuerySpendableBalancesResponse), err -} - -func (f *deterministicFixture) QueryTotalSupply( - ctx context.Context, req *banktypes.QueryTotalSupplyRequest, -) (*banktypes.QueryTotalSupplyResponse, error) { - res, err := f.app.Query(ctx, 0, req) - return res.(*banktypes.QueryTotalSupplyResponse), err -} - -func (f *deterministicFixture) QuerySupplyOf( - ctx context.Context, req *banktypes.QuerySupplyOfRequest, -) (*banktypes.QuerySupplyOfResponse, error) { - res, err := f.app.Query(ctx, 0, req) - return res.(*banktypes.QuerySupplyOfResponse), err -} - -func (f *deterministicFixture) QueryParams( - ctx context.Context, req *banktypes.QueryParamsRequest, -) (*banktypes.QueryParamsResponse, error) { - res, err := f.app.Query(ctx, 0, req) - return res.(*banktypes.QueryParamsResponse), err -} - -func (f *deterministicFixture) QueryDenomsMetadata( - ctx context.Context, req *banktypes.QueryDenomsMetadataRequest, -) (*banktypes.QueryDenomsMetadataResponse, error) { - res, err := f.app.Query(ctx, 0, req) - return res.(*banktypes.QueryDenomsMetadataResponse), err -} - -func (f *deterministicFixture) QueryDenomMetadata( - ctx context.Context, req *banktypes.QueryDenomMetadataRequest, -) (*banktypes.QueryDenomMetadataResponse, error) { - res, err := f.app.Query(ctx, 0, req) - return res.(*banktypes.QueryDenomMetadataResponse), err -} - -func (f *deterministicFixture) QuerySendEnabled( - ctx context.Context, req *banktypes.QuerySendEnabledRequest, -) (*banktypes.QuerySendEnabledResponse, error) { - res, err := f.app.Query(ctx, 0, req) - return res.(*banktypes.QuerySendEnabledResponse), err -} - -func (f *deterministicFixture) QueryDenomOwners( - ctx context.Context, req *banktypes.QueryDenomOwnersRequest, -) (*banktypes.QueryDenomOwnersResponse, error) { - res, err := f.app.Query(ctx, 0, req) - return res.(*banktypes.QueryDenomOwnersResponse), err +func queryFnFactory[RequestT, ResponseT proto.Message]( + f *deterministicFixture, +) func(RequestT) (ResponseT, error) { + return func(req RequestT) (ResponseT, error) { + res, err := f.app.Query(f.ctx, 0, req) + return res.(ResponseT), err + } } func fundAccount(f *deterministicFixture, addr sdk.AccAddress, coin ...sdk.Coin) { @@ -176,6 +116,7 @@ func TestQueryBalance(t *testing.T) { f := initDeterministicFixture(t) f.ctx = f.app.StateLatestContext(t) gasMeterFactory := integration.GasMeterFactory(f.ctx) + queryFn := queryFnFactory[*banktypes.QueryBalanceRequest, *banktypes.QueryBalanceResponse](f) assertBalance := func(coin sdk.Coin) func(t *testing.T, res *banktypes.QueryBalanceResponse) { return func(t *testing.T, res *banktypes.QueryBalanceResponse) { require.Equal(t, coin.Denom, res.Balance.Denom) @@ -194,16 +135,14 @@ func TestQueryBalance(t *testing.T) { req := banktypes.NewQueryBalanceRequest(addrStr, coin.GetDenom()) - testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, - f.QueryBalance, assertNonZeroGas, assertBalance(coin)) + testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, assertBalance(coin)) }) fundAccount(f, addr1, coin1) addr1Str, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr1) require.NoError(t, err) req := banktypes.NewQueryBalanceRequest(addr1Str, coin1.GetDenom()) - testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, - f.QueryBalance, assertNonZeroGas, assertBalance(coin1)) + testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, assertBalance(coin1)) } func TestQueryAllBalances(t *testing.T) { @@ -212,6 +151,7 @@ func TestQueryAllBalances(t *testing.T) { f.ctx = f.app.StateLatestContext(t) gasMeterFactory := integration.GasMeterFactory(f.ctx) addressCodec := codectestutil.CodecOptions{}.GetAddressCodec() + queryFn := queryFnFactory[*banktypes.QueryAllBalancesRequest, *banktypes.QueryAllBalancesResponse](f) rapid.Check(t, func(rt *rapid.T) { addr := testdata.AddressGenerator(rt).Draw(rt, "address") @@ -234,8 +174,7 @@ func TestQueryAllBalances(t *testing.T) { req := banktypes.NewQueryAllBalancesRequest( addrStr, testdata.PaginationGenerator(rt, uint64(numCoins)).Draw(rt, "pagination"), false) - testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, - f.QueryAllBalances, assertNonZeroGas, nil) + testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil) }) coins := sdk.NewCoins( @@ -248,8 +187,7 @@ func TestQueryAllBalances(t *testing.T) { require.NoError(t, err) req := banktypes.NewQueryAllBalancesRequest(addr1Str, nil, false) - testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, - f.QueryAllBalances, assertNonZeroGas, nil) + testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil) } func TestQuerySpendableBalances(t *testing.T) { @@ -257,6 +195,7 @@ func TestQuerySpendableBalances(t *testing.T) { f := initDeterministicFixture(t) f.ctx = f.app.StateLatestContext(t) gasMeterFactory := integration.GasMeterFactory(f.ctx) + queryFn := queryFnFactory[*banktypes.QuerySpendableBalancesRequest, *banktypes.QuerySpendableBalancesResponse](f) rapid.Check(t, func(rt *rapid.T) { addr := testdata.AddressGenerator(rt).Draw(rt, "address") @@ -280,8 +219,7 @@ func TestQuerySpendableBalances(t *testing.T) { require.NoError(t, err) req := banktypes.NewQuerySpendableBalancesRequest(addrStr, testdata.PaginationGenerator(rt, uint64(len(denoms))).Draw(rt, "pagination")) - testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, - f.QuerySpendableBalances, assertNonZeroGas, nil) + testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil) }) coins := sdk.NewCoins( @@ -296,8 +234,7 @@ func TestQuerySpendableBalances(t *testing.T) { require.NoError(t, err) req := banktypes.NewQuerySpendableBalancesRequest(addr1Str, nil) - testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, - f.QuerySpendableBalances, assertNonZeroGas, nil) + testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil) } func TestQueryTotalSupply(t *testing.T) { @@ -305,8 +242,9 @@ func TestQueryTotalSupply(t *testing.T) { f := initDeterministicFixture(t) f.ctx = f.app.StateLatestContext(t) gasMeterFactory := integration.GasMeterFactory(f.ctx) + queryFn := queryFnFactory[*banktypes.QueryTotalSupplyRequest, *banktypes.QueryTotalSupplyResponse](f) - res, err := f.QueryTotalSupply(f.ctx, &banktypes.QueryTotalSupplyRequest{}) + res, err := queryFn(&banktypes.QueryTotalSupplyRequest{}) require.NoError(t, err) initialSupply := res.GetSupply() @@ -331,13 +269,13 @@ func TestQueryTotalSupply(t *testing.T) { Pagination: testdata.PaginationGenerator(rt, uint64(len(initialSupply))).Draw(rt, "pagination"), } - testdata.DeterministicIterationsV2( - t, f.ctx, req, gasMeterFactory, f.QueryTotalSupply, assertNonZeroGas, nil) + testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil) }) f = initDeterministicFixture(t) // reset f.ctx = f.app.StateLatestContext(t) gasMeterFactory = integration.GasMeterFactory(f.ctx) + queryFn = queryFnFactory[*banktypes.QueryTotalSupplyRequest, *banktypes.QueryTotalSupplyResponse](f) coins := sdk.NewCoins( sdk.NewCoin("foo", math.NewInt(10)), @@ -347,8 +285,7 @@ func TestQueryTotalSupply(t *testing.T) { require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, coins)) req := &banktypes.QueryTotalSupplyRequest{} - testdata.DeterministicIterationsV2( - t, f.ctx, req, gasMeterFactory, f.QueryTotalSupply, assertNonZeroGas, nil) + testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil) } func TestQueryTotalSupplyOf(t *testing.T) { @@ -356,6 +293,7 @@ func TestQueryTotalSupplyOf(t *testing.T) { f := initDeterministicFixture(t) f.ctx = f.app.StateLatestContext(t) gasMeterFactory := integration.GasMeterFactory(f.ctx) + queryFn := queryFnFactory[*banktypes.QuerySupplyOfRequest, *banktypes.QuerySupplyOfResponse](f) rapid.Check(t, func(rt *rapid.T) { coin := sdk.NewCoin( @@ -366,16 +304,14 @@ func TestQueryTotalSupplyOf(t *testing.T) { require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, sdk.NewCoins(coin))) req := &banktypes.QuerySupplyOfRequest{Denom: coin.GetDenom()} - testdata.DeterministicIterationsV2( - t, f.ctx, req, gasMeterFactory, f.QuerySupplyOf, assertNonZeroGas, nil) + testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil) }) coin := sdk.NewCoin("bar", math.NewInt(100)) require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, sdk.NewCoins(coin))) req := &banktypes.QuerySupplyOfRequest{Denom: coin.GetDenom()} - testdata.DeterministicIterationsV2( - t, f.ctx, req, gasMeterFactory, f.QuerySupplyOf, assertNonZeroGas, nil) + testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil) } func TestQueryParams(t *testing.T) { @@ -383,6 +319,7 @@ func TestQueryParams(t *testing.T) { f := initDeterministicFixture(t) f.ctx = f.app.StateLatestContext(t) gasMeterFactory := integration.GasMeterFactory(f.ctx) + queryFn := queryFnFactory[*banktypes.QueryParamsRequest, *banktypes.QueryParamsResponse](f) rapid.Check(t, func(rt *rapid.T) { enabledStatus := banktypes.SendEnabled{ @@ -399,8 +336,7 @@ func TestQueryParams(t *testing.T) { require.NoError(t, err) req := &banktypes.QueryParamsRequest{} - testdata.DeterministicIterationsV2( - t, f.ctx, req, gasMeterFactory, f.QueryParams, assertNonZeroGas, nil) + testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil) }) enabledStatus := banktypes.SendEnabled{ @@ -416,8 +352,7 @@ func TestQueryParams(t *testing.T) { err := f.bankKeeper.SetParams(f.ctx, params) require.NoError(t, err) req := &banktypes.QueryParamsRequest{} - testdata.DeterministicIterationsV2( - t, f.ctx, req, gasMeterFactory, f.QueryParams, assertNonZeroGas, nil) + testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil) } func createAndReturnMetadatas(t *rapid.T, count int) []banktypes.Metadata { @@ -460,6 +395,7 @@ func TestDenomsMetadata(t *testing.T) { f := initDeterministicFixture(t) f.ctx = f.app.StateLatestContext(t) gasMeterFactory := integration.GasMeterFactory(f.ctx) + queryFn := queryFnFactory[*banktypes.QueryDenomsMetadataRequest, *banktypes.QueryDenomsMetadataResponse](f) rapid.Check(t, func(rt *rapid.T) { count := rapid.IntRange(1, 3).Draw(rt, "count") @@ -474,19 +410,18 @@ func TestDenomsMetadata(t *testing.T) { Pagination: testdata.PaginationGenerator(rt, uint64(count)).Draw(rt, "pagination"), } - testdata.DeterministicIterationsV2( - t, f.ctx, req, gasMeterFactory, f.QueryDenomsMetadata, assertNonZeroGas, nil) + testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil) }) f = initDeterministicFixture(t) // reset f.ctx = f.app.StateLatestContext(t) gasMeterFactory = integration.GasMeterFactory(f.ctx) + queryFn = queryFnFactory[*banktypes.QueryDenomsMetadataRequest, *banktypes.QueryDenomsMetadataResponse](f) f.bankKeeper.SetDenomMetaData(f.ctx, metadataAtom) req := &banktypes.QueryDenomsMetadataRequest{} - testdata.DeterministicIterationsV2( - t, f.ctx, req, gasMeterFactory, f.QueryDenomsMetadata, assertNonZeroGas, nil) + testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil) } func TestDenomMetadata(t *testing.T) { @@ -494,6 +429,7 @@ func TestDenomMetadata(t *testing.T) { f := initDeterministicFixture(t) f.ctx = f.app.StateLatestContext(t) gasMeterFactory := integration.GasMeterFactory(f.ctx) + queryFn := queryFnFactory[*banktypes.QueryDenomMetadataRequest, *banktypes.QueryDenomMetadataResponse](f) rapid.Check(t, func(rt *rapid.T) { denomMetadata := createAndReturnMetadatas(rt, 1) @@ -504,8 +440,7 @@ func TestDenomMetadata(t *testing.T) { Denom: denomMetadata[0].Base, } - testdata.DeterministicIterationsV2( - t, f.ctx, req, gasMeterFactory, f.QueryDenomMetadata, assertNonZeroGas, nil) + testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil) }) f.bankKeeper.SetDenomMetaData(f.ctx, metadataAtom) @@ -514,8 +449,7 @@ func TestDenomMetadata(t *testing.T) { Denom: metadataAtom.Base, } - testdata.DeterministicIterationsV2( - t, f.ctx, req, gasMeterFactory, f.QueryDenomMetadata, assertNonZeroGas, nil) + testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil) } func TestSendEnabled(t *testing.T) { @@ -523,7 +457,7 @@ func TestSendEnabled(t *testing.T) { f := initDeterministicFixture(t) f.ctx = f.app.StateLatestContext(t) gasMeterFactory := integration.GasMeterFactory(f.ctx) - + queryFn := queryFnFactory[*banktypes.QuerySendEnabledRequest, *banktypes.QuerySendEnabledResponse](f) allDenoms := []string{} rapid.Check(t, func(rt *rapid.T) { @@ -547,8 +481,7 @@ func TestSendEnabled(t *testing.T) { // Pagination is only taken into account when `denoms` is an empty array Pagination: testdata.PaginationGenerator(rt, uint64(len(allDenoms))).Draw(rt, "pagination"), } - testdata.DeterministicIterationsV2( - t, f.ctx, req, gasMeterFactory, f.QuerySendEnabled, assertNonZeroGas, nil) + testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil) }) coin1 := banktypes.SendEnabled{ @@ -567,8 +500,7 @@ func TestSendEnabled(t *testing.T) { Denoms: []string{coin1.GetDenom(), coin2.GetDenom()}, } - testdata.DeterministicIterationsV2( - t, f.ctx, req, gasMeterFactory, f.QuerySendEnabled, assertNonZeroGas, nil) + testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil) } func TestDenomOwners(t *testing.T) { @@ -576,6 +508,7 @@ func TestDenomOwners(t *testing.T) { f := initDeterministicFixture(t) f.ctx = f.app.StateLatestContext(t) gasMeterFactory := integration.GasMeterFactory(f.ctx) + queryFn := queryFnFactory[*banktypes.QueryDenomOwnersRequest, *banktypes.QueryDenomOwnersResponse](f) rapid.Check(t, func(rt *rapid.T) { denom := rapid.StringMatching(denomRegex).Draw(rt, "denom") @@ -596,8 +529,7 @@ func TestDenomOwners(t *testing.T) { Denom: denom, Pagination: testdata.PaginationGenerator(rt, uint64(numAddr)).Draw(rt, "pagination"), } - testdata.DeterministicIterationsV2( - t, f.ctx, req, gasMeterFactory, f.QueryDenomOwners, assertNonZeroGas, nil) + testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil) }) denomOwners := []*banktypes.DenomOwner{ @@ -622,6 +554,5 @@ func TestDenomOwners(t *testing.T) { req := &banktypes.QueryDenomOwnersRequest{ Denom: coin1.GetDenom(), } - testdata.DeterministicIterationsV2( - t, f.ctx, req, gasMeterFactory, f.QueryDenomOwners, assertNonZeroGas, nil) + testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil) } diff --git a/testutil/testdata/grpc_query.go b/testutil/testdata/grpc_query.go index 973b653231fa..beda71db44c9 100644 --- a/testutil/testdata/grpc_query.go +++ b/testutil/testdata/grpc_query.go @@ -100,22 +100,21 @@ func DeterministicIterations[request, response proto.Message]( func DeterministicIterationsV2[request, response proto.Message]( t *testing.T, - ctx context.Context, req request, meterFn func() gas.Meter, - queryFn func(context.Context, request) (response, error), + queryFn func(request) (response, error), assertGas func(*testing.T, gas.Gas), assertResponse func(*testing.T, response), ) { t.Helper() - prevRes, err := queryFn(ctx, req) + prevRes, err := queryFn(req) gasMeter := meterFn() gasConsumed := gasMeter.Consumed() require.NoError(t, err) assertGas(t, gasConsumed) for i := 0; i < iterCount; i++ { - res, err := queryFn(ctx, req) + res, err := queryFn(req) require.NoError(t, err) sameGas := gasMeter.Consumed() require.Equal(t, gasConsumed, sameGas) From 6a9e8036c06c395a88704a35305ed50ce3cf1509 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Fri, 27 Sep 2024 15:22:05 -0500 Subject: [PATCH 52/57] revert whitespace --- server/v2/cometbft/abci.go | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/server/v2/cometbft/abci.go b/server/v2/cometbft/abci.go index 18ba8dcebf9c..85b38e4ccc65 100644 --- a/server/v2/cometbft/abci.go +++ b/server/v2/cometbft/abci.go @@ -189,9 +189,7 @@ func (c *Consensus[T]) Info(ctx context.Context, _ *abciproto.InfoRequest) (*abc // Query implements types.Application. // It is called by cometbft to query application state. -func (c *Consensus[T]) Query( - ctx context.Context, req *abciproto.QueryRequest, -) (resp *abciproto.QueryResponse, err error) { +func (c *Consensus[T]) Query(ctx context.Context, req *abciproto.QueryRequest) (resp *abciproto.QueryResponse, err error) { // check if it's a gRPC method makeGRPCRequest, isGRPC := c.grpcMethodsMap[req.Path] if isGRPC { @@ -240,9 +238,7 @@ func (c *Consensus[T]) Query( } // InitChain implements types.Application. -func (c *Consensus[T]) InitChain(ctx context.Context, req *abciproto.InitChainRequest) ( - *abciproto.InitChainResponse, error, -) { +func (c *Consensus[T]) InitChain(ctx context.Context, req *abciproto.InitChainRequest) (*abciproto.InitChainResponse, error) { c.logger.Info("InitChain", "initialHeight", req.InitialHeight, "chainID", req.ChainId) // store chainID to be used later on in execution @@ -558,9 +554,7 @@ func (c *Consensus[T]) VerifyVoteExtension( } // ExtendVote implements types.Application. -func (c *Consensus[T]) ExtendVote(ctx context.Context, req *abciproto.ExtendVoteRequest) ( - *abciproto.ExtendVoteResponse, error, -) { +func (c *Consensus[T]) ExtendVote(ctx context.Context, req *abciproto.ExtendVoteRequest) (*abciproto.ExtendVoteResponse, error) { // If vote extensions are not enabled, as a safety precaution, we return an // error. cp, err := c.GetConsensusParams(ctx) From 9cf71f4afed96197940037140b6d0f773a1f8ffa Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 30 Sep 2024 11:52:48 -0500 Subject: [PATCH 53/57] godocs --- runtime/v2/module.go | 9 ++++++--- server/v2/appmanager/appmanager.go | 4 +--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/runtime/v2/module.go b/runtime/v2/module.go index a8fb394419fc..8e8b7e0ce832 100644 --- a/runtime/v2/module.go +++ b/runtime/v2/module.go @@ -149,9 +149,12 @@ type AppInputs struct { InterfaceRegistrar registry.InterfaceRegistrar LegacyAmino registry.AminoRegistrar Logger log.Logger - StoreBuilder *StoreBuilder - DynamicConfig server.DynamicConfig `optional:"true"` // can be nil in client wiring - StoreOptions *rootstore.Options `optional:"true"` // if unset defaults will be used + // StoreBuilder is a builder for a store/v2 RootStore satisfying the Store interface + StoreBuilder *StoreBuilder + // StoreOptions are required as input for the StoreBuilder. If not provided, the default options are used. + StoreOptions *rootstore.Options `optional:"true"` + // DynamicConfig can be nil in client wiring, but is required in server wiring. + DynamicConfig server.DynamicConfig `optional:"true"` } func SetupAppBuilder(inputs AppInputs) { diff --git a/server/v2/appmanager/appmanager.go b/server/v2/appmanager/appmanager.go index b9de9d280c39..436c3f345a40 100644 --- a/server/v2/appmanager/appmanager.go +++ b/server/v2/appmanager/appmanager.go @@ -135,9 +135,7 @@ func (a AppManager[T]) Simulate(ctx context.Context, tx T) (server.TxResult, cor // Query queries the application at the provided version. // CONTRACT: Version must always be provided, if 0, get latest -func (a AppManager[T]) Query( - ctx context.Context, version uint64, request transaction.Msg, -) (transaction.Msg, error) { +func (a AppManager[T]) Query(ctx context.Context, version uint64, request transaction.Msg) (transaction.Msg, error) { var ( queryState corestore.ReaderMap err error From 47136de93c7523b75cae9babb468550342ed77e5 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 30 Sep 2024 11:58:57 -0500 Subject: [PATCH 54/57] runtime/v2 clean up --- runtime/v2/store.go | 3 ++- runtime/v2/types.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/runtime/v2/store.go b/runtime/v2/store.go index 08d86bfd2c82..a41e86b8d3ca 100644 --- a/runtime/v2/store.go +++ b/runtime/v2/store.go @@ -79,7 +79,7 @@ func (sb *StoreBuilder) Build( if sb.store != nil { return sb.store, nil } - home := config.GetString(FlagHome) + home := config.GetString(flagHome) scRawDb, err := db.NewDB( db.DBType(config.GetString("store.app-db-backend")), "application", @@ -106,6 +106,7 @@ func (sb *StoreBuilder) Build( return sb.store, nil } +// Get returns the Store. Build must be called before calling Get or the result will be nil. func (sb *StoreBuilder) Get() Store { return sb.store } diff --git a/runtime/v2/types.go b/runtime/v2/types.go index baa20182b512..9018af921b1c 100644 --- a/runtime/v2/types.go +++ b/runtime/v2/types.go @@ -14,7 +14,7 @@ import ( const ( ModuleName = "runtime" - FlagHome = "home" + flagHome = "home" ) // validateProtoAnnotations validates that the proto annotations are correct. From 52c502ad4ac1c78e0ed099f87e6d031d7ec19d26 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 30 Sep 2024 12:02:35 -0500 Subject: [PATCH 55/57] add comment --- simapp/v2/app_di.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/simapp/v2/app_di.go b/simapp/v2/app_di.go index 3ccd1b9020ab..ff29df3c98d2 100644 --- a/simapp/v2/app_di.go +++ b/simapp/v2/app_di.go @@ -126,6 +126,10 @@ func NewSimApp[T transaction.Tx]( ) ) + // the subsection of config that contains the store options (in app.toml [store.options] header) + // is unmarshaled into a store.Options struct and passed to the store builder. + // future work may move this specification and retrieval into store/v2. + // If these options are not specified then default values will be used. if sub := viper.Sub("store.options"); sub != nil { storeOptions := &root.Options{} err := sub.Unmarshal(storeOptions) From 8d34c75e151a24b29b66569bbb719a954a686285 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 30 Sep 2024 12:24:44 -0500 Subject: [PATCH 56/57] clean up --- tests/integration/v2/app.go | 21 +++++++++++-------- tests/integration/v2/bank/app_test.go | 2 -- .../v2/bank/determinisitic_test.go | 18 ++++++++++++---- tests/integration/v2/services.go | 7 +++---- 4 files changed, 29 insertions(+), 19 deletions(-) diff --git a/tests/integration/v2/app.go b/tests/integration/v2/app.go index f7e956ec63bd..87b536c83bb3 100644 --- a/tests/integration/v2/app.go +++ b/tests/integration/v2/app.go @@ -74,17 +74,18 @@ var DefaultConsensusParams = &cmtproto.ConsensusParams{ }, } -// StartupConfig defines the startup configuration new a test application. -// -// ValidatorSet defines a custom validator set to be validating the app. -// BaseAppOption defines the additional operations that must be run on baseapp before app start. -// AtGenesis defines if the app started should already have produced block or not. +// StartupConfig defines the startup configuration of a new test app. type StartupConfig struct { - ValidatorSet func() (*cmttypes.ValidatorSet, error) - AppOption runtime.AppBuilderOption[stateMachineTx] + // ValidatorSet defines a custom validator set to be validating the app. + ValidatorSet func() (*cmttypes.ValidatorSet, error) + // AppOption defines the additional operations that will be run in the app builder phase. + AppOption runtime.AppBuilderOption[stateMachineTx] + // GenesisBehavior defines the behavior of the app at genesis. GenesisBehavior int + // GenesisAccounts defines the genesis accounts to be used in the app. GenesisAccounts []GenesisAccount - HomeDir string + // HomeDir defines the home directory of the app where config and data will be stored. + HomeDir string } func DefaultStartUpConfig(t *testing.T) StartupConfig { @@ -103,11 +104,13 @@ func DefaultStartUpConfig(t *testing.T) StartupConfig { sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100000000000000)), ), } + homedir := t.TempDir() + t.Logf("generated integration test app config; HomeDir=%s", homedir) return StartupConfig{ ValidatorSet: CreateRandomValidatorSet, GenesisBehavior: Genesis_COMMIT, GenesisAccounts: []GenesisAccount{ga}, - HomeDir: t.TempDir(), + HomeDir: homedir, } } diff --git a/tests/integration/v2/bank/app_test.go b/tests/integration/v2/bank/app_test.go index c6aa89ab5e87..7e75417eb2c9 100644 --- a/tests/integration/v2/bank/app_test.go +++ b/tests/integration/v2/bank/app_test.go @@ -141,8 +141,6 @@ func TestSendNotEnoughBalance(t *testing.T) { require.Equal(t, origAccNum, res2.GetAccountNumber()) require.Equal(t, origSeq+1, res2.GetSequence()) - - require.NoError(t, err) } func TestMsgMultiSendWithAccounts(t *testing.T) { diff --git a/tests/integration/v2/bank/determinisitic_test.go b/tests/integration/v2/bank/determinisitic_test.go index 9a59325d8461..70306e795087 100644 --- a/tests/integration/v2/bank/determinisitic_test.go +++ b/tests/integration/v2/bank/determinisitic_test.go @@ -2,21 +2,22 @@ package bank import ( "context" - "cosmossdk.io/core/gas" - minttypes "cosmossdk.io/x/mint/types" - "github.com/cosmos/gogoproto/proto" + "fmt" "testing" + "github.com/cosmos/gogoproto/proto" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" "pgregory.net/rapid" + "cosmossdk.io/core/gas" "cosmossdk.io/depinject" "cosmossdk.io/log" "cosmossdk.io/math" bankkeeper "cosmossdk.io/x/bank/keeper" banktestutil "cosmossdk.io/x/bank/testutil" banktypes "cosmossdk.io/x/bank/types" + minttypes "cosmossdk.io/x/mint/types" codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil" "github.com/cosmos/cosmos-sdk/tests/integration/v2" @@ -59,8 +60,16 @@ func queryFnFactory[RequestT, ResponseT proto.Message]( f *deterministicFixture, ) func(RequestT) (ResponseT, error) { return func(req RequestT) (ResponseT, error) { + var emptyResponse ResponseT res, err := f.app.Query(f.ctx, 0, req) - return res.(ResponseT), err + if err != nil { + return emptyResponse, err + } + castedRes, ok := res.(ResponseT) + if !ok { + return emptyResponse, fmt.Errorf("unexpected response type: %T", res) + } + return castedRes, nil } } @@ -119,6 +128,7 @@ func TestQueryBalance(t *testing.T) { queryFn := queryFnFactory[*banktypes.QueryBalanceRequest, *banktypes.QueryBalanceResponse](f) assertBalance := func(coin sdk.Coin) func(t *testing.T, res *banktypes.QueryBalanceResponse) { return func(t *testing.T, res *banktypes.QueryBalanceResponse) { + t.Helper() require.Equal(t, coin.Denom, res.Balance.Denom) require.Truef(t, coin.Amount.Equal(res.Balance.Amount), "expected %s, got %s", coin.Amount, res.Balance.Amount) diff --git a/tests/integration/v2/services.go b/tests/integration/v2/services.go index d1af2986968f..f69aa70574a0 100644 --- a/tests/integration/v2/services.go +++ b/tests/integration/v2/services.go @@ -2,16 +2,15 @@ package integration import ( "context" - "cosmossdk.io/core/gas" - stfgas "cosmossdk.io/server/v2/stf/gas" "fmt" "cosmossdk.io/core/comet" "cosmossdk.io/core/event" + "cosmossdk.io/core/gas" "cosmossdk.io/core/server" corestore "cosmossdk.io/core/store" "cosmossdk.io/core/transaction" - "cosmossdk.io/runtime/v2" + stfgas "cosmossdk.io/server/v2/stf/gas" ) func (c cometServiceImpl) CometInfo(context.Context) comet.Info { @@ -32,7 +31,7 @@ func (d *dynamicConfigImpl) Get(key string) any { func (d *dynamicConfigImpl) GetString(key string) string { switch key { - case runtime.FlagHome: + case "home": return d.homeDir case "store.app-db-backend": return "goleveldb" From 55e77a5a61c3b8a4f16c810d79d39f7114279d81 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 30 Sep 2024 12:35:41 -0500 Subject: [PATCH 57/57] linting --- tests/integration/v2/genesis.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/integration/v2/genesis.go b/tests/integration/v2/genesis.go index c4c7f91aec49..d101ce3e8672 100644 --- a/tests/integration/v2/genesis.go +++ b/tests/integration/v2/genesis.go @@ -1,13 +1,17 @@ package integration import ( - sdkmath "cosmossdk.io/math" - banktypes "cosmossdk.io/x/bank/types" - stakingtypes "cosmossdk.io/x/staking/types" "encoding/json" "errors" "fmt" + "time" + cmttypes "github.com/cometbft/cometbft/types" + + sdkmath "cosmossdk.io/math" + banktypes "cosmossdk.io/x/bank/types" + stakingtypes "cosmossdk.io/x/staking/types" + "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" @@ -15,7 +19,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/tx" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "time" ) // genesisStateWithValSet returns a new genesis state with the validator set @@ -26,6 +29,9 @@ func genesisStateWithValSet( genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance, ) (map[string]json.RawMessage, error) { + if len(genAccs) == 0 { + return nil, errors.New("no genesis accounts provided") + } // set genesis accounts authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs) genesisState[authtypes.ModuleName] = codec.MustMarshalJSON(authGenesis)