[wip] update e2e integration tests

- use sdk testutil/network

- refactor e2e tests

- gomock -> uber gomock
This commit is contained in:
Roy Crihfield 2024-10-08 14:54:59 +08:00
parent e5a085642c
commit c7e0753f08
31 changed files with 930 additions and 1425 deletions

3
go.mod
View File

@ -37,6 +37,7 @@ require (
github.com/ethereum/go-ethereum v1.14.5
github.com/gibson042/canonicaljson-go v1.0.3
github.com/go-chi/chi/v5 v5.0.8
github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.4
github.com/grpc-ecosystem/grpc-gateway v1.16.0
github.com/ipfs/go-cid v0.4.1
@ -61,7 +62,6 @@ require (
cosmossdk.io/x/distribution v0.0.0-20241007000829-38662ecb209f
cosmossdk.io/x/gov v1.0.0-alpha.4
cosmossdk.io/x/mint v0.0.0-20241004153623-489aaae40234
cosmossdk.io/x/params v0.0.0-20241007000829-38662ecb209f
cosmossdk.io/x/protocolpool v1.0.0-alpha.4
cosmossdk.io/x/slashing v0.0.0-20241007000829-38662ecb209f
cosmossdk.io/x/staking v1.0.0-alpha.4
@ -127,7 +127,6 @@ require (
github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
github.com/google/btree v1.1.3 // indirect
github.com/google/flatbuffers v2.0.8+incompatible // indirect

View File

@ -3,13 +3,14 @@ package auction
import (
"testing"
"github.com/cosmos/cosmos-sdk/testutil/network"
"github.com/stretchr/testify/suite"
"git.vdb.to/cerc-io/laconicd/tests/e2e"
"git.vdb.to/cerc-io/laconicd/testutil/network"
)
func TestAuctionE2ETestSuite(t *testing.T) {
// e2e.RunTestSuite(t)
cfg := network.DefaultConfig(e2e.NewTestNetworkFixture)
cfg.NumValidators = 1

View File

@ -15,16 +15,16 @@ const (
)
func (ets *E2ETestSuite) TestQueryParamsGrpc() {
val := ets.network.Validators[0]
val := ets.network.GetValidators()[0]
sr := ets.Require()
reqURL := fmt.Sprintf("%s/cerc/auction/v1/params", val.APIAddress)
reqURL := fmt.Sprintf("%s/cerc/auction/v1/params", val.GetAPIAddress())
ets.Run("valid request to get auction params", func() {
resp, err := testutil.GetRequest(reqURL)
ets.Require().NoError(err)
var params auctiontypes.QueryParamsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &params)
err = val.GetClientCtx().Codec.UnmarshalJSON(resp, &params)
sr.NoError(err)
sr.Equal(*params.GetParams(), auctiontypes.DefaultParams())
@ -32,9 +32,9 @@ func (ets *E2ETestSuite) TestQueryParamsGrpc() {
}
func (ets *E2ETestSuite) TestGetAllAuctionsGrpc() {
val := ets.network.Validators[0]
val := ets.network.GetValidators()[0]
sr := ets.Require()
reqURL := fmt.Sprintf("%s/cerc/auction/v1/auctions", val.APIAddress)
reqURL := fmt.Sprintf("%s/cerc/auction/v1/auctions", val.GetAPIAddress())
testCases := []struct {
msg string
@ -63,7 +63,7 @@ func (ets *E2ETestSuite) TestGetAllAuctionsGrpc() {
} else {
sr.NoError(err)
var auctions auctiontypes.QueryAuctionsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &auctions)
err = val.GetClientCtx().Codec.UnmarshalJSON(resp, &auctions)
sr.NoError(err)
sr.NotZero(len(auctions.Auctions.Auctions))
}
@ -72,9 +72,9 @@ func (ets *E2ETestSuite) TestGetAllAuctionsGrpc() {
}
func (ets *E2ETestSuite) TestGetAuctionGrpc() {
val := ets.network.Validators[0]
val := ets.network.GetValidators()[0]
sr := ets.Require()
reqURL := fmt.Sprintf("%s/cerc/auction/v1/auctions/", val.APIAddress)
reqURL := fmt.Sprintf("%s/cerc/auction/v1/auctions/", val.GetAPIAddress())
testCases := []struct {
msg string
@ -107,7 +107,7 @@ func (ets *E2ETestSuite) TestGetAuctionGrpc() {
} else {
sr.NoError(err)
var auction auctiontypes.QueryGetAuctionResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &auction)
err = val.GetClientCtx().Codec.UnmarshalJSON(resp, &auction)
sr.NoError(err)
sr.Equal(auctionId, auction.Auction.Id)
}
@ -116,9 +116,9 @@ func (ets *E2ETestSuite) TestGetAuctionGrpc() {
}
func (ets *E2ETestSuite) TestGetBidsGrpc() {
val := ets.network.Validators[0]
val := ets.network.GetValidators()[0]
sr := ets.Require()
reqURL := fmt.Sprintf("%s/cerc/auction/v1/bids/", val.APIAddress)
reqURL := fmt.Sprintf("%s/cerc/auction/v1/bids/", val.GetAPIAddress())
testCases := []struct {
msg string
url string
@ -152,7 +152,7 @@ func (ets *E2ETestSuite) TestGetBidsGrpc() {
} else {
sr.NoError(err)
var bids auctiontypes.QueryGetBidsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &bids)
err = val.GetClientCtx().Codec.UnmarshalJSON(resp, &bids)
sr.NoError(err)
sr.Equal(auctionId, bids.Bids[0].AuctionId)
}
@ -161,9 +161,9 @@ func (ets *E2ETestSuite) TestGetBidsGrpc() {
}
func (ets *E2ETestSuite) TestGetBidGrpc() {
val := ets.network.Validators[0]
val := ets.network.GetValidators()[0]
sr := ets.Require()
reqURL := fmt.Sprintf("%s/cerc/auction/v1/bids/", val.APIAddress)
reqURL := fmt.Sprintf("%s/cerc/auction/v1/bids/", val.GetAPIAddress())
testCases := []struct {
msg string
url string
@ -197,7 +197,7 @@ func (ets *E2ETestSuite) TestGetBidGrpc() {
} else {
sr.NoError(err)
var bid auctiontypes.QueryGetBidResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &bid)
err = val.GetClientCtx().Codec.UnmarshalJSON(resp, &bid)
sr.NoError(err)
}
})
@ -205,9 +205,9 @@ func (ets *E2ETestSuite) TestGetBidGrpc() {
}
func (ets *E2ETestSuite) TestGetAuctionsByOwnerGrpc() {
val := ets.network.Validators[0]
val := ets.network.GetValidators()[0]
sr := ets.Require()
reqURL := fmt.Sprintf("%s/cerc/auction/v1/by-owner/", val.APIAddress)
reqURL := fmt.Sprintf("%s/cerc/auction/v1/by-owner/", val.GetAPIAddress())
testCases := []struct {
msg string
url string
@ -235,7 +235,7 @@ func (ets *E2ETestSuite) TestGetAuctionsByOwnerGrpc() {
} else {
sr.NoError(err)
var auctions auctiontypes.QueryAuctionsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &auctions)
err = val.GetClientCtx().Codec.UnmarshalJSON(resp, &auctions)
sr.NoError(err)
}
})
@ -243,9 +243,9 @@ func (ets *E2ETestSuite) TestGetAuctionsByOwnerGrpc() {
}
func (ets *E2ETestSuite) TestQueryBalanceGrpc() {
val := ets.network.Validators[0]
val := ets.network.GetValidators()[0]
sr := ets.Require()
reqURL := fmt.Sprintf("%s/cerc/auction/v1/balance", val.APIAddress)
reqURL := fmt.Sprintf("%s/cerc/auction/v1/balance", val.GetAPIAddress())
msg := "valid request to get the auction module balance"
ets.createAuctionAndBid(false, true)
@ -255,7 +255,7 @@ func (ets *E2ETestSuite) TestQueryBalanceGrpc() {
sr.NoError(err)
var response auctiontypes.QueryGetAuctionModuleBalanceResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
err = val.GetClientCtx().Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
sr.NotZero(len(response.GetBalance()))

View File

@ -13,7 +13,7 @@ import (
var queryJSONFlag = []string{fmt.Sprintf("--%s=json", flags.FlagOutput)}
func (ets *E2ETestSuite) TestGetCmdList() {
val := ets.network.Validators[0]
val := ets.network.GetValidators()[0]
sr := ets.Require()
testCases := []struct {
@ -32,10 +32,10 @@ func (ets *E2ETestSuite) TestGetCmdList() {
for _, test := range testCases {
ets.Run(fmt.Sprintf("Case %s", test.msg), func() {
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cli.GetCmdList(), queryJSONFlag)
out, err := clitestutil.ExecTestCLICmd(val.GetClientCtx(), cli.GetCmdList(), queryJSONFlag)
sr.NoError(err)
var auctions types.QueryAuctionsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &auctions)
err = val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &auctions)
sr.NoError(err)
if test.createAuction {
sr.NotZero(len(auctions.Auctions.Auctions))

View File

@ -6,17 +6,15 @@ import (
"path/filepath"
"cosmossdk.io/math"
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/client/flags"
banktypes "cosmossdk.io/x/bank/types"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/suite"
laconictestcli "git.vdb.to/cerc-io/laconicd/testutil/cli"
"git.vdb.to/cerc-io/laconicd/testutil/network"
"git.vdb.to/cerc-io/laconicd/utils"
types "git.vdb.to/cerc-io/laconicd/x/auction"
"git.vdb.to/cerc-io/laconicd/x/auction/client/cli"
)
@ -32,7 +30,7 @@ type E2ETestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
network network.NetworkI
defaultAuctionId string
}
@ -68,36 +66,37 @@ func (ets *E2ETestSuite) TearDownSuite() {
}
func (ets *E2ETestSuite) createAccountWithBalance(accountName string, accountAddress *string) {
val := ets.network.Validators[0]
val := ets.network.GetValidators()[0]
sr := ets.Require()
info, _, err := val.ClientCtx.Keyring.NewMnemonic(accountName, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
info, _, err := val.GetClientCtx().Keyring.NewMnemonic(accountName, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
sr.NoError(err)
newAddr, _ := info.GetAddress()
out, err := clitestutil.MsgSendExec(
val.ClientCtx,
val.Address,
msgSend := &banktypes.MsgSend{
FromAddress: newAddr.String(),
ToAddress: val.GetAddress().String(),
Amount: sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(200000))),
}
out, err := clitestutil.SubmitTestTx(
val.GetClientCtx(),
msgSend,
newAddr,
sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(200000))),
utils.NewAddressCodec(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, accountName),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(10))).String()),
clitestutil.TestTxConfig{
Fee: sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(10))),
},
)
sr.NoError(err)
var response sdk.TxResponse
sr.NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, response.TxHash, 0))
sr.NoError(val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.GetClientCtx(), response.TxHash, 0))
*accountAddress = newAddr.String()
}
func (ets *E2ETestSuite) createAuctionAndBid(createAuction, createBid bool) string {
val := ets.network.Validators[0]
val := ets.network.GetValidators()[0]
sr := ets.Require()
auctionId := ""
@ -114,12 +113,12 @@ func (ets *E2ETestSuite) createAuctionAndBid(createAuction, createBid bool) stri
resp, err := ets.executeTx(cli.GetCmdCreateAuction(), auctionArgs, ownerAccount)
sr.NoError(err)
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, resp.TxHash, 0))
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.GetClientCtx(), resp.TxHash, 0))
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cli.GetCmdList(), queryJSONFlag)
out, err := clitestutil.ExecTestCLICmd(val.GetClientCtx(), cli.GetCmdList(), queryJSONFlag)
sr.NoError(err)
var queryResponse types.QueryAuctionsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &queryResponse)
err = val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &queryResponse)
sr.NoError(err)
auctionId = queryResponse.Auctions.Auctions[0].Id
} else {
@ -130,7 +129,7 @@ func (ets *E2ETestSuite) createAuctionAndBid(createAuction, createBid bool) stri
bidArgs := []string{auctionId, fmt.Sprintf("200%s", ets.cfg.BondDenom)}
resp, err := ets.executeTx(cli.GetCmdCommitBid(), bidArgs, bidderAccount)
sr.NoError(err)
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, resp.TxHash, 0))
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.GetClientCtx(), resp.TxHash, 0))
}
return auctionId

View File

@ -20,7 +20,7 @@ const (
)
func (ets *E2ETestSuite) TestTxCommitBid() {
val := ets.network.Validators[0]
val := ets.network.GetValidators()[0]
sr := ets.Require()
testCases := []struct {
msg string
@ -57,13 +57,13 @@ func (ets *E2ETestSuite) TestTxCommitBid() {
resp, err := ets.executeTx(cli.GetCmdCreateAuction(), auctionArgs, ownerAccount)
sr.NoError(err)
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, resp.TxHash, 0))
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.GetClientCtx(), resp.TxHash, 0))
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cli.GetCmdList(),
out, err := clitestutil.ExecTestCLICmd(val.GetClientCtx(), cli.GetCmdList(),
[]string{fmt.Sprintf("--%s=json", flags.FlagOutput)})
sr.NoError(err)
var queryResponse auctiontypes.QueryAuctionsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &queryResponse)
err = val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &queryResponse)
sr.NoError(err)
sr.NotNil(queryResponse.GetAuctions())
test.args[0] = queryResponse.GetAuctions().Auctions[0].Id
@ -72,7 +72,7 @@ func (ets *E2ETestSuite) TestTxCommitBid() {
resp, err := ets.executeTx(cli.GetCmdCommitBid(), test.args, bidderAccount)
if test.createAuction {
sr.NoError(err)
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, resp.TxHash, 0))
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.GetClientCtx(), resp.TxHash, 0))
} else {
sr.Error(err)
}
@ -81,7 +81,7 @@ func (ets *E2ETestSuite) TestTxCommitBid() {
}
func (ets *E2ETestSuite) executeTx(cmd *cobra.Command, args []string, caller string) (sdk.TxResponse, error) {
val := ets.network.Validators[0]
val := ets.network.GetValidators()[0]
additionalArgs := []string{
fmt.Sprintf("--%s=%s", flags.FlagFrom, caller),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
@ -90,13 +90,13 @@ func (ets *E2ETestSuite) executeTx(cmd *cobra.Command, args []string, caller str
}
args = append(args, additionalArgs...)
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args)
out, err := clitestutil.ExecTestCLICmd(val.GetClientCtx(), cmd, args)
if err != nil {
return sdk.TxResponse{}, err
}
var resp sdk.TxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp)
err = val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &resp)
if err != nil {
return sdk.TxResponse{}, err
}

View File

@ -3,13 +3,14 @@ package bond
import (
"testing"
"github.com/cosmos/cosmos-sdk/testutil/network"
"github.com/stretchr/testify/suite"
"git.vdb.to/cerc-io/laconicd/tests/e2e"
"git.vdb.to/cerc-io/laconicd/testutil/network"
)
func TestBondE2ETestSuite(t *testing.T) {
// e2e.RunTestSuite(t)
cfg := network.DefaultConfig(e2e.NewTestNetworkFixture)
cfg.NumValidators = 1

View File

@ -9,24 +9,24 @@ import (
)
func (ets *E2ETestSuite) TestGRPCGetParams() {
val := ets.network.Validators[0]
val := ets.network.GetValidators()[0]
sr := ets.Require()
reqURL := fmt.Sprintf("%s/cerc/bond/v1/params", val.APIAddress)
reqURL := fmt.Sprintf("%s/cerc/bond/v1/params", val.GetAPIAddress())
resp, err := testutil.GetRequest(reqURL)
ets.Require().NoError(err)
var params bondtypes.QueryParamsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &params)
err = val.GetClientCtx().Codec.UnmarshalJSON(resp, &params)
sr.NoError(err)
sr.Equal(params.GetParams().MaxBondAmount, bondtypes.DefaultParams().MaxBondAmount)
}
func (ets *E2ETestSuite) TestGRPCGetBonds() {
val := ets.network.Validators[0]
val := ets.network.GetValidators()[0]
sr := ets.Require()
reqURL := fmt.Sprintf("%s/cerc/bond/v1/bonds", val.APIAddress)
reqURL := fmt.Sprintf("%s/cerc/bond/v1/bonds", val.GetAPIAddress())
testCases := []struct {
name string
@ -59,7 +59,7 @@ func (ets *E2ETestSuite) TestGRPCGetBonds() {
sr.Contains(string(resp), tc.errorMsg)
} else {
var response bondtypes.QueryBondsResponse
err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
err := val.GetClientCtx().Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
sr.NotZero(len(response.GetBonds()))
}
@ -68,9 +68,9 @@ func (ets *E2ETestSuite) TestGRPCGetBonds() {
}
func (ets *E2ETestSuite) TestGRPCGetBondsByOwner() {
val := ets.network.Validators[0]
val := ets.network.GetValidators()[0]
sr := ets.Require()
reqURL := val.APIAddress + "/cerc/bond/v1/by-owner/%s"
reqURL := val.GetAPIAddress() + "/cerc/bond/v1/by-owner/%s"
testCases := []struct {
name string
@ -100,7 +100,7 @@ func (ets *E2ETestSuite) TestGRPCGetBondsByOwner() {
ets.Require().NoError(err)
var bonds bondtypes.QueryGetBondsByOwnerResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &bonds)
err = val.GetClientCtx().Codec.UnmarshalJSON(resp, &bonds)
sr.NoError(err)
if tc.expErr {
sr.Empty(bonds.GetBonds())
@ -114,9 +114,9 @@ func (ets *E2ETestSuite) TestGRPCGetBondsByOwner() {
}
func (ets *E2ETestSuite) TestGRPCGetBondById() {
val := ets.network.Validators[0]
val := ets.network.GetValidators()[0]
sr := ets.Require()
reqURL := val.APIAddress + "/cerc/bond/v1/bonds/%s"
reqURL := val.GetAPIAddress() + "/cerc/bond/v1/bonds/%s"
testCases := []struct {
name string
@ -149,7 +149,7 @@ func (ets *E2ETestSuite) TestGRPCGetBondById() {
ets.Require().NoError(err)
var bonds bondtypes.QueryGetBondByIdResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &bonds)
err = val.GetClientCtx().Codec.UnmarshalJSON(resp, &bonds)
if tc.expErr {
sr.Empty(bonds.GetBond().GetId())
@ -163,9 +163,9 @@ func (ets *E2ETestSuite) TestGRPCGetBondById() {
}
func (ets *E2ETestSuite) TestGRPCGetBondModuleBalance() {
val := ets.network.Validators[0]
val := ets.network.GetValidators()[0]
sr := ets.Require()
reqURL := fmt.Sprintf("%s/cerc/bond/v1/balance", val.APIAddress)
reqURL := fmt.Sprintf("%s/cerc/bond/v1/balance", val.GetAPIAddress())
// creating the bond
ets.createBond()
@ -175,7 +175,7 @@ func (ets *E2ETestSuite) TestGRPCGetBondModuleBalance() {
sr.NoError(err)
var response bondtypes.QueryGetBondModuleBalanceResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
err = val.GetClientCtx().Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
sr.False(response.GetBalance().IsZero())

View File

@ -11,7 +11,7 @@ import (
)
func (ets *E2ETestSuite) TestGetQueryBondList() {
val := ets.network.Validators[0]
val := ets.network.GetValidators()[0]
sr := ets.Require()
testCases := []struct {
@ -32,7 +32,7 @@ func (ets *E2ETestSuite) TestGetQueryBondList() {
for _, tc := range testCases {
ets.Run(fmt.Sprintf("Case %s", tc.name), func() {
clientCtx := val.ClientCtx
clientCtx := val.GetClientCtx()
if tc.createBond {
tc.preRun()
}

View File

@ -4,17 +4,16 @@ import (
"fmt"
"cosmossdk.io/math"
"github.com/stretchr/testify/suite"
banktypes "cosmossdk.io/x/bank/types"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/suite"
laconictestcli "git.vdb.to/cerc-io/laconicd/testutil/cli"
"git.vdb.to/cerc-io/laconicd/testutil/network"
"git.vdb.to/cerc-io/laconicd/utils"
bondtypes "git.vdb.to/cerc-io/laconicd/x/bond"
"git.vdb.to/cerc-io/laconicd/x/bond/client/cli"
)
@ -23,7 +22,7 @@ type E2ETestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
network network.NetworkI
accountName string
accountAddress string
@ -56,36 +55,37 @@ func (ets *E2ETestSuite) TearDownSuite() {
}
func (ets *E2ETestSuite) createAccountWithBalance(accountName string, accountAddress *string) {
val := ets.network.Validators[0]
val := ets.network.GetValidators()[0]
sr := ets.Require()
info, _, err := val.ClientCtx.Keyring.NewMnemonic(accountName, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
info, _, err := val.GetClientCtx().Keyring.NewMnemonic(accountName, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
sr.NoError(err)
newAddr, _ := info.GetAddress()
out, err := clitestutil.MsgSendExec(
val.ClientCtx,
val.Address,
msgSend := &banktypes.MsgSend{
FromAddress: newAddr.String(),
ToAddress: val.GetAddress().String(),
Amount: sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(200000))),
}
out, err := clitestutil.SubmitTestTx(
val.GetClientCtx(),
msgSend,
newAddr,
sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(200000))),
utils.NewAddressCodec(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, accountName),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(10))).String()),
clitestutil.TestTxConfig{
Fee: sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(10))),
},
)
sr.NoError(err)
var response sdk.TxResponse
sr.NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, response.TxHash, 0))
sr.NoError(val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.GetClientCtx(), response.TxHash, 0))
*accountAddress = newAddr.String()
}
func (ets *E2ETestSuite) createBond() string {
val := ets.network.Validators[0]
val := ets.network.GetValidators()[0]
sr := ets.Require()
createBondCmd := cli.NewCreateBondCmd()
args := []string{
@ -96,17 +96,17 @@ func (ets *E2ETestSuite) createBond() string {
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)),
}
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, createBondCmd, args)
out, err := clitestutil.ExecTestCLICmd(val.GetClientCtx(), createBondCmd, args)
sr.NoError(err)
var d sdk.TxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d)
err = val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &d)
sr.NoError(err)
sr.Zero(d.Code)
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, d.TxHash, 0))
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.GetClientCtx(), d.TxHash, 0))
// getting the bonds list and returning the bond-id
clientCtx := val.ClientCtx
clientCtx := val.GetClientCtx()
cmd := cli.GetQueryBondList()
args = []string{
fmt.Sprintf("--%s=json", flags.FlagOutput),
@ -114,7 +114,7 @@ func (ets *E2ETestSuite) createBond() string {
out, err = clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
sr.NoError(err)
var queryResponse bondtypes.QueryBondsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &queryResponse)
err = val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &queryResponse)
sr.NoError(err)
// extract bond id from bonds list

View File

@ -11,7 +11,7 @@ import (
)
func (ets *E2ETestSuite) TestTxCreateBond() {
val := ets.network.Validators[0]
val := ets.network.GetValidators()[0]
sr := ets.Require()
testCases := []struct {
@ -44,7 +44,7 @@ func (ets *E2ETestSuite) TestTxCreateBond() {
for _, tc := range testCases {
ets.Run(fmt.Sprintf("Case %s", tc.name), func() {
clientCtx := val.ClientCtx
clientCtx := val.GetClientCtx()
cmd := cli.NewCreateBondCmd()
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
@ -53,7 +53,7 @@ func (ets *E2ETestSuite) TestTxCreateBond() {
} else {
sr.NoError(err)
var d sdk.TxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d)
err = val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &d)
sr.Nil(err)
sr.NoError(err)
sr.Zero(d.Code)

View File

@ -4,26 +4,31 @@ import (
"fmt"
"os"
"github.com/spf13/viper"
"cosmossdk.io/depinject"
"cosmossdk.io/log"
pruningtypes "cosmossdk.io/store/pruning/types"
serverv2 "cosmossdk.io/server/v2"
"cosmossdk.io/server/v2/cometbft/mempool"
"cosmossdk.io/x/bank"
"cosmossdk.io/x/staking"
dbm "github.com/cosmos/cosmos-db"
bam "github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
serverv1types "github.com/cosmos/cosmos-sdk/server/types"
"github.com/cosmos/cosmos-sdk/testutil/network"
"github.com/cosmos/cosmos-sdk/types/module/testutil"
"github.com/cosmos/cosmos-sdk/x/auth"
"git.vdb.to/cerc-io/laconicd/app"
laconicApp "git.vdb.to/cerc-io/laconicd/app"
auctionmodule "git.vdb.to/cerc-io/laconicd/x/auction/module"
bondmodule "git.vdb.to/cerc-io/laconicd/x/bond/module"
registrymodule "git.vdb.to/cerc-io/laconicd/x/registry/module"
_ "cosmossdk.io/runtime/v2" // import for side-effects
_ "git.vdb.to/cerc-io/laconicd/app/params" // import for side-effects (see init)
"git.vdb.to/cerc-io/laconicd/testutil/network"
"git.vdb.to/cerc-io/laconicd/cmd/laconicd/cmd"
)
// NewTestNetworkFixture returns a new LaconicApp AppConstructor for network simulation tests
@ -34,29 +39,59 @@ func NewTestNetworkFixture() network.TestFixture {
}
defer os.RemoveAll(dir)
app, err := laconicApp.NewLaconicApp(log.NewNopLogger(), dbm.NewMemDB(), nil, true, simtestutil.NewAppOptionsWithFlagHome(dir))
// logfile := "/Users/roy/vulcanize/dump/laconic-debug/e2e_depinject.log"
// var genapp *app.AppBuilder
// if err := depinject.InjectDebug(
// depinject.DebugOptions(
// depinject.FileLogger(logfile),
// ),
// depinject.Configs(
// app.AppConfig(),
// depinject.Supply(
// log.NewNopLogger(),
// ),
// ),
// &genapp); err != nil {
// panic(fmt.Errorf("failed to initialize app builder: %w", err))
// }
vp := viper.New()
vp.Set(flags.FlagHome, dir)
genapp, err := laconicApp.NewLaconicApp(log.NewNopLogger(), vp, true)
if err != nil {
panic(fmt.Sprintf("failed to create laconic app: %v", err))
}
appCtr := func(val network.ValidatorI) servertypes.Application {
appConstructor := func(val network.ValidatorI) serverv1types.Application {
vp := val.GetViper()
vp.Set(flags.FlagHome, dir)
// viper.SetString(flags.FlagHome, ?)
vp.Set(serverv2.FlagMinGasPrices, val.GetAppConfig().MinGasPrices)
// bam.SetChainID(val.GetClientCtx().Viper.GetString(flags.FlagChainID)),
app, err := laconicApp.NewLaconicApp(
val.GetCtx().Logger, dbm.NewMemDB(), nil, true,
simtestutil.NewAppOptionsWithFlagHome(val.GetCtx().Config.RootDir),
bam.SetPruning(pruningtypes.NewPruningOptionsFromString(val.GetAppConfig().Pruning)),
bam.SetMinGasPrices(val.GetAppConfig().MinGasPrices),
bam.SetChainID(val.GetCtx().Viper.GetString(flags.FlagChainID)),
val.GetLogger(), val.GetViper(), true,
// simtestutil.NewAppOptionsWithFlagHome(val.GetViper().GetString(flags.FlagHome)),
// bam.SetPruning(pruningtypes.NewPruningOptionsFromString(val.GetAppConfig().Pruning)),
// bam.SetMinGasPrices(val.GetAppConfig().MinGasPrices),
// bam.SetChainID(val.GetClientCtx().Viper.GetString(flags.FlagChainID)),
)
if err != nil {
panic(fmt.Sprintf("failed creating temporary directory: %v", err))
}
return app
abci, err := setUpConsensus(
val.GetLogger(), 100_000, mempool.NoOpMempool[laconicApp.AppTx]{},
dir, val.GetClientCtx().TxConfig)
if err != nil {
panic(fmt.Errorf("failed to build ABCI app: %w", err))
}
return &serverAppV1{App: app, ABCI: abci}
}
return network.TestFixture{
AppConstructor: appCtr,
GenesisState: app.DefaultGenesis(),
AppConstructor: appConstructor,
GenesisState: genapp.DefaultGenesis(),
EncodingConfig: testutil.MakeTestEncodingConfig(
codectestutil.CodecOptions{},
auth.AppModule{},
@ -68,3 +103,47 @@ func NewTestNetworkFixture() network.TestFixture {
),
}
}
// type BaseE2ETestSuite struct {
// suite.Suite
// Config network.Config
// Network network.NetworkI
// }
func MakeNetworkConfig() network.Config {
logfile := "/Users/roy/vulcanize/dump/laconic-debug/e2e_depinject.log"
var clientCtx client.Context
if err := depinject.InjectDebug(
depinject.DebugOptions(
depinject.FileLogger(logfile),
),
depinject.Configs(
app.AppConfig(),
depinject.Supply(
log.NewNopLogger(),
),
depinject.Provide(
cmd.ProvideClientContext,
cmd.ProvideKeyring,
),
),
&clientCtx); err != nil {
panic(fmt.Errorf("failed to initialize app builder: %w", err))
}
cfg := network.DefaultConfig(NewTestNetworkFixture)
cfg.NumValidators = 1
// cfg.Codec = clientCtx.Codec
cfg.InterfaceRegistry = clientCtx.InterfaceRegistry
cfg.TxConfig = clientCtx.TxConfig
cfg.AccountRetriever = clientCtx.AccountRetriever
cfg.KeyringOptions = clientCtx.KeyringOptions
// cfg.MinGasPrices =
cfg.AddressCodec = clientCtx.AddressCodec
cfg.ValidatorAddressCodec = clientCtx.ValidatorAddressCodec
cfg.ConsensusAddressCodec = clientCtx.ConsensusAddressCodec
return cfg
}

View File

@ -6,12 +6,12 @@ import (
"github.com/stretchr/testify/suite"
"git.vdb.to/cerc-io/laconicd/tests/e2e"
"git.vdb.to/cerc-io/laconicd/testutil/network"
)
func TestRegistryE2ETestSuite(t *testing.T) {
cfg := network.DefaultConfig(e2e.NewTestNetworkFixture)
cfg.NumValidators = 1
// cfg := network.DefaultConfig(e2e.NewTestNetworkFixture)
// cfg.NumValidators = 1
suite.Run(t, NewE2ETestSuite(cfg))
suite.Run(t, NewE2ETestSuite(e2e.MakeNetworkConfig()))
// e2e.RunTestSuite(t)
}

View File

@ -15,9 +15,9 @@ import (
const badPath = "/asdasd"
func (ets *E2ETestSuite) TestGRPCQueryParams() {
val := ets.network.Validators[0]
val := ets.Network.GetValidators()[0]
sr := ets.Require()
reqURL := val.APIAddress + "/cerc/registry/v1/params"
reqURL := val.GetAPIAddress() + "/cerc/registry/v1/params"
testCases := []struct {
name string
@ -48,7 +48,7 @@ func (ets *E2ETestSuite) TestGRPCQueryParams() {
require.Contains(string(resp), tc.errorMsg)
} else {
var response registrytypes.QueryParamsResponse
err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
err := val.GetClientCtx().Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
params := registrytypes.DefaultParams()
@ -60,9 +60,9 @@ func (ets *E2ETestSuite) TestGRPCQueryParams() {
}
func (ets *E2ETestSuite) TestGRPCQueryWhoIs() {
val := ets.network.Validators[0]
val := ets.Network.GetValidators()[0]
sr := ets.Require()
reqUrl := val.APIAddress + "/cerc/registry/v1/whois/%s"
reqUrl := val.GetAPIAddress() + "/cerc/registry/v1/whois/%s"
authorityName := "QueryWhoIS"
testCases := []struct {
name string
@ -100,7 +100,7 @@ func (ets *E2ETestSuite) TestGRPCQueryWhoIs() {
require.Contains(string(resp), tc.errorMsg)
} else {
var response registrytypes.QueryWhoisResponse
err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
err := val.GetClientCtx().Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
sr.Equal(registrytypes.AuthorityActive, response.GetNameAuthority().Status)
}
@ -109,9 +109,9 @@ func (ets *E2ETestSuite) TestGRPCQueryWhoIs() {
}
func (ets *E2ETestSuite) TestGRPCQueryLookup() {
val := ets.network.Validators[0]
val := ets.Network.GetValidators()[0]
sr := ets.Require()
reqURL := val.APIAddress + "/cerc/registry/v1/lookup"
reqURL := val.GetAPIAddress() + "/cerc/registry/v1/lookup"
authorityName := "QueryLookUp"
testCases := []struct {
@ -150,7 +150,7 @@ func (ets *E2ETestSuite) TestGRPCQueryLookup() {
sr.Contains(string(resp), tc.errorMsg)
} else {
var response registrytypes.QueryLookupLrnResponse
err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
err := val.GetClientCtx().Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
sr.NotZero(len(response.Name.Latest.Id))
}
@ -159,9 +159,9 @@ func (ets *E2ETestSuite) TestGRPCQueryLookup() {
}
func (ets *E2ETestSuite) TestGRPCQueryListRecords() {
val := ets.network.Validators[0]
val := ets.Network.GetValidators()[0]
sr := ets.Require()
reqUrl := val.APIAddress + "/cerc/registry/v1/records"
reqUrl := val.GetAPIAddress() + "/cerc/registry/v1/records"
testCases := []struct {
name string
@ -197,7 +197,7 @@ func (ets *E2ETestSuite) TestGRPCQueryListRecords() {
require.Contains(string(resp), tc.errorMsg)
} else {
var response registrytypes.QueryRecordsResponse
err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
err := val.GetClientCtx().Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
sr.NotZero(len(response.GetRecords()))
sr.Equal(ets.bondId, response.GetRecords()[0].GetBondId())
@ -207,9 +207,9 @@ func (ets *E2ETestSuite) TestGRPCQueryListRecords() {
}
func (ets *E2ETestSuite) TestGRPCQueryGetRecordById() {
val := ets.network.Validators[0]
val := ets.Network.GetValidators()[0]
sr := ets.Require()
reqURL := val.APIAddress + "/cerc/registry/v1/records/%s"
reqURL := val.GetAPIAddress() + "/cerc/registry/v1/records/%s"
testCases := []struct {
name string
@ -237,7 +237,7 @@ func (ets *E2ETestSuite) TestGRPCQueryGetRecordById() {
ets.createRecord(bondId)
// list the records
clientCtx := val.ClientCtx
clientCtx := val.GetClientCtx()
cmd := cli.GetCmdList()
args := []string{
fmt.Sprintf("--%s=json", flags.FlagOutput),
@ -264,7 +264,7 @@ func (ets *E2ETestSuite) TestGRPCQueryGetRecordById() {
require.Contains(string(resp), tc.errorMsg)
} else {
var response registrytypes.QueryGetRecordResponse
err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
err := val.GetClientCtx().Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
record := response.GetRecord()
sr.NotZero(len(record.GetId()))
@ -275,9 +275,9 @@ func (ets *E2ETestSuite) TestGRPCQueryGetRecordById() {
}
func (ets *E2ETestSuite) TestGRPCQueryGetRecordByBondId() {
val := ets.network.Validators[0]
val := ets.Network.GetValidators()[0]
sr := ets.Require()
reqURL := val.APIAddress + "/cerc/registry/v1/records-by-bond-id/%s"
reqURL := val.GetAPIAddress() + "/cerc/registry/v1/records-by-bond-id/%s"
testCases := []struct {
name string
@ -318,7 +318,7 @@ func (ets *E2ETestSuite) TestGRPCQueryGetRecordByBondId() {
require.Contains(string(resp), tc.errorMsg)
} else {
var response registrytypes.QueryGetRecordsByBondIdResponse
err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
err := val.GetClientCtx().Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
records := response.GetRecords()
sr.NotZero(len(records))
@ -329,9 +329,9 @@ func (ets *E2ETestSuite) TestGRPCQueryGetRecordByBondId() {
}
func (ets *E2ETestSuite) TestGRPCQueryGetRegistryModuleBalance() {
val := ets.network.Validators[0]
val := ets.Network.GetValidators()[0]
sr := ets.Require()
reqURL := val.APIAddress + "/cerc/registry/v1/balance"
reqURL := val.GetAPIAddress() + "/cerc/registry/v1/balance"
testCases := []struct {
name string
@ -370,7 +370,7 @@ func (ets *E2ETestSuite) TestGRPCQueryGetRegistryModuleBalance() {
require.Contains(string(resp), tc.errorMsg)
} else {
var response registrytypes.QueryGetRegistryModuleBalanceResponse
err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
err := val.GetClientCtx().Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
sr.NotZero(len(response.GetBalances()))
}
@ -379,9 +379,9 @@ func (ets *E2ETestSuite) TestGRPCQueryGetRegistryModuleBalance() {
}
func (ets *E2ETestSuite) TestGRPCQueryNamesList() {
val := ets.network.Validators[0]
val := ets.Network.GetValidators()[0]
sr := ets.Require()
reqURL := val.APIAddress + "/cerc/registry/v1/names"
reqURL := val.GetAPIAddress() + "/cerc/registry/v1/names"
testCases := []struct {
name string
@ -420,7 +420,7 @@ func (ets *E2ETestSuite) TestGRPCQueryNamesList() {
require.Contains(string(resp), tc.errorMsg)
} else {
var response registrytypes.QueryNameRecordsResponse
err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response)
err := val.GetClientCtx().Codec.UnmarshalJSON(resp, &response)
sr.NoError(err)
sr.NotZero(len(response.GetNames()))
}

View File

@ -6,17 +6,16 @@ import (
"time"
"cosmossdk.io/math"
"github.com/stretchr/testify/suite"
banktypes "cosmossdk.io/x/bank/types"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/suite"
laconictestcli "git.vdb.to/cerc-io/laconicd/testutil/cli"
"git.vdb.to/cerc-io/laconicd/testutil/network"
"git.vdb.to/cerc-io/laconicd/utils"
bondtypes "git.vdb.to/cerc-io/laconicd/x/bond"
bondcli "git.vdb.to/cerc-io/laconicd/x/bond/client/cli"
registrytypes "git.vdb.to/cerc-io/laconicd/x/registry"
@ -24,10 +23,11 @@ import (
)
type E2ETestSuite struct {
// e2e.E2ETestSuite
suite.Suite
cfg network.Config
network *network.Network
Config network.Config
Network network.NetworkI
accountName string
accountAddress string
@ -36,7 +36,7 @@ type E2ETestSuite struct {
}
func NewE2ETestSuite(cfg network.Config) *E2ETestSuite {
return &E2ETestSuite{cfg: cfg}
return &E2ETestSuite{Config: cfg}
}
func (ets *E2ETestSuite) SetupSuite() {
@ -45,21 +45,21 @@ func (ets *E2ETestSuite) SetupSuite() {
var err error
genesisState := ets.cfg.GenesisState
genesisState := ets.Config.GenesisState
var registryGenesis registrytypes.GenesisState
ets.Require().NoError(ets.cfg.Codec.UnmarshalJSON(genesisState[registrytypes.ModuleName], &registryGenesis))
ets.Require().NoError(ets.Config.Codec.UnmarshalJSON(genesisState[registrytypes.ModuleName], &registryGenesis))
ets.updateParams(&registryGenesis.Params)
registryGenesisBz, err := ets.cfg.Codec.MarshalJSON(&registryGenesis)
registryGenesisBz, err := ets.Config.Codec.MarshalJSON(&registryGenesis)
ets.Require().NoError(err)
genesisState[registrytypes.ModuleName] = registryGenesisBz
ets.cfg.GenesisState = genesisState
ets.Config.GenesisState = genesisState
ets.network, err = network.New(ets.T(), ets.T().TempDir(), ets.cfg)
ets.Network, err = network.New(ets.T(), ets.T().TempDir(), ets.Config)
sr.NoError(err)
_, err = ets.network.WaitForHeight(2)
_, err = ets.Network.WaitForHeight(2)
sr.NoError(err)
// setting up random account
@ -71,59 +71,60 @@ func (ets *E2ETestSuite) SetupSuite() {
func (ets *E2ETestSuite) TearDownSuite() {
ets.T().Log("tearing down e2e test suite")
ets.network.Cleanup()
ets.Network.Cleanup()
}
func (ets *E2ETestSuite) createAccountWithBalance(accountName string, accountAddress *string) {
val := ets.network.Validators[0]
val := ets.Network.GetValidators()[0]
sr := ets.Require()
info, _, err := val.ClientCtx.Keyring.NewMnemonic(accountName, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
info, _, err := val.GetClientCtx().Keyring.NewMnemonic(accountName, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
sr.NoError(err)
newAddr, _ := info.GetAddress()
out, err := clitestutil.MsgSendExec(
val.ClientCtx,
val.Address,
msgSend := &banktypes.MsgSend{
FromAddress: newAddr.String(),
ToAddress: val.GetAddress().String(),
Amount: sdk.NewCoins(sdk.NewCoin(ets.Config.BondDenom, math.NewInt(100000000))),
}
out, err := clitestutil.SubmitTestTx(
val.GetClientCtx(),
msgSend,
newAddr,
sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(100000000))),
utils.NewAddressCodec(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, accountName),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(10))).String()),
clitestutil.TestTxConfig{
Fee: sdk.NewCoins(sdk.NewCoin(ets.Config.BondDenom, math.NewInt(10))),
},
)
sr.NoError(err)
var response sdk.TxResponse
sr.NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, response.TxHash, 0))
sr.NoError(val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
sr.NoError(laconictestcli.CheckTxCode(ets.Network, val.GetClientCtx(), response.TxHash, 0))
*accountAddress = newAddr.String()
}
func (ets *E2ETestSuite) createBond() string {
val := ets.network.Validators[0]
val := ets.Network.GetValidators()[0]
sr := ets.Require()
createBondCmd := bondcli.NewCreateBondCmd()
args := []string{
fmt.Sprintf("1000000%s", ets.cfg.BondDenom),
fmt.Sprintf("1000000%s", ets.Config.BondDenom),
fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.Config.BondDenom)),
}
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, createBondCmd, args)
out, err := clitestutil.ExecTestCLICmd(val.GetClientCtx(), createBondCmd, args)
sr.NoError(err)
var d sdk.TxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d)
err = val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &d)
sr.NoError(err)
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, d.TxHash, 0))
sr.NoError(laconictestcli.CheckTxCode(ets.Network, val.GetClientCtx(), d.TxHash, 0))
// getting the bonds list and returning the bond-id
clientCtx := val.ClientCtx
clientCtx := val.GetClientCtx()
cmd := bondcli.GetQueryBondList()
args = []string{
fmt.Sprintf("--%s=json", flags.FlagOutput),
@ -131,7 +132,7 @@ func (ets *E2ETestSuite) createBond() string {
out, err = clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
sr.NoError(err)
var queryResponse bondtypes.QueryBondsResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &queryResponse)
err = val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &queryResponse)
sr.NoError(err)
// extract bond id from bonds list
@ -140,10 +141,10 @@ func (ets *E2ETestSuite) createBond() string {
}
func (ets *E2ETestSuite) reserveName(authorityName string) {
val := ets.network.Validators[0]
val := ets.Network.GetValidators()[0]
sr := ets.Require()
clientCtx := val.ClientCtx
clientCtx := val.GetClientCtx()
cmd := cli.GetCmdReserveAuthority()
args := []string{
authorityName,
@ -152,23 +153,23 @@ func (ets *E2ETestSuite) reserveName(authorityName string) {
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.Config.BondDenom)),
}
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
sr.NoError(err)
var d sdk.TxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d)
err = val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &d)
sr.NoError(err)
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, d.TxHash, 0))
sr.NoError(laconictestcli.CheckTxCode(ets.Network, val.GetClientCtx(), d.TxHash, 0))
}
func (ets *E2ETestSuite) createNameRecord(authorityName string) {
val := ets.network.Validators[0]
val := ets.Network.GetValidators()[0]
sr := ets.Require()
// reserving the name
clientCtx := val.ClientCtx
clientCtx := val.GetClientCtx()
cmd := cli.GetCmdReserveAuthority()
args := []string{
authorityName,
@ -177,14 +178,14 @@ func (ets *E2ETestSuite) createNameRecord(authorityName string) {
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.Config.BondDenom)),
}
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
sr.NoError(err)
var d sdk.TxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d)
err = val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &d)
sr.NoError(err)
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, d.TxHash, 0))
sr.NoError(laconictestcli.CheckTxCode(ets.Network, val.GetClientCtx(), d.TxHash, 0))
// Get the bond-id
bondId := ets.bondId
@ -196,15 +197,15 @@ func (ets *E2ETestSuite) createNameRecord(authorityName string) {
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.Config.BondDenom)),
}
cmd = cli.GetCmdSetAuthorityBond()
out, err = clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
sr.NoError(err)
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d)
err = val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &d)
sr.NoError(err)
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, d.TxHash, 0))
sr.NoError(laconictestcli.CheckTxCode(ets.Network, val.GetClientCtx(), d.TxHash, 0))
args = []string{
fmt.Sprintf("lrn://%s/", authorityName),
@ -213,20 +214,20 @@ func (ets *E2ETestSuite) createNameRecord(authorityName string) {
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.Config.BondDenom)),
}
cmd = cli.GetCmdSetName()
out, err = clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
sr.NoError(err)
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d)
err = val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &d)
sr.NoError(err)
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, d.TxHash, 0))
sr.NoError(laconictestcli.CheckTxCode(ets.Network, val.GetClientCtx(), d.TxHash, 0))
}
func (ets *E2ETestSuite) createRecord(bondId string) {
val := ets.network.Validators[0]
val := ets.Network.GetValidators()[0]
sr := ets.Require()
payloadPath := "../../data/examples/service_provider_example.yml"
@ -238,28 +239,28 @@ func (ets *E2ETestSuite) createRecord(bondId string) {
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.Config.BondDenom)),
}
args = append([]string{payloadFilePath, bondId}, args...)
clientCtx := val.ClientCtx
clientCtx := val.GetClientCtx()
cmd := cli.GetCmdSetRecord()
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
sr.NoError(err)
var d sdk.TxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d)
err = val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &d)
sr.NoError(err)
sr.NoError(laconictestcli.CheckTxCode(ets.network, val.ClientCtx, d.TxHash, 0))
sr.NoError(laconictestcli.CheckTxCode(ets.Network, val.GetClientCtx(), d.TxHash, 0))
}
func (ets *E2ETestSuite) updateParams(params *registrytypes.Params) {
params.RecordRent = sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(1000))
params.RecordRent = sdk.NewCoin(ets.Config.BondDenom, math.NewInt(1000))
params.RecordRentDuration = 10 * time.Second
params.AuthorityRent = sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(1000))
params.AuthorityRent = sdk.NewCoin(ets.Config.BondDenom, math.NewInt(1000))
params.AuthorityGracePeriod = 10 * time.Second
params.AuthorityAuctionCommitFee = sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(100))
params.AuthorityAuctionRevealFee = sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(100))
params.AuthorityAuctionMinimumBid = sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(500))
params.AuthorityAuctionCommitFee = sdk.NewCoin(ets.Config.BondDenom, math.NewInt(100))
params.AuthorityAuctionRevealFee = sdk.NewCoin(ets.Config.BondDenom, math.NewInt(100))
params.AuthorityAuctionMinimumBid = sdk.NewCoin(ets.Config.BondDenom, math.NewInt(500))
}

View File

@ -12,7 +12,7 @@ import (
)
func (ets *E2ETestSuite) TestGetCmdSetRecord() {
val := ets.network.Validators[0]
val := ets.Network.GetValidators()[0]
sr := ets.Require()
bondId := ets.bondId
@ -32,7 +32,7 @@ func (ets *E2ETestSuite) TestGetCmdSetRecord() {
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.Config.BondDenom)),
},
true,
},
@ -44,7 +44,7 @@ func (ets *E2ETestSuite) TestGetCmdSetRecord() {
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)),
fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.Config.BondDenom)),
},
false,
},
@ -52,7 +52,7 @@ func (ets *E2ETestSuite) TestGetCmdSetRecord() {
for _, tc := range testCases {
ets.Run(fmt.Sprintf("Case %s", tc.name), func() {
clientCtx := val.ClientCtx
clientCtx := val.GetClientCtx()
cmd := cli.GetCmdSetRecord()
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
@ -61,7 +61,7 @@ func (ets *E2ETestSuite) TestGetCmdSetRecord() {
} else {
sr.NoError(err)
var d sdk.TxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d)
err = val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &d)
sr.NoError(err)
sr.Zero(d.Code)
}

162
tests/e2e/server.go Normal file
View File

@ -0,0 +1,162 @@
package e2e
import (
"context"
"cosmossdk.io/store/snapshots"
storetypes "cosmossdk.io/store/types"
abci "github.com/cometbft/cometbft/abci/types"
cmtcrypto "github.com/cometbft/cometbft/crypto"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/server/api"
"github.com/cosmos/cosmos-sdk/server/config"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
"github.com/cosmos/gogoproto/grpc"
"git.vdb.to/cerc-io/laconicd/app"
)
// wrap a server/v2 implementation so it satisfies v1 server/types.Application
// type Application interface {
// Info(*abci.InfoRequest) (*abci.InfoResponse, error)
// Query(context.Context, *abci.QueryRequest) (*abci.QueryResponse, error)
// CheckTx(*abci.CheckTxRequest) (*abci.CheckTxResponse, error)
// InitChain(*abci.InitChainRequest) (*abci.InitChainResponse, error)
// PrepareProposal(*abci.PrepareProposalRequest) (*abci.PrepareProposalResponse, error)
// ProcessProposal(*abci.ProcessProposalRequest) (*abci.ProcessProposalResponse, error)
// FinalizeBlock(*abci.FinalizeBlockRequest) (*abci.FinalizeBlockResponse, error)
// ExtendVote(context.Context, *abci.ExtendVoteRequest) (*abci.ExtendVoteResponse, error)
// VerifyVoteExtension(*abci.VerifyVoteExtensionRequest) (*abci.VerifyVoteExtensionResponse, error)
// Commit() (*abci.CommitResponse, error)
// ListSnapshots(*abci.ListSnapshotsRequest) (*abci.ListSnapshotsResponse, error)
// OfferSnapshot(*abci.OfferSnapshotRequest) (*abci.OfferSnapshotResponse, error)
// LoadSnapshotChunk(*abci.LoadSnapshotChunkRequest) (*abci.LoadSnapshotChunkResponse, error)
// ApplySnapshotChunk(*abci.ApplySnapshotChunkRequest) (*abci.ApplySnapshotChunkResponse, error)
// RegisterAPIRoutes(*api.Server, config.APIConfig)
// RegisterGRPCServer(grpc.Server)
// RegisterTxService(client.Context)
// RegisterTendermintService(client.Context)
// RegisterNodeService(client.Context, config.Config)
// CommitMultiStore() storetypes.CommitMultiStore
// SnapshotManager() *snapshots.Manager
// ValidatorKeyProvider() func() (cmtcrypto.PrivKey, error)
// Close() error
// }
var _ servertypes.Application = (*serverAppV1)(nil)
type serverAppV1 struct {
// serverv2.AppI[transaction.Tx]
App *app.LaconicApp
ABCI abci.Application
ctx context.Context
}
func (s *serverAppV1) Info(req *abci.InfoRequest) (*abci.InfoResponse, error) {
return s.ABCI.Info(s.ctx, req)
}
func (s *serverAppV1) Query(ctx context.Context, req *abci.QueryRequest) (*abci.QueryResponse, error) {
return s.ABCI.Query(ctx, req)
}
func (s *serverAppV1) CheckTx(req *abci.CheckTxRequest) (*abci.CheckTxResponse, error) {
return s.ABCI.CheckTx(s.ctx, req)
}
func (s *serverAppV1) InitChain(req *abci.InitChainRequest) (*abci.InitChainResponse, error) {
return s.ABCI.InitChain(s.ctx, req)
}
func (s *serverAppV1) PrepareProposal(req *abci.PrepareProposalRequest) (*abci.PrepareProposalResponse, error) {
return s.ABCI.PrepareProposal(s.ctx, req)
}
func (s *serverAppV1) ProcessProposal(req *abci.ProcessProposalRequest) (*abci.ProcessProposalResponse, error) {
return s.ABCI.ProcessProposal(s.ctx, req)
}
func (s *serverAppV1) FinalizeBlock(req *abci.FinalizeBlockRequest) (*abci.FinalizeBlockResponse, error) {
return s.ABCI.FinalizeBlock(s.ctx, req)
}
func (s *serverAppV1) ExtendVote(ctx context.Context, req *abci.ExtendVoteRequest) (*abci.ExtendVoteResponse, error) {
return s.ABCI.ExtendVote(ctx, req)
}
func (s *serverAppV1) VerifyVoteExtension(req *abci.VerifyVoteExtensionRequest) (*abci.VerifyVoteExtensionResponse, error) {
return s.ABCI.VerifyVoteExtension(s.ctx, req)
}
func (s *serverAppV1) Commit() (*abci.CommitResponse, error) {
return s.ABCI.Commit(s.ctx, nil)
}
func (s *serverAppV1) ListSnapshots(req *abci.ListSnapshotsRequest) (*abci.ListSnapshotsResponse, error) {
return s.ABCI.ListSnapshots(s.ctx, req)
}
func (s *serverAppV1) OfferSnapshot(req *abci.OfferSnapshotRequest) (*abci.OfferSnapshotResponse, error) {
return s.ABCI.OfferSnapshot(s.ctx, req)
}
func (s *serverAppV1) LoadSnapshotChunk(req *abci.LoadSnapshotChunkRequest) (*abci.LoadSnapshotChunkResponse, error) {
return s.ABCI.LoadSnapshotChunk(s.ctx, req)
}
func (s *serverAppV1) ApplySnapshotChunk(req *abci.ApplySnapshotChunkRequest) (*abci.ApplySnapshotChunkResponse, error) {
return s.ABCI.ApplySnapshotChunk(s.ctx, req)
}
// Placeholder implementations for the API, gRPC, and services registration
func (s *serverAppV1) RegisterAPIRoutes(apiServer *api.Server, apiConfig config.APIConfig) {
// Implement API route registration
}
func (s *serverAppV1) RegisterGRPCServer(grpcServer grpc.Server) {
// Implement gRPC server registration
}
func (s *serverAppV1) RegisterTxService(clientCtx client.Context) {
// Implement Tx service registration
}
func (s *serverAppV1) RegisterTendermintService(clientCtx client.Context) {
// Implement Tendermint service registration
}
func (s *serverAppV1) RegisterNodeService(clientCtx client.Context, cfg config.Config) {
// Implement Node service registration
}
type unsupportedMethod struct {
method string
}
func (u unsupportedMethod) Error() string {
return "unsupported method: " + u.method
}
func (s *serverAppV1) CommitMultiStore() storetypes.CommitMultiStore {
panic(unsupportedMethod{"CommitMultiStore"})
return nil
}
func (s *serverAppV1) SnapshotManager() *snapshots.Manager {
panic(unsupportedMethod{"SnapshotManager"})
return nil
}
func (s *serverAppV1) ValidatorKeyProvider() func() (cmtcrypto.PrivKey, error) {
panic(unsupportedMethod{"ValidatorKeyProvider"})
return nil
}
func (s *serverAppV1) Close() error {
return s.App.Close()
}

169
tests/e2e/util.go Normal file
View File

@ -0,0 +1,169 @@
package e2e
import (
"context"
"encoding/json"
"io"
// client "cosmossdk.io/client/v2"
appmodulev2 "cosmossdk.io/core/appmodule/v2"
"cosmossdk.io/core/store"
"cosmossdk.io/core/transaction"
"cosmossdk.io/log"
"cosmossdk.io/server/v2/appmanager"
"cosmossdk.io/server/v2/cometbft"
"cosmossdk.io/server/v2/cometbft/mempool"
"cosmossdk.io/server/v2/stf"
"cosmossdk.io/server/v2/stf/branch"
consensustypes "cosmossdk.io/x/consensus/types"
v1 "github.com/cometbft/cometbft/api/cometbft/types/v1"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/gogoproto/proto"
gogotypes "github.com/cosmos/gogoproto/types"
"git.vdb.to/cerc-io/laconicd/app"
cometmock "git.vdb.to/cerc-io/laconicd/testutil/cometbft/mock"
"git.vdb.to/cerc-io/laconicd/utils"
)
var actorName = []byte("cookies")
func getQueryRouterBuilder[T any, PT interface {
*T
proto.Message
},
U any, UT interface {
*U
proto.Message
}](
// t *testing.T,
handler func(ctx context.Context, msg PT) (UT, error),
) (*stf.MsgRouterBuilder, error) {
// t.Helper()
queryRouterBuilder := stf.NewMsgRouterBuilder()
err := queryRouterBuilder.RegisterHandler(
proto.MessageName(PT(new(T))),
func(ctx context.Context, msg transaction.Msg) (msgResp transaction.Msg, err error) {
typedReq := msg.(PT)
typedResp, err := handler(ctx, typedReq)
if err != nil {
return nil, err
}
return typedResp, nil
},
)
return queryRouterBuilder, err
}
func getMsgRouterBuilder[T any, PT interface {
*T
transaction.Msg
},
U any, UT interface {
*U
transaction.Msg
}](
handler func(ctx context.Context, msg PT) (UT, error),
) (*stf.MsgRouterBuilder, error) {
// t.Helper()
msgRouterBuilder := stf.NewMsgRouterBuilder()
err := msgRouterBuilder.RegisterHandler(
proto.MessageName(PT(new(T))),
func(ctx context.Context, msg transaction.Msg) (msgResp transaction.Msg, err error) {
typedReq := msg.(PT)
typedResp, err := handler(ctx, typedReq)
if err != nil {
return nil, err
}
return typedResp, nil
},
)
return msgRouterBuilder, err
}
func setUpConsensus(
logger log.Logger,
gasLimit uint64,
mempool mempool.Mempool[app.Tx],
storageDir string,
txConfig client.TxConfig,
) (*cometbft.Consensus[app.Tx], error) {
msgRouterBuilder, err := getMsgRouterBuilder(func(ctx context.Context, msg *gogotypes.BoolValue) (*gogotypes.BoolValue, error) {
return nil, nil
})
if err != nil {
return nil, err
}
queryRouterBuilder, err := getQueryRouterBuilder(func(ctx context.Context, q *consensustypes.QueryParamsRequest) (*consensustypes.QueryParamsResponse, error) {
cParams := &v1.ConsensusParams{
Block: &v1.BlockParams{
MaxGas: 300000,
},
Feature: &v1.FeatureParams{
VoteExtensionsEnableHeight: &gogotypes.Int64Value{Value: 2},
},
}
return &consensustypes.QueryParamsResponse{
Params: cParams,
}, nil
})
if err != nil {
return nil, err
}
s, err := stf.New(
log.NewNopLogger().With("module", "stf"),
msgRouterBuilder,
queryRouterBuilder,
func(ctx context.Context, txs []app.Tx) error { return nil },
func(ctx context.Context) error { return nil },
func(ctx context.Context) error { return nil },
func(ctx context.Context, tx app.Tx) error { return nil },
func(ctx context.Context) ([]appmodulev2.ValidatorUpdate, error) { return nil, nil },
func(ctx context.Context, tx app.Tx, success bool) error { return nil },
branch.DefaultNewWriterMap,
)
if err != nil {
return nil, err
}
// todo pass tempdir
ss := cometmock.NewMockStorage(log.NewNopLogger(), storageDir)
sc := cometmock.NewMockCommiter(log.NewNopLogger(), string(actorName), "stf")
mockStore := cometmock.NewMockStore(ss, sc)
am := appmanager.New(appmanager.Config{
ValidateTxGasLimit: gasLimit,
QueryGasLimit: gasLimit,
SimulationGasLimit: gasLimit,
},
mockStore,
s,
func(ctx context.Context, src io.Reader, txHandler func(json.RawMessage) error) (store.WriterMap, error) {
_, st, err := mockStore.StateLatest()
if err != nil {
return nil, err
}
return branch.DefaultNewWriterMap(st), nil
},
nil,
)
return cometbft.NewConsensus(
logger,
"laconicd",
am,
func() error { return nil },
mempool,
map[string]struct{}{},
nil,
mockStore,
cometbft.Config{AppTomlConfig: cometbft.DefaultAppTomlConfig()},
utils.GenericTxDecoder[app.Tx]{txConfig},
"test",
), nil
}

View File

@ -18,7 +18,7 @@ type KeeperTestSuite struct {
}
func (kts *KeeperTestSuite) SetupTest() {
err := kts.TestFixture.Setup()
err := kts.TestFixture.Setup(kts.T())
assert.Nil(kts.T(), err)
qr := kts.App.QueryHelper()

View File

@ -5,12 +5,9 @@ import (
"fmt"
"time"
"cosmossdk.io/math"
sdkmath "cosmossdk.io/math"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
integrationTest "git.vdb.to/cerc-io/laconicd/tests/integration"
types "git.vdb.to/cerc-io/laconicd/x/auction"
)
@ -322,13 +319,13 @@ func (kts *KeeperTestSuite) TestGrpcQueryBalance() {
func (kts *KeeperTestSuite) createAuctionAndCommitBid(commitBid bool) (*types.Auction, *types.Bid, error) {
ctx, k := kts.SdkCtx, kts.AuctionKeeper
accCount := 1
numAccounts := 1
if commitBid {
accCount++
numAccounts++
}
// Create funded account(s)
accounts := simtestutil.AddTestAddrs(kts.BankKeeper, integrationTest.BondDenomProvider{}, ctx, accCount, math.NewInt(1000000))
accounts := kts.MakeTestAccounts(numAccounts, sdkmath.NewInt(1000000))
auction, err := k.CreateAuction(
ctx,

View File

@ -18,7 +18,7 @@ type KeeperTestSuite struct {
}
func (kts *KeeperTestSuite) SetupTest() {
err := kts.TestFixture.Setup()
err := kts.TestFixture.Setup(kts.T())
assert.Nil(kts.T(), err)
qr := kts.App.QueryHelper()

View File

@ -5,10 +5,8 @@ import (
"fmt"
"cosmossdk.io/math"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
integrationTest "git.vdb.to/cerc-io/laconicd/tests/integration"
types "git.vdb.to/cerc-io/laconicd/x/bond"
)
@ -196,10 +194,9 @@ func (kts *KeeperTestSuite) TestGrpcGetModuleBalance() {
func (kts *KeeperTestSuite) createBond() (*types.Bond, error) {
ctx, k := kts.SdkCtx, kts.BondKeeper
accCount := 1
// Create funded account(s)
accounts := simtestutil.AddTestAddrs(kts.BankKeeper, integrationTest.BondDenomProvider{}, ctx, accCount, math.NewInt(1000))
accounts := kts.MakeTestAccounts(1, math.NewInt(1000))
bond, err := k.CreateBond(ctx, accounts[0], sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(10))))
if err != nil {

View File

@ -2,27 +2,32 @@ package integration_test
import (
"context"
"testing"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/log"
"cosmossdk.io/math"
storetypes "cosmossdk.io/store/types"
cmtprototypes "github.com/cometbft/cometbft/api/cometbft/types/v1"
"cosmossdk.io/x/bank"
bankkeeper "cosmossdk.io/x/bank/keeper"
banktypes "cosmossdk.io/x/bank/types"
minttypes "cosmossdk.io/x/mint/types"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil"
"github.com/cosmos/cosmos-sdk/runtime"
"github.com/cosmos/cosmos-sdk/testutil/integration"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
"github.com/cosmos/cosmos-sdk/x/auth"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation"
authtestutil "github.com/cosmos/cosmos-sdk/x/auth/testutil"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
gomock "go.uber.org/mock/gomock"
"git.vdb.to/cerc-io/laconicd/utils"
auctionTypes "git.vdb.to/cerc-io/laconicd/x/auction"
auctionkeeper "git.vdb.to/cerc-io/laconicd/x/auction/keeper"
auctionmodule "git.vdb.to/cerc-io/laconicd/x/auction/module"
@ -49,12 +54,13 @@ type TestFixture struct {
RegistryKeeper registrykeeper.Keeper
}
func (tf *TestFixture) Setup() error {
func (tf *TestFixture) Setup(t *testing.T) error {
keys := storetypes.NewKVStoreKeys(
authtypes.StoreKey, banktypes.StoreKey, auctionTypes.StoreKey, bondTypes.StoreKey, registryTypes.StoreKey,
)
cdc := moduletestutil.MakeTestEncodingConfig(
auth.AppModuleBasic{},
codectestutil.CodecOptions{},
auth.AppModule{},
auctionmodule.AppModule{},
bondmodule.AppModule{},
registrymodule.AppModule{},
@ -63,10 +69,20 @@ func (tf *TestFixture) Setup() error {
logger := log.NewNopLogger() // Use log.NewTestLogger(kts.T()) for help with debugging
cms := integration.CreateMultiStore(keys, logger)
newCtx := sdk.NewContext(cms, cmtprototypes.Header{}, true, logger)
newCtx := sdk.NewContext(cms, true, logger)
authority := authtypes.NewModuleAddress("gov")
// gomock initializations
ctrl := gomock.NewController(t)
accountsModKeeper := authtestutil.NewMockAccountsModKeeper(ctrl)
acctNum := uint64(0)
accountsModKeeper.EXPECT().NextAccountNumber(gomock.Any()).AnyTimes().DoAndReturn(func(ctx context.Context) (uint64, error) {
currNum := acctNum
acctNum++
return currNum, nil
})
maccPerms := map[string][]string{
minttypes.ModuleName: {authtypes.Minter},
auctionTypes.ModuleName: {},
@ -78,12 +94,13 @@ func (tf *TestFixture) Setup() error {
}
accountKeeper := authkeeper.NewAccountKeeper(
runtime.NewEnvironment(runtime.NewKVStoreService(keys[authtypes.StoreKey]), logger),
cdc,
runtime.NewKVStoreService(keys[authtypes.StoreKey]),
authtypes.ProtoBaseAccount,
accountsModKeeper,
maccPerms,
addresscodec.NewBech32Codec(sdk.Bech32MainPrefix),
sdk.Bech32MainPrefix,
utils.NewAddressCodec(),
sdk.GetConfig().GetBech32AccountAddrPrefix(),
authority.String(),
)
@ -91,12 +108,11 @@ func (tf *TestFixture) Setup() error {
accountKeeper.GetAuthority(): false,
}
bankKeeper := bankkeeper.NewBaseKeeper(
runtime.NewEnvironment(runtime.NewKVStoreService(keys[banktypes.StoreKey]), logger),
cdc,
runtime.NewKVStoreService(keys[banktypes.StoreKey]),
accountKeeper,
blockedAddresses,
authority.String(),
log.NewNopLogger(),
)
auctionKeeper := auctionkeeper.NewKeeper(cdc, runtime.NewKVStoreService(keys[auctionTypes.StoreKey]), accountKeeper, bankKeeper, authority.String())
@ -113,19 +129,27 @@ func (tf *TestFixture) Setup() error {
authority.String(),
)
authModule := auth.NewAppModule(cdc, accountKeeper, authsims.RandomGenesisAccounts, nil)
bankModule := bank.NewAppModule(cdc, bankKeeper, accountKeeper, nil)
authModule := auth.NewAppModule(cdc, accountKeeper, accountsModKeeper, authsims.RandomGenesisAccounts, nil)
bankModule := bank.NewAppModule(cdc, bankKeeper, accountKeeper)
auctionModule := auctionmodule.NewAppModule(cdc, auctionKeeper)
bondModule := bondmodule.NewAppModule(cdc, bondKeeper)
registryModule := registrymodule.NewAppModule(cdc, registryKeeper)
integrationApp := integration.NewIntegrationApp(newCtx, logger, keys, cdc, map[string]appmodule.AppModule{
authtypes.ModuleName: authModule,
banktypes.ModuleName: bankModule,
auctionTypes.ModuleName: auctionModule,
bondTypes.ModuleName: bondModule,
registryTypes.ModuleName: registryModule,
})
router := baseapp.NewMsgServiceRouter()
queryRouter := baseapp.NewGRPCQueryRouter()
integrationApp := integration.NewIntegrationApp(
newCtx, logger, keys, cdc,
utils.NewAddressCodec(),
utils.NewValAddressCodec(),
map[string]appmodule.AppModule{
authtypes.ModuleName: authModule,
banktypes.ModuleName: bankModule,
auctionTypes.ModuleName: auctionModule,
bondTypes.ModuleName: bondModule,
registryTypes.ModuleName: registryModule,
},
router, queryRouter)
sdkCtx := sdk.UnwrapSDKContext(integrationApp.Context())
@ -158,8 +182,24 @@ func (tf *TestFixture) Setup() error {
return nil
}
type BondDenomProvider struct{}
func (kts *TestFixture) MakeTestAccounts(numAccounts int, funds math.Int) []sdk.AccAddress {
accounts := simtestutil.CreateRandomAccounts(numAccounts)
coins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, funds))
const mintModuleName = "mint"
for _, addr := range accounts {
println("funding test account:", addr.String())
if err := kts.BankKeeper.MintCoins(kts.SdkCtx, mintModuleName, coins); err != nil {
panic(err)
}
func (bdp BondDenomProvider) BondDenom(ctx context.Context) (string, error) {
return sdk.DefaultBondDenom, nil
if err := kts.BankKeeper.SendCoinsFromModuleToAccount(kts.SdkCtx, mintModuleName, addr, coins); err != nil {
panic(err)
}
}
for _, acct := range accounts {
kts.AccountKeeper.SetAccount(kts.SdkCtx, kts.AccountKeeper.NewAccountWithAddress(kts.SdkCtx, acct))
}
return accounts
}

View File

@ -4,7 +4,6 @@ import (
"testing"
"cosmossdk.io/math"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
@ -25,7 +24,7 @@ type KeeperTestSuite struct {
}
func (kts *KeeperTestSuite) SetupTest() {
err := kts.TestFixture.Setup()
err := kts.TestFixture.Setup(kts.T())
assert.Nil(kts.T(), err)
// set default params
@ -49,7 +48,7 @@ func (kts *KeeperTestSuite) createBond() (*bondTypes.Bond, error) {
ctx := kts.SdkCtx
// Create a funded account
kts.accounts = simtestutil.AddTestAddrs(kts.BankKeeper, integrationTest.BondDenomProvider{}, ctx, 1, math.NewInt(1000000000000))
kts.accounts = kts.MakeTestAccounts(1, math.NewInt(1000000000000))
bond, err := kts.BondKeeper.CreateBond(ctx, kts.accounts[0], sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(1000000000))))
if err != nil {

View File

@ -6,17 +6,16 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
authcli "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
"git.vdb.to/cerc-io/laconicd/testutil/network"
)
// Reference: https://github.com/cosmos/cosmos-sdk/blob/v0.50.3/testutil/cli/tx.go#L15
// CheckTxCode verifies that the transaction result returns a specific code
// Takes a network, wait for two blocks and fetch the transaction from its hash
func CheckTxCode(network *network.Network, clientCtx client.Context, txHash string, expectedCode uint32) error {
func CheckTxCode(network network.NetworkI, clientCtx client.Context, txHash string, expectedCode uint32) error {
// wait for 2 blocks
for i := 0; i < 2; i++ {
if err := network.WaitForNextBlock(); err != nil {

View File

@ -0,0 +1,20 @@
package mock
import (
"context"
"cosmossdk.io/core/transaction"
"cosmossdk.io/server/v2/cometbft/mempool"
)
var _ mempool.Mempool[transaction.Tx] = (*MockMempool[transaction.Tx])(nil)
// MockMempool implements Mempool
// Used for testing instead of NoOpMempool
type MockMempool[T transaction.Tx] struct{}
func (MockMempool[T]) Insert(context.Context, T) error { return nil }
func (MockMempool[T]) Select(context.Context, []T) mempool.Iterator[T] { return nil }
func (MockMempool[T]) SelectBy(context.Context, []T, func(T) bool) {}
func (MockMempool[T]) CountTx() int { return 0 }
func (MockMempool[T]) Remove(T) error { return nil }

View File

@ -0,0 +1,65 @@
package mock
import (
corestore "cosmossdk.io/core/store"
)
// ReaderMap defines an adapter around a RootStore that only exposes read-only
// operations. This is useful for exposing a read-only view of the RootStore at
// a specific version in history, which could also be the latest state.
type ReaderMap struct {
store *MockStore
version uint64
}
func NewMockReaderMap(v uint64, rs *MockStore) *ReaderMap {
return &ReaderMap{
store: rs,
version: v,
}
}
func (roa *ReaderMap) GetReader(actor []byte) (corestore.Reader, error) {
return NewMockReader(roa.version, roa.store, actor), nil
}
// MockReader represents a read-only adapter for accessing data from the root store.
type MockReader struct {
version uint64 // The version of the data.
store *MockStore // The root store to read data from.
actor []byte // The actor associated with the data.
}
func NewMockReader(v uint64, rs *MockStore, actor []byte) *MockReader {
return &MockReader{
version: v,
store: rs,
actor: actor,
}
}
func (roa *MockReader) Has(key []byte) (bool, error) {
val, err := roa.store.GetStateStorage().Has(roa.actor, roa.version, key)
if err != nil {
return false, err
}
return val, nil
}
func (roa *MockReader) Get(key []byte) ([]byte, error) {
result, err := roa.store.GetStateStorage().Get(roa.actor, roa.version, key)
if err != nil {
return nil, err
}
return result, nil
}
func (roa *MockReader) Iterator(start, end []byte) (corestore.Iterator, error) {
return roa.store.GetStateStorage().Iterator(roa.actor, roa.version, start, end)
}
func (roa *MockReader) ReverseIterator(start, end []byte) (corestore.Iterator, error) {
return roa.store.GetStateStorage().ReverseIterator(roa.actor, roa.version, start, end)
}

View File

@ -0,0 +1,143 @@
package mock
import (
"crypto/sha256"
"fmt"
"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"
dbm "cosmossdk.io/store/v2/db"
"cosmossdk.io/store/v2/proof"
"cosmossdk.io/store/v2/storage"
"cosmossdk.io/store/v2/storage/sqlite"
)
type MockStore struct {
Storage storev2.VersionedWriter
Committer storev2.Committer
}
func NewMockStorage(logger log.Logger, dir string) storev2.VersionedWriter {
storageDB, _ := sqlite.New(dir)
ss := storage.NewStorageStore(storageDB, logger)
return ss
}
func NewMockCommiter(logger log.Logger, actors ...string) storev2.Committer {
treeMap := make(map[string]commitment.Tree)
for _, actor := range actors {
tree := iavl.NewIavlTree(dbm.NewMemDB(), logger, iavl.DefaultConfig())
treeMap[actor] = tree
}
sc, _ := commitment.NewCommitStore(treeMap, treeMap, dbm.NewMemDB(), logger)
return sc
}
func NewMockStore(ss storev2.VersionedWriter, sc storev2.Committer) *MockStore {
return &MockStore{Storage: ss, Committer: sc}
}
func (s *MockStore) GetLatestVersion() (uint64, error) {
lastCommitID, err := s.LastCommitID()
if err != nil {
return 0, err
}
return lastCommitID.Version, nil
}
func (s *MockStore) StateLatest() (uint64, corestore.ReaderMap, error) {
v, err := s.GetLatestVersion()
if err != nil {
return 0, nil, err
}
return v, NewMockReaderMap(v, s), nil
}
func (s *MockStore) Commit(changeset *corestore.Changeset) (corestore.Hash, error) {
v, _, _ := s.StateLatest()
err := s.Storage.ApplyChangeset(v, changeset)
if err != nil {
return []byte{}, err
}
err = s.Committer.WriteChangeset(changeset)
if err != nil {
return []byte{}, err
}
commitInfo, err := s.Committer.Commit(v + 1)
fmt.Println("commitInfo", commitInfo, err)
return []byte{}, err
}
func (s *MockStore) StateAt(version uint64) (corestore.ReaderMap, error) {
info, err := s.Committer.GetCommitInfo(version)
if err != nil || info == nil {
return nil, fmt.Errorf("failed to get commit info for version %d: %w", version, err)
}
return NewMockReaderMap(version, s), nil
}
func (s *MockStore) GetStateStorage() storev2.VersionedWriter {
return s.Storage
}
func (s *MockStore) GetStateCommitment() storev2.Committer {
return s.Committer
}
func (s *MockStore) Query(storeKey []byte, version uint64, key []byte, prove bool) (storev2.QueryResult, error) {
state, err := s.StateAt(version)
if err != nil {
return storev2.QueryResult{}, err
}
reader, err := state.GetReader(storeKey)
if err != nil {
return storev2.QueryResult{}, err
}
value, err := reader.Get(key)
if err != nil {
return storev2.QueryResult{}, err
}
res := storev2.QueryResult{
Key: key,
Value: value,
Version: version,
}
return res, err
}
func (s *MockStore) LastCommitID() (proof.CommitID, error) {
v, err := s.GetStateCommitment().GetLatestVersion()
bz := sha256.Sum256([]byte{})
return proof.CommitID{
Version: v,
Hash: bz[:],
}, err
}
func (s *MockStore) SetInitialVersion(v uint64) error {
return s.Committer.SetInitialVersion(v)
}
func (s *MockStore) WorkingHash(changeset *corestore.Changeset) (corestore.Hash, error) {
v, _, _ := s.StateLatest()
err := s.Storage.ApplyChangeset(v, changeset)
if err != nil {
return []byte{}, err
}
err = s.Committer.WriteChangeset(changeset)
if err != nil {
return []byte{}, err
}
return []byte{}, nil
}

View File

@ -1,74 +0,0 @@
/*
Package network implements and exposes a fully operational in-process CometBFT
test network that consists of at least one or potentially many validators. This
test network can be used primarily for integration tests or unit test suites.
The test network utilizes SimApp as the ABCI application and uses all the modules
defined in the Cosmos SDK. An in-process test network can be configured with any
number of validators as well as account funds and even custom genesis state.
When creating a test network, a series of Validator objects are returned. Each
Validator object has useful information such as their address and public key. A
Validator will also provide its RPC, P2P, and API addresses that can be useful
for integration testing. In addition, a CometBFT local RPC client is also provided
which can be handy for making direct RPC calls to CometBFT.
Note, due to limitations in concurrency and the design of the RPC layer in
CometBFT, only the first Validator object will have an RPC and API client
exposed. Due to this exact same limitation, only a single test network can exist
at a time. A caller must be certain it calls Cleanup after it no longer needs
the network.
A typical testing flow might look like the following:
type IntegrationTestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
}
func (s *IntegrationTestSuite) SetupSuite() {
s.T().Log("setting up integration test suite")
cfg := network.DefaultConfig()
cfg.NumValidators = 1
s.cfg = cfg
var err error
s.network, err = network.New(s.T(), s.T().TempDir(), cfg)
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
}
func (s *IntegrationTestSuite) TearDownSuite() {
s.T().Log("tearing down integration test suite")
// This is important and must be called to ensure other tests can create
// a network!
s.network.Cleanup()
}
func (s *IntegrationTestSuite) TestQueryBalancesRequestHandlerFn() {
val := s.network.Validators[0]
baseURL := val.APIAddress
// Use baseURL to make API HTTP requests or use val.RPCClient to make direct
// CometBFT RPC calls.
// ...
}
func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
}
*/
package network
/*
NOTE:
Copied over from https://github.com/cosmos/cosmos-sdk/tree/v0.50.3/testutil/network
Patch:
- Skipped network.LatestHeight() call at the end of New()
- Removed block timeouts
*/

View File

@ -1,852 +0,0 @@
package network
import (
"bufio"
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"
"os"
"os/signal"
"path/filepath"
"strings"
"sync"
"syscall"
"testing"
"time"
"github.com/cometbft/cometbft/node"
cmtclient "github.com/cometbft/cometbft/rpc/client"
dbm "github.com/cosmos/cosmos-db"
"github.com/spf13/cobra"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"cosmossdk.io/depinject"
"cosmossdk.io/log"
sdkmath "cosmossdk.io/math"
"cosmossdk.io/math/unsafe"
pruningtypes "cosmossdk.io/store/pruning/types"
_ "cosmossdk.io/x/bank" // import bank as a blank
banktypes "cosmossdk.io/x/bank/types"
_ "cosmossdk.io/x/consensus" // import consensus as a blank
_ "cosmossdk.io/x/params" // import params as a blank
_ "cosmossdk.io/x/staking" // import staking as a blank
stakingtypes "cosmossdk.io/x/staking/types"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/grpc/cmtservice"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/runtime"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/server/api"
srvconfig "github.com/cosmos/cosmos-sdk/server/config"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
"github.com/cosmos/cosmos-sdk/testutil"
"github.com/cosmos/cosmos-sdk/testutil/configurator"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
_ "github.com/cosmos/cosmos-sdk/x/auth" // import auth as a blank
_ "github.com/cosmos/cosmos-sdk/x/auth/tx/config" // import auth tx config as a blank
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/genutil"
)
// package-wide network lock to only allow one test network at a time
var (
lock = new(sync.Mutex)
portPool = make(chan string, 200)
)
func init() {
closeFns := []func() error{}
for i := 0; i < 200; i++ {
_, port, closeFn, err := FreeTCPAddr()
if err != nil {
panic(err)
}
portPool <- port
closeFns = append(closeFns, closeFn)
}
for _, closeFn := range closeFns {
err := closeFn()
if err != nil {
panic(err)
}
}
}
// AppConstructor defines a function which accepts a network configuration and
// creates an ABCI Application to provide to CometBFT.
type (
AppConstructor = func(val ValidatorI) servertypes.Application
TestFixtureFactory = func() TestFixture
)
type TestFixture struct {
AppConstructor AppConstructor
GenesisState map[string]json.RawMessage
EncodingConfig moduletestutil.TestEncodingConfig
}
// Config defines the necessary configuration used to bootstrap and start an
// in-process local testing network.
type Config struct {
Codec codec.Codec
LegacyAmino *codec.LegacyAmino // TODO: Remove!
InterfaceRegistry codectypes.InterfaceRegistry
TxConfig client.TxConfig
AccountRetriever client.AccountRetriever
AppConstructor AppConstructor // the ABCI application constructor
GenesisState map[string]json.RawMessage // custom genesis state to provide
TimeoutCommit time.Duration // the consensus commitment timeout
ChainID string // the network chain-id
NumValidators int // the total number of validators to create and bond
Mnemonics []string // custom user-provided validator operator mnemonics
BondDenom string // the staking bond denomination
MinGasPrices string // the minimum gas prices each validator will accept
AccountTokens sdkmath.Int // the amount of unique validator tokens (e.g. 1000node0)
StakingTokens sdkmath.Int // the amount of tokens each validator has available to stake
BondedTokens sdkmath.Int // the amount of tokens each validator stakes
PruningStrategy string // the pruning strategy each validator will have
EnableLogging bool // enable logging to STDOUT
CleanupDir bool // remove base temporary directory during cleanup
SigningAlgo string // signing algorithm for keys
KeyringOptions []keyring.Option // keyring configuration options
RPCAddress string // RPC listen address (including port)
APIAddress string // REST API listen address (including port)
GRPCAddress string // GRPC server listen address (including port)
PrintMnemonic bool // print the mnemonic of first validator as log output for testing
}
// DefaultConfig returns a sane default configuration suitable for nearly all
// testing requirements.
func DefaultConfig(factory TestFixtureFactory) Config {
fixture := factory()
return Config{
Codec: fixture.EncodingConfig.Codec,
TxConfig: fixture.EncodingConfig.TxConfig,
LegacyAmino: fixture.EncodingConfig.Amino,
InterfaceRegistry: fixture.EncodingConfig.InterfaceRegistry,
AccountRetriever: authtypes.AccountRetriever{},
AppConstructor: fixture.AppConstructor,
GenesisState: fixture.GenesisState,
TimeoutCommit: 2 * time.Second,
ChainID: "chain-" + unsafe.Str(6),
NumValidators: 4,
BondDenom: sdk.DefaultBondDenom,
MinGasPrices: fmt.Sprintf("0.000006%s", sdk.DefaultBondDenom),
AccountTokens: sdk.TokensFromConsensusPower(1000, sdk.DefaultPowerReduction),
StakingTokens: sdk.TokensFromConsensusPower(500, sdk.DefaultPowerReduction),
BondedTokens: sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction),
PruningStrategy: pruningtypes.PruningOptionNothing,
CleanupDir: true,
SigningAlgo: string(hd.Secp256k1Type),
KeyringOptions: []keyring.Option{},
PrintMnemonic: false,
}
}
// MinimumAppConfig defines the minimum of modules required for a call to New to succeed
func MinimumAppConfig() depinject.Config {
return configurator.NewAppConfig(
configurator.AuthModule(),
configurator.ParamsModule(),
configurator.BankModule(),
configurator.GenutilModule(),
configurator.StakingModule(),
configurator.ConsensusModule(),
configurator.TxModule(),
)
}
func DefaultConfigWithAppConfig(appConfig depinject.Config) (Config, error) {
var (
appBuilder *runtime.AppBuilder
txConfig client.TxConfig
legacyAmino *codec.LegacyAmino
cdc codec.Codec
interfaceRegistry codectypes.InterfaceRegistry
)
if err := depinject.Inject(
depinject.Configs(
appConfig,
depinject.Supply(log.NewNopLogger()),
),
&appBuilder,
&txConfig,
&cdc,
&legacyAmino,
&interfaceRegistry,
); err != nil {
return Config{}, err
}
cfg := DefaultConfig(func() TestFixture {
return TestFixture{}
})
cfg.Codec = cdc
cfg.TxConfig = txConfig
cfg.LegacyAmino = legacyAmino
cfg.InterfaceRegistry = interfaceRegistry
cfg.GenesisState = appBuilder.DefaultGenesis()
cfg.AppConstructor = func(val ValidatorI) servertypes.Application {
// we build a unique app instance for every validator here
var appBuilder *runtime.AppBuilder
if err := depinject.Inject(
depinject.Configs(
appConfig,
depinject.Supply(val.GetCtx().Logger),
),
&appBuilder); err != nil {
panic(err)
}
app := appBuilder.Build(
dbm.NewMemDB(),
nil,
baseapp.SetPruning(pruningtypes.NewPruningOptionsFromString(val.GetAppConfig().Pruning)),
baseapp.SetMinGasPrices(val.GetAppConfig().MinGasPrices),
baseapp.SetChainID(cfg.ChainID),
)
testdata.RegisterQueryServer(app.GRPCQueryRouter(), testdata.QueryImpl{})
if err := app.Load(true); err != nil {
panic(err)
}
return app
}
return cfg, nil
}
type (
// Network defines a local in-process testing network using SimApp. It can be
// configured to start any number of validators, each with its own RPC and API
// clients. Typically, this test network would be used in client and integration
// testing where user input is expected.
//
// Note, due to CometBFT constraints in regards to RPC functionality, there
// may only be one test network running at a time. Thus, any caller must be
// sure to Cleanup after testing is finished in order to allow other tests
// to create networks. In addition, only the first validator will have a valid
// RPC and API server/client.
Network struct {
Logger Logger
BaseDir string
Validators []*Validator
Config Config
}
// Validator defines an in-process CometBFT validator node. Through this object,
// a client can make RPC and API calls and interact with any client command
// or handler.
Validator struct {
AppConfig *srvconfig.Config
ClientCtx client.Context
Ctx *server.Context
Dir string
NodeID string
PubKey cryptotypes.PubKey
Moniker string
APIAddress string
RPCAddress string
P2PAddress string
Address sdk.AccAddress
ValAddress sdk.ValAddress
RPCClient cmtclient.Client
app servertypes.Application
tmNode *node.Node
api *api.Server
grpc *grpc.Server
grpcWeb *http.Server
errGroup *errgroup.Group
cancelFn context.CancelFunc
}
// ValidatorI expose a validator's context and configuration
ValidatorI interface {
GetCtx() *server.Context
GetAppConfig() *srvconfig.Config
}
// Logger is a network logger interface that exposes testnet-level Log() methods for an in-process testing network
// This is not to be confused with logging that may happen at an individual node or validator level
Logger interface {
Log(args ...interface{})
Logf(format string, args ...interface{})
}
)
var (
_ Logger = (*testing.T)(nil)
_ Logger = (*CLILogger)(nil)
_ ValidatorI = Validator{}
)
func (v Validator) GetCtx() *server.Context {
return v.Ctx
}
func (v Validator) GetAppConfig() *srvconfig.Config {
return v.AppConfig
}
// CLILogger wraps a cobra.Command and provides command logging methods.
type CLILogger struct {
cmd *cobra.Command
}
// Log logs given args.
func (s CLILogger) Log(args ...interface{}) {
s.cmd.Println(args...)
}
// Logf logs given args according to a format specifier.
func (s CLILogger) Logf(format string, args ...interface{}) {
s.cmd.Printf(format, args...)
}
// NewCLILogger creates a new CLILogger.
func NewCLILogger(cmd *cobra.Command) CLILogger {
return CLILogger{cmd}
}
// New creates a new Network for integration tests or in-process testnets run via the CLI
func New(l Logger, baseDir string, cfg Config) (*Network, error) {
// only one caller/test can create and use a network at a time
l.Log("acquiring test network lock")
lock.Lock()
network := &Network{
Logger: l,
BaseDir: baseDir,
Validators: make([]*Validator, cfg.NumValidators),
Config: cfg,
}
l.Logf("preparing test network with chain-id \"%s\"\n", cfg.ChainID)
monikers := make([]string, cfg.NumValidators)
nodeIDs := make([]string, cfg.NumValidators)
valPubKeys := make([]cryptotypes.PubKey, cfg.NumValidators)
var (
genAccounts []authtypes.GenesisAccount
genBalances []banktypes.Balance
genFiles []string
)
buf := bufio.NewReader(os.Stdin)
// generate private keys, node IDs, and initial transactions
for i := 0; i < cfg.NumValidators; i++ {
appCfg := srvconfig.DefaultConfig()
appCfg.Pruning = cfg.PruningStrategy
appCfg.MinGasPrices = cfg.MinGasPrices
appCfg.API.Enable = true
appCfg.API.Swagger = false
appCfg.Telemetry.Enabled = false
ctx := server.NewDefaultContext()
cmtCfg := ctx.Config
cmtCfg.Consensus.TimeoutCommit = cfg.TimeoutCommit
// Only allow the first validator to expose an RPC, API and gRPC
// server/client due to CometBFT in-process constraints.
apiAddr := ""
cmtCfg.RPC.ListenAddress = ""
appCfg.GRPC.Enable = false
appCfg.GRPCWeb.Enable = false
apiListenAddr := ""
if i == 0 {
if cfg.APIAddress != "" {
apiListenAddr = cfg.APIAddress
} else {
if len(portPool) == 0 {
return nil, fmt.Errorf("failed to get port for API server")
}
port := <-portPool
apiListenAddr = fmt.Sprintf("tcp://0.0.0.0:%s", port)
}
appCfg.API.Address = apiListenAddr
apiURL, err := url.Parse(apiListenAddr)
if err != nil {
return nil, err
}
apiAddr = fmt.Sprintf("http://%s:%s", apiURL.Hostname(), apiURL.Port())
if cfg.RPCAddress != "" {
cmtCfg.RPC.ListenAddress = cfg.RPCAddress
} else {
if len(portPool) == 0 {
return nil, fmt.Errorf("failed to get port for RPC server")
}
port := <-portPool
cmtCfg.RPC.ListenAddress = fmt.Sprintf("tcp://0.0.0.0:%s", port)
}
if cfg.GRPCAddress != "" {
appCfg.GRPC.Address = cfg.GRPCAddress
} else {
if len(portPool) == 0 {
return nil, fmt.Errorf("failed to get port for GRPC server")
}
port := <-portPool
appCfg.GRPC.Address = fmt.Sprintf("0.0.0.0:%s", port)
}
appCfg.GRPC.Enable = true
appCfg.GRPCWeb.Enable = true
}
logger := log.NewNopLogger()
if cfg.EnableLogging {
logger = log.NewLogger(os.Stdout) // TODO(mr): enable selection of log destination.
}
ctx.Logger = logger
nodeDirName := fmt.Sprintf("node%d", i)
nodeDir := filepath.Join(network.BaseDir, nodeDirName, "simd")
clientDir := filepath.Join(network.BaseDir, nodeDirName, "simcli")
gentxsDir := filepath.Join(network.BaseDir, "gentxs")
err := os.MkdirAll(filepath.Join(nodeDir, "config"), 0o755)
if err != nil {
return nil, err
}
err = os.MkdirAll(clientDir, 0o755)
if err != nil {
return nil, err
}
cmtCfg.SetRoot(nodeDir)
cmtCfg.Moniker = nodeDirName
monikers[i] = nodeDirName
if len(portPool) == 0 {
return nil, fmt.Errorf("failed to get port for Proxy server")
}
port := <-portPool
proxyAddr := fmt.Sprintf("tcp://0.0.0.0:%s", port)
cmtCfg.ProxyApp = proxyAddr
if len(portPool) == 0 {
return nil, fmt.Errorf("failed to get port for Proxy server")
}
port = <-portPool
p2pAddr := fmt.Sprintf("tcp://0.0.0.0:%s", port)
cmtCfg.P2P.ListenAddress = p2pAddr
cmtCfg.P2P.AddrBookStrict = false
cmtCfg.P2P.AllowDuplicateIP = true
nodeID, pubKey, err := genutil.InitializeNodeValidatorFiles(cmtCfg)
if err != nil {
return nil, err
}
nodeIDs[i] = nodeID
valPubKeys[i] = pubKey
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, clientDir, buf, cfg.Codec, cfg.KeyringOptions...)
if err != nil {
return nil, err
}
keyringAlgos, _ := kb.SupportedAlgorithms()
algo, err := keyring.NewSigningAlgoFromString(cfg.SigningAlgo, keyringAlgos)
if err != nil {
return nil, err
}
var mnemonic string
if i < len(cfg.Mnemonics) {
mnemonic = cfg.Mnemonics[i]
}
addr, secret, err := testutil.GenerateSaveCoinKey(kb, nodeDirName, mnemonic, true, algo)
if err != nil {
return nil, err
}
// if PrintMnemonic is set to true, we print the first validator node's secret to the network's logger
// for debugging and manual testing
if cfg.PrintMnemonic && i == 0 {
printMnemonic(l, secret)
}
info := map[string]string{"secret": secret}
infoBz, err := json.Marshal(info)
if err != nil {
return nil, err
}
// save private key seed words
err = writeFile(fmt.Sprintf("%v.json", "key_seed"), clientDir, infoBz)
if err != nil {
return nil, err
}
balances := sdk.NewCoins(
sdk.NewCoin(fmt.Sprintf("%stoken", nodeDirName), cfg.AccountTokens),
sdk.NewCoin(cfg.BondDenom, cfg.StakingTokens),
)
genFiles = append(genFiles, cmtCfg.GenesisFile())
genBalances = append(genBalances, banktypes.Balance{Address: addr.String(), Coins: balances.Sort()})
genAccounts = append(genAccounts, authtypes.NewBaseAccount(addr, nil, 0, 0))
commission, err := sdkmath.LegacyNewDecFromStr("0.5")
if err != nil {
return nil, err
}
createValMsg, err := stakingtypes.NewMsgCreateValidator(
sdk.ValAddress(addr).String(),
valPubKeys[i],
sdk.NewCoin(cfg.BondDenom, cfg.BondedTokens),
stakingtypes.NewDescription(nodeDirName, "", "", "", ""),
stakingtypes.NewCommissionRates(commission, sdkmath.LegacyOneDec(), sdkmath.LegacyOneDec()),
sdkmath.OneInt(),
)
if err != nil {
return nil, err
}
p2pURL, err := url.Parse(p2pAddr)
if err != nil {
return nil, err
}
memo := fmt.Sprintf("%s@%s:%s", nodeIDs[i], p2pURL.Hostname(), p2pURL.Port())
fee := sdk.NewCoins(sdk.NewCoin(fmt.Sprintf("%stoken", nodeDirName), sdkmath.NewInt(0)))
txBuilder := cfg.TxConfig.NewTxBuilder()
err = txBuilder.SetMsgs(createValMsg)
if err != nil {
return nil, err
}
txBuilder.SetFeeAmount(fee) // Arbitrary fee
txBuilder.SetGasLimit(1000000) // Need at least 100386
txBuilder.SetMemo(memo)
txFactory := tx.Factory{}
txFactory = txFactory.
WithChainID(cfg.ChainID).
WithMemo(memo).
WithKeybase(kb).
WithTxConfig(cfg.TxConfig)
err = tx.Sign(context.Background(), txFactory, nodeDirName, txBuilder, true)
if err != nil {
return nil, err
}
txBz, err := cfg.TxConfig.TxJSONEncoder()(txBuilder.GetTx())
if err != nil {
return nil, err
}
err = writeFile(fmt.Sprintf("%v.json", nodeDirName), gentxsDir, txBz)
if err != nil {
return nil, err
}
srvconfig.WriteConfigFile(filepath.Join(nodeDir, "config", "app.toml"), appCfg)
clientCtx := client.Context{}.
WithKeyringDir(clientDir).
WithKeyring(kb).
WithHomeDir(cmtCfg.RootDir).
WithChainID(cfg.ChainID).
WithInterfaceRegistry(cfg.InterfaceRegistry).
WithCodec(cfg.Codec).
WithLegacyAmino(cfg.LegacyAmino).
WithTxConfig(cfg.TxConfig).
WithAccountRetriever(cfg.AccountRetriever).
WithNodeURI(cmtCfg.RPC.ListenAddress)
// Provide ChainID here since we can't modify it in the Comet config.
ctx.Viper.Set(flags.FlagChainID, cfg.ChainID)
network.Validators[i] = &Validator{
AppConfig: appCfg,
ClientCtx: clientCtx,
Ctx: ctx,
Dir: filepath.Join(network.BaseDir, nodeDirName),
NodeID: nodeID,
PubKey: pubKey,
Moniker: nodeDirName,
RPCAddress: cmtCfg.RPC.ListenAddress,
P2PAddress: cmtCfg.P2P.ListenAddress,
APIAddress: apiAddr,
Address: addr,
ValAddress: sdk.ValAddress(addr),
}
}
err := initGenFiles(cfg, genAccounts, genBalances, genFiles)
if err != nil {
return nil, err
}
err = collectGenFiles(cfg, network.Validators, network.BaseDir)
if err != nil {
return nil, err
}
l.Log("starting test network...")
for idx, v := range network.Validators {
if err := startInProcess(cfg, v); err != nil {
return nil, err
}
l.Log("started validator", idx)
}
// height, err := network.LatestHeight()
// if err != nil {
// return nil, err
// }
// l.Log("started test network at height:", height)
// Ensure we cleanup incase any test was abruptly halted (e.g. SIGINT) as any
// defer in a test would not be called.
trapSignal(network.Cleanup)
return network, nil
}
// trapSignal traps SIGINT and SIGTERM and calls os.Exit once a signal is received.
func trapSignal(cleanupFunc func()) {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig := <-sigs
if cleanupFunc != nil {
cleanupFunc()
}
exitCode := 128
switch sig {
case syscall.SIGINT:
exitCode += int(syscall.SIGINT)
case syscall.SIGTERM:
exitCode += int(syscall.SIGTERM)
}
os.Exit(exitCode)
}()
}
// LatestHeight returns the latest height of the network or an error if the
// query fails or no validators exist.
func (n *Network) LatestHeight() (int64, error) {
if len(n.Validators) == 0 {
return 0, errors.New("no validators available")
}
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
timeout := time.NewTimer(time.Second * 5)
defer timeout.Stop()
var latestHeight int64
val := n.Validators[0]
queryClient := cmtservice.NewServiceClient(val.ClientCtx)
for {
select {
case <-ticker.C:
done := make(chan struct{})
go func() {
res, err := queryClient.GetLatestBlock(context.Background(), &cmtservice.GetLatestBlockRequest{})
if err == nil && res != nil {
latestHeight = res.SdkBlock.Header.Height
}
done <- struct{}{}
}()
select {
case <-timeout.C:
return latestHeight, errors.New("timeout exceeded waiting for block")
case <-done:
if latestHeight != 0 {
return latestHeight, nil
}
}
default: //nolint: all
}
}
}
// WaitForHeight performs a blocking check where it waits for a block to be
// committed after a given block.
func (n *Network) WaitForHeight(h int64) (int64, error) {
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
if len(n.Validators) == 0 {
return 0, errors.New("no validators available")
}
var latestHeight int64
val := n.Validators[0]
queryClient := cmtservice.NewServiceClient(val.ClientCtx)
for {
select {
case <-ticker.C:
res, err := queryClient.GetLatestBlock(context.Background(), &cmtservice.GetLatestBlockRequest{})
if err == nil && res != nil {
latestHeight = res.GetSdkBlock().Header.Height
if latestHeight >= h {
return latestHeight, nil
}
}
default: //nolint: all
}
}
}
// RetryForBlocks will wait for the next block and execute the function provided.
// It will do this until the function returns a nil error or until the number of
// blocks has been reached.
func (n *Network) RetryForBlocks(retryFunc func() error, blocks int) error {
for i := 0; i < blocks; i++ {
_ = n.WaitForNextBlock()
err := retryFunc()
if err == nil {
return nil
}
// we've reached the last block to wait, return the error
if i == blocks-1 {
return err
}
}
return nil
}
// WaitForNextBlock waits for the next block to be committed, returning an error
// upon failure.
func (n *Network) WaitForNextBlock() error {
lastBlock, err := n.LatestHeight()
if err != nil {
return err
}
_, err = n.WaitForHeight(lastBlock + 1)
if err != nil {
return err
}
return err
}
// Cleanup removes the root testing (temporary) directory and stops both the
// CometBFT and API services. It allows other callers to create and start
// test networks. This method must be called when a test is finished, typically
// in a defer.
func (n *Network) Cleanup() {
defer func() {
lock.Unlock()
n.Logger.Log("released test network lock")
}()
n.Logger.Log("cleaning up test network...")
for _, v := range n.Validators {
// cancel the validator's context which will signal to the gRPC and API
// goroutines that they should gracefully exit.
v.cancelFn()
if err := v.errGroup.Wait(); err != nil {
n.Logger.Log("unexpected error waiting for validator gRPC and API processes to exit", "err", err)
}
if v.tmNode != nil && v.tmNode.IsRunning() {
if err := v.tmNode.Stop(); err != nil {
n.Logger.Log("failed to stop validator CometBFT node", "err", err)
}
}
if v.grpcWeb != nil {
_ = v.grpcWeb.Close()
}
if v.app != nil {
if err := v.app.Close(); err != nil {
n.Logger.Log("failed to stop validator ABCI application", "err", err)
}
}
}
time.Sleep(100 * time.Millisecond)
if n.Config.CleanupDir {
_ = os.RemoveAll(n.BaseDir)
}
n.Logger.Log("finished cleaning up test network")
}
// printMnemonic prints a provided mnemonic seed phrase on a network logger
// for debugging and manual testing
func printMnemonic(l Logger, secret string) {
lines := []string{
"THIS MNEMONIC IS FOR TESTING PURPOSES ONLY",
"DO NOT USE IN PRODUCTION",
"",
strings.Join(strings.Fields(secret)[0:8], " "),
strings.Join(strings.Fields(secret)[8:16], " "),
strings.Join(strings.Fields(secret)[16:24], " "),
}
lineLengths := make([]int, len(lines))
for i, line := range lines {
lineLengths[i] = len(line)
}
maxLineLength := 0
for _, lineLen := range lineLengths {
if lineLen > maxLineLength {
maxLineLength = lineLen
}
}
l.Log("\n")
l.Log(strings.Repeat("+", maxLineLength+8))
for _, line := range lines {
l.Logf("++ %s ++\n", centerText(line, maxLineLength))
}
l.Log(strings.Repeat("+", maxLineLength+8))
l.Log("\n")
}
// centerText centers text across a fixed width, filling either side with whitespace buffers
func centerText(text string, width int) string {
textLen := len(text)
leftBuffer := strings.Repeat(" ", (width-textLen)/2)
rightBuffer := strings.Repeat(" ", (width-textLen)/2+(width-textLen)%2)
return fmt.Sprintf("%s%s%s", leftBuffer, text, rightBuffer)
}

View File

@ -1,240 +0,0 @@
package network
import (
"context"
"encoding/json"
"fmt"
"net"
"os"
"path/filepath"
cmtcfg "github.com/cometbft/cometbft/config"
"github.com/cometbft/cometbft/node"
"github.com/cometbft/cometbft/p2p"
pvm "github.com/cometbft/cometbft/privval"
"github.com/cometbft/cometbft/proxy"
"github.com/cometbft/cometbft/rpc/client/local"
cmttypes "github.com/cometbft/cometbft/types"
cmttime "github.com/cometbft/cometbft/types/time"
"golang.org/x/sync/errgroup"
"cosmossdk.io/log"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/server/api"
servergrpc "github.com/cosmos/cosmos-sdk/server/grpc"
servercmtlog "github.com/cosmos/cosmos-sdk/server/log"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "cosmossdk.io/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/genutil"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
)
func startInProcess(cfg Config, val *Validator) error {
logger := val.Ctx.Logger
cmtCfg := val.Ctx.Config
cmtCfg.Instrumentation.Prometheus = false
if err := val.AppConfig.ValidateBasic(); err != nil {
return err
}
nodeKey, err := p2p.LoadOrGenNodeKey(cmtCfg.NodeKeyFile())
if err != nil {
return err
}
app := cfg.AppConstructor(*val)
val.app = app
appGenesisProvider := func() (*cmttypes.GenesisDoc, error) {
appGenesis, err := genutiltypes.AppGenesisFromFile(cmtCfg.GenesisFile())
if err != nil {
return nil, err
}
return appGenesis.ToGenesisDoc()
}
cmtApp := server.NewCometABCIWrapper(app)
tmNode, err := node.NewNode( //resleak:notresource
cmtCfg,
pvm.LoadOrGenFilePV(cmtCfg.PrivValidatorKeyFile(), cmtCfg.PrivValidatorStateFile()),
nodeKey,
proxy.NewLocalClientCreator(cmtApp),
appGenesisProvider,
cmtcfg.DefaultDBProvider,
node.DefaultMetricsProvider(cmtCfg.Instrumentation),
servercmtlog.CometLoggerWrapper{Logger: logger.With("module", val.Moniker)},
)
if err != nil {
return err
}
if err := tmNode.Start(); err != nil {
return err
}
val.tmNode = tmNode
if val.RPCAddress != "" {
val.RPCClient = local.New(tmNode)
}
// We'll need a RPC client if the validator exposes a gRPC or REST endpoint.
if val.APIAddress != "" || val.AppConfig.GRPC.Enable {
val.ClientCtx = val.ClientCtx.
WithClient(val.RPCClient)
app.RegisterTxService(val.ClientCtx)
app.RegisterTendermintService(val.ClientCtx)
app.RegisterNodeService(val.ClientCtx, *val.AppConfig)
}
ctx := context.Background()
ctx, val.cancelFn = context.WithCancel(ctx)
val.errGroup, ctx = errgroup.WithContext(ctx)
grpcCfg := val.AppConfig.GRPC
if grpcCfg.Enable {
grpcSrv, err := servergrpc.NewGRPCServer(val.ClientCtx, app, grpcCfg)
if err != nil {
return err
}
// Start the gRPC server in a goroutine. Note, the provided ctx will ensure
// that the server is gracefully shut down.
val.errGroup.Go(func() error {
return servergrpc.StartGRPCServer(ctx, logger.With(log.ModuleKey, "grpc-server"), grpcCfg, grpcSrv)
})
val.grpc = grpcSrv
}
if val.APIAddress != "" {
apiSrv := api.New(val.ClientCtx, logger.With(log.ModuleKey, "api-server"), val.grpc)
app.RegisterAPIRoutes(apiSrv, val.AppConfig.API)
val.errGroup.Go(func() error {
return apiSrv.Start(ctx, *val.AppConfig)
})
val.api = apiSrv
}
return nil
}
func collectGenFiles(cfg Config, vals []*Validator, outputDir string) error {
genTime := cmttime.Now()
for i := 0; i < cfg.NumValidators; i++ {
cmtCfg := vals[i].Ctx.Config
nodeDir := filepath.Join(outputDir, vals[i].Moniker, "simd")
gentxsDir := filepath.Join(outputDir, "gentxs")
cmtCfg.Moniker = vals[i].Moniker
cmtCfg.SetRoot(nodeDir)
initCfg := genutiltypes.NewInitConfig(cfg.ChainID, gentxsDir, vals[i].NodeID, vals[i].PubKey)
genFile := cmtCfg.GenesisFile()
appGenesis, err := genutiltypes.AppGenesisFromFile(genFile)
if err != nil {
return err
}
appState, err := genutil.GenAppStateFromConfig(cfg.Codec, cfg.TxConfig,
cmtCfg, initCfg, appGenesis,
banktypes.GenesisBalancesIterator{},
genutiltypes.DefaultMessageValidator,
cfg.TxConfig.SigningContext().ValidatorAddressCodec(),
)
if err != nil {
return err
}
// overwrite each validator's genesis file to have a canonical genesis time
if err := genutil.ExportGenesisFileWithTime(genFile, cfg.ChainID, nil, appState, genTime); err != nil {
return err
}
}
return nil
}
func initGenFiles(cfg Config, genAccounts []authtypes.GenesisAccount, genBalances []banktypes.Balance, genFiles []string) error {
// set the accounts in the genesis state
var authGenState authtypes.GenesisState
cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[authtypes.ModuleName], &authGenState)
accounts, err := authtypes.PackAccounts(genAccounts)
if err != nil {
return err
}
authGenState.Accounts = append(authGenState.Accounts, accounts...)
cfg.GenesisState[authtypes.ModuleName] = cfg.Codec.MustMarshalJSON(&authGenState)
// set the balances in the genesis state
var bankGenState banktypes.GenesisState
cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[banktypes.ModuleName], &bankGenState)
bankGenState.Balances = append(bankGenState.Balances, genBalances...)
cfg.GenesisState[banktypes.ModuleName] = cfg.Codec.MustMarshalJSON(&bankGenState)
appGenStateJSON, err := json.MarshalIndent(cfg.GenesisState, "", " ")
if err != nil {
return err
}
appGenesis := genutiltypes.AppGenesis{
ChainID: cfg.ChainID,
AppState: appGenStateJSON,
Consensus: &genutiltypes.ConsensusGenesis{
Validators: nil,
},
}
// generate empty genesis files for each validator and save
for i := 0; i < cfg.NumValidators; i++ {
if err := appGenesis.SaveAs(genFiles[i]); err != nil {
return err
}
}
return nil
}
func writeFile(name, dir string, contents []byte) error {
file := filepath.Join(dir, name)
if err := os.MkdirAll(dir, 0o755); err != nil {
return fmt.Errorf("could not create directory %q: %w", dir, err)
}
if err := os.WriteFile(file, contents, 0o600); err != nil {
return err
}
return nil
}
// Get a free address for a test CometBFT server
// protocol is either tcp, http, etc
func FreeTCPAddr() (addr, port string, closeFn func() error, err error) {
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
return "", "", nil, err
}
closeFn = func() error {
return l.Close()
}
portI := l.Addr().(*net.TCPAddr).Port
port = fmt.Sprintf("%d", portI)
addr = fmt.Sprintf("tcp://0.0.0.0:%s", port)
return
}