feat(ITS): [ENG-1627]: Moving ITS from release branch to main (#236)

Co-authored-by: Nikhil <nikhil@skip.money>
This commit is contained in:
David Terpay
2023-08-11 18:22:39 +00:00
committed by GitHub
co-authored by Nikhil
parent 14f83b5e25
commit 1ed1adc856
31 changed files with 3771 additions and 6086 deletions
+3 -43
View File
@@ -18,7 +18,6 @@ import (
feegrantkeeper "cosmossdk.io/x/feegrant/keeper"
feegrantmodule "cosmossdk.io/x/feegrant/module"
cometabci "github.com/cometbft/cometbft/abci/types"
tmtypes "github.com/cometbft/cometbft/proto/tendermint/types"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
@@ -62,7 +61,6 @@ import (
"github.com/cosmos/cosmos-sdk/x/staking"
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
veabci "github.com/skip-mev/pob/abci"
"github.com/skip-mev/pob/blockbuster"
"github.com/skip-mev/pob/blockbuster/abci"
"github.com/skip-mev/pob/blockbuster/lanes/auction"
@@ -340,27 +338,14 @@ func New(
app.App.SetAnteHandler(anteHandler)
// Set the proposal handlers on base app
proposalHandler := veabci.NewProposalHandler(
lanes,
tobLane,
proposalHandler := abci.NewProposalHandler(
app.Logger(),
app.txConfig.TxEncoder(),
app.txConfig.TxDecoder(),
veabci.NoOpValidateVoteExtensionsFn(),
app.TxConfig().TxDecoder(),
mempool,
)
app.App.SetPrepareProposal(proposalHandler.PrepareProposalHandler())
app.App.SetProcessProposal(proposalHandler.ProcessProposalHandler())
// Set the vote extension handler on the app.
voteExtensionHandler := veabci.NewVoteExtensionHandler(
app.Logger(),
tobLane,
app.txConfig.TxDecoder(),
app.txConfig.TxEncoder(),
)
app.App.SetExtendVoteHandler(voteExtensionHandler.ExtendVoteHandler())
app.App.SetVerifyVoteExtensionHandler(voteExtensionHandler.VerifyVoteExtensionHandler())
// Set the custom CheckTx handler on BaseApp.
checkTxHandler := abci.NewCheckTxHandler(
app.App,
@@ -415,31 +400,6 @@ func (app *TestApp) SetCheckTx(handler abci.CheckTx) {
app.checkTxHandler = handler
}
// TODO: remove this once we have a proper config file
func (app *TestApp) InitChain(req *cometabci.RequestInitChain) (*cometabci.ResponseInitChain, error) {
req.ConsensusParams.Abci.VoteExtensionsEnableHeight = 2
resp, err := app.App.InitChain(req)
if resp == nil {
resp = &cometabci.ResponseInitChain{}
}
resp.ConsensusParams = &tmtypes.ConsensusParams{
Abci: &tmtypes.ABCIParams{
VoteExtensionsEnableHeight: 2,
},
}
return resp, err
}
// TODO: remove this once we have a proper config file
func (app *TestApp) FinalizeBlock(req *cometabci.RequestFinalizeBlock) (*cometabci.ResponseFinalizeBlock, error) {
resp, err := app.App.FinalizeBlock(req)
if resp != nil {
resp.ConsensusParamUpdates = nil
}
return resp, err
}
// Name returns the name of the App
func (app *TestApp) Name() string { return app.BaseApp.Name() }
-94
View File
@@ -1,94 +0,0 @@
package e2e
import (
"fmt"
"os"
"cosmossdk.io/log"
dbm "github.com/cosmos/cosmos-db"
"github.com/cosmos/cosmos-sdk/codec"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
"github.com/skip-mev/pob/tests/app"
"github.com/skip-mev/pob/tests/app/params"
)
const (
keyringPassphrase = "testpassphrase"
keyringAppName = "testnet"
)
var (
encodingConfig params.EncodingConfig
cdc codec.Codec
)
func init() {
testApp := app.New(log.NewNopLogger(), dbm.NewMemDB(), nil, true, simtestutil.NewAppOptionsWithFlagHome(app.DefaultNodeHome))
encodingConfig = params.EncodingConfig{
InterfaceRegistry: testApp.InterfaceRegistry(),
Codec: testApp.AppCodec(),
TxConfig: testApp.TxConfig(),
Amino: testApp.LegacyAmino(),
}
cdc = encodingConfig.Codec
}
type chain struct {
dataDir string
id string
validators []*validator
}
func newChain() (*chain, error) {
pwd, err := os.Getwd()
if err != nil {
return nil, err
}
tmpDir, err := os.MkdirTemp(pwd, ".pob-e2e-testnet-")
if err != nil {
return nil, err
}
return &chain{
id: app.ChainID,
dataDir: tmpDir,
}, nil
}
func (c *chain) configDir() string {
return fmt.Sprintf("%s/%s", c.dataDir, c.id)
}
func (c *chain) createAndInitValidators(count int) error {
for i := 0; i < count; i++ {
node := c.createValidator(i)
// generate genesis files
if err := node.init(); err != nil {
return err
}
c.validators = append(c.validators, node)
// create keys
if err := node.createKey("val"); err != nil {
return err
}
if err := node.createNodeKey(); err != nil {
return err
}
if err := node.createConsensusKey(); err != nil {
return err
}
}
return nil
}
func (c *chain) createValidator(index int) *validator {
return &validator{
chain: c,
index: index,
moniker: "testapp",
}
}
-323
View File
@@ -1,323 +0,0 @@
package e2e
import (
"context"
"encoding/json"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"testing"
"time"
"cosmossdk.io/math"
cometcfg "github.com/cometbft/cometbft/config"
cometjson "github.com/cometbft/cometbft/libs/json"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
"github.com/cosmos/cosmos-sdk/server"
srvconfig "github.com/cosmos/cosmos-sdk/server/config"
sdk "github.com/cosmos/cosmos-sdk/types"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
"github.com/ory/dockertest/v3"
"github.com/ory/dockertest/v3/docker"
"github.com/skip-mev/pob/tests/app"
"github.com/skip-mev/pob/x/builder/types"
"github.com/spf13/viper"
"github.com/stretchr/testify/suite"
)
var (
numValidators = 4
minGasPrice = sdk.NewDecCoinFromDec(app.BondDenom, math.LegacyMustNewDecFromStr("0.02")).String()
initBalanceStr = sdk.NewInt64Coin(app.BondDenom, 1000000000000000000).String()
stakeAmount = math.NewInt(100000000000)
stakeAmountCoin = sdk.NewCoin(app.BondDenom, stakeAmount)
)
type (
TestAccount struct {
PrivateKey *secp256k1.PrivKey
Address sdk.AccAddress
}
IntegrationTestSuite struct {
suite.Suite
tmpDirs []string
chain *chain
dkrPool *dockertest.Pool
dkrNet *dockertest.Network
valResources []*dockertest.Resource
}
)
func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
}
func (s *IntegrationTestSuite) SetupSuite() {
s.T().Log("setting up e2e integration test suite...")
var err error
s.chain, err = newChain()
s.Require().NoError(err)
s.T().Logf("starting e2e infrastructure; chain-id: %s; datadir: %s", s.chain.id, s.chain.dataDir)
s.dkrPool, err = dockertest.NewPool("")
s.Require().NoError(err)
s.dkrNet, err = s.dkrPool.CreateNetwork(fmt.Sprintf("%s-testnet", s.chain.id))
s.Require().NoError(err)
// The bootstrapping phase is as follows:
//
// 1. Initialize TestApp validator nodes.
// 2. Create and initialize TestApp validator genesis files, i.e. setting
// delegate keys for validators.
// 3. Start TestApp network.
s.initNodes()
s.initGenesis()
s.initValidatorConfigs()
s.runValidators()
}
func (s *IntegrationTestSuite) TearDownSuite() {
if str := os.Getenv("POB_E2E_SKIP_CLEANUP"); len(str) > 0 {
skipCleanup, err := strconv.ParseBool(str)
s.Require().NoError(err)
if skipCleanup {
return
}
}
s.T().Log("tearing down e2e integration test suite...")
for _, vc := range s.valResources {
s.Require().NoError(s.dkrPool.Purge(vc))
}
s.Require().NoError(s.dkrPool.RemoveNetwork(s.dkrNet))
os.RemoveAll(s.chain.dataDir)
for _, td := range s.tmpDirs {
os.RemoveAll(td)
}
}
func (s *IntegrationTestSuite) initNodes() {
s.Require().NoError(s.chain.createAndInitValidators(numValidators))
// initialize a genesis file for the first validator
val0ConfigDir := s.chain.validators[0].configDir()
// Define the builder module parameters
params := types.Params{
MaxBundleSize: 5,
EscrowAccountAddress: sdk.MustAccAddressFromBech32("cosmos14j5j2lsx7629590jvpk3vj0xe9w8203jf4yknk").Bytes(),
ReserveFee: sdk.NewCoin(app.BondDenom, math.NewInt(1000000)),
MinBidIncrement: sdk.NewCoin(app.BondDenom, math.NewInt(1000000)),
ProposerFee: math.LegacyMustNewDecFromStr("0.1"),
FrontRunningProtection: true,
}
for _, val := range s.chain.validators {
valAddr, err := val.keyInfo.GetAddress()
s.Require().NoError(err)
s.Require().NoError(initGenesisFile(val0ConfigDir, "", initBalanceStr, valAddr, params))
}
// copy the genesis file to the remaining validators
for _, val := range s.chain.validators[1:] {
_, err := copyFile(
filepath.Join(val0ConfigDir, "config", "genesis.json"),
filepath.Join(val.configDir(), "config", "genesis.json"),
)
s.Require().NoError(err)
}
}
func (s *IntegrationTestSuite) initGenesis() {
serverCtx := server.NewDefaultContext()
config := serverCtx.Config
config.SetRoot(s.chain.validators[0].configDir())
config.Moniker = s.chain.validators[0].moniker
genFilePath := config.GenesisFile()
appGenState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFilePath)
s.T().Log("starting e2e infrastructure; validator_0 config:", genFilePath)
s.Require().NoError(err)
// x/gov
var govGenState govtypesv1.GenesisState
s.Require().NoError(cdc.UnmarshalJSON(appGenState[govtypes.ModuleName], &govGenState))
votingPeriod := 5 * time.Second
govGenState.Params.VotingPeriod = &votingPeriod
govGenState.Params.MinDeposit = sdk.NewCoins(sdk.NewCoin(app.BondDenom, math.NewInt(100)))
bz, err := cdc.MarshalJSON(&govGenState)
s.Require().NoError(err)
appGenState[govtypes.ModuleName] = bz
var genUtilGenState genutiltypes.GenesisState
s.Require().NoError(cdc.UnmarshalJSON(appGenState[genutiltypes.ModuleName], &genUtilGenState))
// x/genutil genesis txs
genTxs := make([]json.RawMessage, len(s.chain.validators))
for i, val := range s.chain.validators {
createValMsg, err := val.buildCreateValidatorMsg(stakeAmountCoin)
s.Require().NoError(err)
signedTx, err := val.signMsg(createValMsg)
s.Require().NoError(err)
txRaw, err := cdc.MarshalJSON(signedTx)
s.Require().NoError(err)
genTxs[i] = txRaw
}
genUtilGenState.GenTxs = genTxs
bz, err = cdc.MarshalJSON(&genUtilGenState)
s.Require().NoError(err)
appGenState[genutiltypes.ModuleName] = bz
bz, err = json.MarshalIndent(appGenState, "", " ")
s.Require().NoError(err)
genDoc.AppState = bz
bz, err = cometjson.MarshalIndent(genDoc, "", " ")
s.Require().NoError(err)
// write the updated genesis file to each validator
for _, val := range s.chain.validators {
writeFile(filepath.Join(val.configDir(), "config", "genesis.json"), bz)
}
}
func (s *IntegrationTestSuite) initValidatorConfigs() {
for i, val := range s.chain.validators {
tmCfgPath := filepath.Join(val.configDir(), "config", "config.toml")
vpr := viper.New()
vpr.SetConfigFile(tmCfgPath)
s.Require().NoError(vpr.ReadInConfig())
valConfig := cometcfg.DefaultConfig()
s.Require().NoError(vpr.Unmarshal(valConfig))
valConfig.P2P.ListenAddress = "tcp://0.0.0.0:26656"
valConfig.P2P.AddrBookStrict = false
valConfig.P2P.ExternalAddress = fmt.Sprintf("%s:%d", val.instanceName(), 26656)
valConfig.RPC.ListenAddress = "tcp://0.0.0.0:26657"
valConfig.StateSync.Enable = false
valConfig.LogLevel = "info"
valConfig.BaseConfig.Genesis = filepath.Join("config", "genesis.json")
valConfig.RootDir = filepath.Join("root", ".simapp")
valConfig.Consensus.TimeoutCommit = 2 * time.Second
var peers []string
for j := 0; j < len(s.chain.validators); j++ {
if i == j {
continue
}
peer := s.chain.validators[j]
peerID := fmt.Sprintf("%s@%s%d:26656", peer.nodeKey.ID(), peer.moniker, j)
peers = append(peers, peerID)
}
valConfig.P2P.PersistentPeers = strings.Join(peers, ",")
cometcfg.WriteConfigFile(tmCfgPath, valConfig)
// set application configuration
appCfgPath := filepath.Join(val.configDir(), "config", "app.toml")
appConfig := srvconfig.DefaultConfig()
appConfig.API.Enable = true
appConfig.MinGasPrices = minGasPrice
appConfig.API.Address = "tcp://0.0.0.0:1317"
appConfig.GRPC.Address = "0.0.0.0:9090"
srvconfig.WriteConfigFile(appCfgPath, appConfig)
}
}
func (s *IntegrationTestSuite) runValidators() {
s.T().Log("starting POB TestApp validator containers...")
s.valResources = make([]*dockertest.Resource, len(s.chain.validators))
for i, val := range s.chain.validators {
runOpts := &dockertest.RunOptions{
Name: val.instanceName(),
NetworkID: s.dkrNet.Network.ID,
Mounts: []string{
fmt.Sprintf("%s/:/root/.testapp", val.configDir()),
},
Repository: "docker.io/skip-mev/pob-e2e",
}
// expose the first validator for debugging and communication
if val.index == 0 {
runOpts.PortBindings = map[docker.Port][]docker.PortBinding{
"1317/tcp": {{HostIP: "", HostPort: "1317"}},
"6060/tcp": {{HostIP: "", HostPort: "6060"}},
"6061/tcp": {{HostIP: "", HostPort: "6061"}},
"6062/tcp": {{HostIP: "", HostPort: "6062"}},
"6063/tcp": {{HostIP: "", HostPort: "6063"}},
"6064/tcp": {{HostIP: "", HostPort: "6064"}},
"6065/tcp": {{HostIP: "", HostPort: "6065"}},
"9090/tcp": {{HostIP: "", HostPort: "9090"}},
"26656/tcp": {{HostIP: "", HostPort: "26656"}},
"26657/tcp": {{HostIP: "", HostPort: "26657"}},
}
}
resource, err := s.dkrPool.RunWithOptions(runOpts, noRestart)
s.Require().NoError(err)
s.valResources[i] = resource
s.T().Logf("started POB TestApp validator container: %s", resource.Container.ID)
}
rpcClient, err := rpchttp.New("tcp://localhost:26657", "/websocket")
s.Require().NoError(err)
s.Require().Eventually(
func() bool {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
status, err := rpcClient.Status(ctx)
if err != nil {
return false
}
// let the node produce a few blocks
if status.SyncInfo.CatchingUp || status.SyncInfo.LatestBlockHeight < 3 {
return false
}
return true
},
2*time.Minute,
time.Second,
"POB TestApp node failed to produce blocks",
)
}
func noRestart(config *docker.HostConfig) {
// in this case we don't want the nodes to restart on failure
config.RestartPolicy = docker.RestartPolicy{
Name: "no",
}
}
File diff suppressed because it is too large Load Diff
-180
View File
@@ -1,180 +0,0 @@
package e2e
import (
"bytes"
"context"
"fmt"
"strings"
"time"
"cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/client/flags"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/ory/dockertest/v3/docker"
"github.com/skip-mev/pob/tests/app"
buildertypes "github.com/skip-mev/pob/x/builder/types"
)
// execMsgSendTx executes a send transaction on the given validator given the provided
// recipient and amount. This function returns the transaction hash. It does not wait for the
// transaction to be committed.
func (s *IntegrationTestSuite) execMsgSendTx(valIdx int, to sdk.AccAddress, amount sdk.Coin) string {
address, err := s.chain.validators[valIdx].keyInfo.GetAddress()
s.Require().NoError(err)
s.T().Logf(
"sending %s from %s to %s",
amount, address, to,
)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
exec, err := s.dkrPool.Client.CreateExec(docker.CreateExecOptions{
Context: ctx,
AttachStdout: true,
AttachStderr: true,
Container: s.valResources[valIdx].Container.ID,
User: "root",
Cmd: []string{
"testappd",
"tx",
"bank",
"send",
address.String(), // sender
to.String(), // receiver
amount.String(), // amount
fmt.Sprintf("--%s=%s", flags.FlagFrom, s.chain.validators[valIdx].keyInfo.Name),
fmt.Sprintf("--%s=%s", flags.FlagChainID, s.chain.id),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoin(app.BondDenom, math.NewInt(1000000000)).String()),
"--keyring-backend=test",
"--broadcast-mode=sync",
"-y",
},
})
s.Require().NoError(err)
var (
outBuf bytes.Buffer
errBuf bytes.Buffer
)
err = s.dkrPool.Client.StartExec(exec.ID, docker.StartExecOptions{
Context: ctx,
Detach: false,
OutputStream: &outBuf,
ErrorStream: &errBuf,
})
s.Require().NoErrorf(err, "stdout: %s, stderr: %s", outBuf.String(), errBuf.String())
output := outBuf.String()
resp := strings.Split(output, ":")
txHash := strings.TrimSpace(resp[len(resp)-1])
return txHash
}
// createAuctionBidTx creates a transaction that bids on an auction given the provided bidder, bid, and transactions.
func (s *IntegrationTestSuite) createAuctionBidTx(account TestAccount, bid sdk.Coin, transactions [][]byte, sequenceOffset, height, gasLimit uint64, fees sdk.Coins) []byte {
msgs := []sdk.Msg{
&buildertypes.MsgAuctionBid{
Bidder: account.Address.String(),
Bid: bid,
Transactions: transactions,
},
}
return s.createTx(account, msgs, sequenceOffset, height, gasLimit, fees)
}
// createMsgSendTx creates a send transaction given the provided signer, recipient, amount, sequence number offset, and block height timeout.
// This function is primarily used to create bundles of transactions.
func (s *IntegrationTestSuite) createMsgSendTx(account TestAccount, toAddress string, amount sdk.Coins, sequenceOffset, height, gasLimit uint64, fees sdk.Coins) []byte {
msgs := []sdk.Msg{
&banktypes.MsgSend{
FromAddress: account.Address.String(),
ToAddress: toAddress,
Amount: amount,
},
}
return s.createTx(account, msgs, sequenceOffset, height, gasLimit, fees)
}
// createMsgDelegateTx creates a delegate transaction given the provided signer, validator, amount, sequence number offset
// and block height timeout.
func (s *IntegrationTestSuite) createMsgDelegateTx(account TestAccount, validator string, amount sdk.Coin, sequenceOffset, height, gasLimit uint64, fees sdk.Coins) []byte {
msgs := []sdk.Msg{
&stakingtypes.MsgDelegate{
DelegatorAddress: account.Address.String(),
ValidatorAddress: validator,
Amount: amount,
},
}
return s.createTx(account, msgs, sequenceOffset, height, gasLimit, fees)
}
// createTx creates a transaction given the provided messages, sequence number offset, and block height timeout.
func (s *IntegrationTestSuite) createTx(account TestAccount, msgs []sdk.Msg, sequenceOffset, height, gasLimit uint64, fees sdk.Coins) []byte {
txConfig := encodingConfig.TxConfig
txBuilder := txConfig.NewTxBuilder()
// Get account info of the sender to set the account number and sequence number
baseAccount := s.queryAccount(account.Address)
sequenceNumber := baseAccount.Sequence + sequenceOffset
s.Require().NoError(txBuilder.SetMsgs(msgs...))
txBuilder.SetFeeAmount(fees)
txBuilder.SetGasLimit(gasLimit)
txBuilder.SetTimeoutHeight(height)
signerData := authsigning.SignerData{
ChainID: app.ChainID,
AccountNumber: baseAccount.AccountNumber,
Sequence: sequenceNumber,
PubKey: account.PrivateKey.PubKey(),
}
sig := signing.SignatureV2{
PubKey: account.PrivateKey.PubKey(),
Data: &signing.SingleSignatureData{
SignMode: signing.SignMode_SIGN_MODE_DIRECT,
Signature: nil,
},
Sequence: sequenceNumber,
}
s.Require().NoError(txBuilder.SetSignatures(sig))
bytesToSign, err := authsigning.GetSignBytesAdapter(
context.Background(),
encodingConfig.TxConfig.SignModeHandler(),
signing.SignMode_SIGN_MODE_DIRECT,
signerData,
txBuilder.GetTx(),
)
s.Require().NoError(err)
sigBytes, err := account.PrivateKey.Sign(bytesToSign)
s.Require().NoError(err)
sig = signing.SignatureV2{
PubKey: account.PrivateKey.PubKey(),
Data: &signing.SingleSignatureData{
SignMode: signing.SignMode_SIGN_MODE_DIRECT,
Signature: sigBytes,
},
Sequence: sequenceNumber,
}
s.Require().NoError(txBuilder.SetSignatures(sig))
signedTx := txBuilder.GetTx()
bz, err := encodingConfig.TxConfig.TxEncoder()(signedTx)
s.Require().NoError(err)
return bz
}
-401
View File
@@ -1,401 +0,0 @@
package e2e
import (
"context"
"crypto/sha256"
"encoding/hex"
"fmt"
"strings"
"time"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
cmtclient "github.com/cosmos/cosmos-sdk/client/grpc/cmtservice"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
sdk "github.com/cosmos/cosmos-sdk/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
buildertypes "github.com/skip-mev/pob/x/builder/types"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
// createClientContext creates a client.Context for use in integration tests.
// Note, it assumes all queries and broadcasts go to the first node.
func (s *IntegrationTestSuite) createClientContext() client.Context {
node := s.valResources[0]
rpcURI := node.GetHostPort("26657/tcp")
gRPCURI := node.GetHostPort("9090/tcp")
rpcClient, err := client.NewClientFromNode(rpcURI)
s.Require().NoError(err)
grpcClient, err := grpc.Dial(gRPCURI, []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}...)
s.Require().NoError(err)
return client.Context{}.
WithNodeURI(rpcURI).
WithClient(rpcClient).
WithGRPCClient(grpcClient).
WithInterfaceRegistry(encodingConfig.InterfaceRegistry).
WithCodec(encodingConfig.Codec).
WithChainID(s.chain.id).
WithBroadcastMode(flags.BroadcastSync)
}
// createTestAccounts creates and funds test accounts with a balance.
func (s *IntegrationTestSuite) createTestAccounts(numAccounts int, balance sdk.Coin) []TestAccount {
accounts := make([]TestAccount, numAccounts)
for i := 0; i < numAccounts; i++ {
// Generate a new account with private key that will be used to sign transactions.
privKey := secp256k1.GenPrivKey()
pubKey := privKey.PubKey()
addr := sdk.AccAddress(pubKey.Address())
account := TestAccount{
PrivateKey: privKey,
Address: addr,
}
// Fund the account.
s.execMsgSendTx(0, account.Address, balance)
// Wait for the balance to be updated.
s.Require().Eventually(func() bool {
return !s.queryBalancesOf(addr.String()).IsZero()
},
10*time.Second,
1*time.Second,
)
accounts[i] = account
}
return accounts
}
// calculateProposerEscrowSplit calculates the amount of a bid that should go to the escrow account
// and the amount that should go to the proposer. The simulation e2e environment does not support
// checking the proposer's balance, it only validates that the escrow address has the correct balance.
func (s *IntegrationTestSuite) calculateProposerEscrowSplit(bid sdk.Coin) sdk.Coin {
// Get the params to determine the proposer fee.
params := s.queryBuilderParams()
proposerFee := params.ProposerFee
var proposerReward sdk.Coins
if proposerFee.IsZero() {
// send the entire bid to the escrow account when no proposer fee is set
return bid
}
// determine the amount of the bid that goes to the (previous) proposer
bidDec := sdk.NewDecCoinsFromCoins(bid)
proposerReward, _ = bidDec.MulDecTruncate(proposerFee).TruncateDecimal()
// Determine the amount of the remaining bid that goes to the escrow account.
// If a decimal remainder exists, it'll stay with the bidding account.
escrowTotal := bidDec.Sub(sdk.NewDecCoinsFromCoins(proposerReward...))
escrowReward, _ := escrowTotal.TruncateDecimal()
return sdk.NewCoin(bid.Denom, escrowReward.AmountOf(bid.Denom))
}
// waitForABlock will wait until the current block height has increased by a single block.
func (s *IntegrationTestSuite) waitForABlock() {
height := s.queryCurrentHeight()
s.Require().Eventually(
func() bool {
return s.queryCurrentHeight() >= height+1
},
10*time.Second,
50*time.Millisecond,
)
}
// waitForNBlocks will wait until the current block height has increased by n blocks.
func (s *IntegrationTestSuite) waitForNBlocks(n int) {
height := s.queryCurrentHeight()
s.Require().Eventually(
func() bool {
return s.queryCurrentHeight() >= height+uint64(n)
},
10*time.Second,
50*time.Millisecond,
)
}
// bundleToTxHashes converts a bundle to a slice of transaction hashes.
func (s *IntegrationTestSuite) bundleToTxHashes(bidTx []byte, bundle [][]byte) []string {
hashes := make([]string, len(bundle)+1)
// encode the bid transaction into a hash
hashBz := sha256.Sum256(bidTx)
hash := hex.EncodeToString(hashBz[:])
hashes[0] = hash
for i, hash := range s.normalTxsToTxHashes(bundle) {
hashes[i+1] = hash
}
return hashes
}
// normalTxsToTxHashes converts a slice of normal transactions to a slice of transaction hashes.
func (s *IntegrationTestSuite) normalTxsToTxHashes(txs [][]byte) []string {
hashes := make([]string, len(txs))
for i, tx := range txs {
hashBz := sha256.Sum256(tx)
hash := hex.EncodeToString(hashBz[:])
hashes[i] = hash
}
return hashes
}
// verifyTopOfBlockAuction verifies that blocks that include a bid transaction execute as expected.
func (s *IntegrationTestSuite) verifyTopOfBlockAuction(height uint64, bundle []string, expectedExecution map[string]bool) {
s.waitForABlock()
s.T().Logf("Verifying block %d", height)
// Get the block's transactions and display the expected and actual block for debugging.
txs := s.queryBlockTxs(height)
s.displayBlock(txs, bundle)
// Ensure that all transactions executed as expected (i.e. landed or failed to land).
for tx, landed := range expectedExecution {
s.T().Logf("Verifying tx %s executed as %t", tx, landed)
s.Require().Equal(landed, s.queryTxPassed(tx) == nil)
}
s.T().Logf("All txs executed as expected")
// Check that the block contains the expected transactions in the expected order
// iff the bid transaction was expected to execute.
if len(bundle) > 0 && len(expectedExecution) > 0 && expectedExecution[bundle[0]] && len(txs) > 0 {
if expectedExecution[bundle[0]] {
hashBz := sha256.Sum256(txs[0])
hash := hex.EncodeToString(hashBz[:])
s.Require().Equal(strings.ToUpper(bundle[0]), strings.ToUpper(hash))
for index, bundleTx := range bundle[1:] {
hashBz := sha256.Sum256(txs[index+1])
txHash := hex.EncodeToString(hashBz[:])
s.Require().Equal(strings.ToUpper(bundleTx), strings.ToUpper(txHash))
}
}
}
}
// verifyBlock verifies that the transactions in the block at the given height were seen
// and executed in the order they were submitted.
func (s *IntegrationTestSuite) verifyBlock(height uint64, txs []string, expectedExecution map[string]bool) {
s.waitForABlock()
s.T().Logf("Verifying block %d", height)
// Get the block's transactions and display the expected and actual block for debugging.
blockTxs := s.queryBlockTxs(height)
s.displayBlock(blockTxs, txs)
// Ensure that all transactions executed as expected (i.e. landed or failed to land).
for tx, landed := range expectedExecution {
s.T().Logf("Verifying tx %s executed as %t", tx, landed)
s.Require().Equal(landed, s.queryTxPassed(tx) == nil)
}
s.T().Logf("All txs executed as expected")
// Check that the block contains the expected transactions in the expected order.
s.Require().Equal(len(txs), len(blockTxs))
hashBlockTxs := s.normalTxsToTxHashes(blockTxs)
for index, tx := range txs {
s.Require().Equal(strings.ToUpper(tx), strings.ToUpper(hashBlockTxs[index]))
}
s.T().Logf("Block %d contains the expected transactions in the expected order", height)
}
// displayExpectedBlock displays the expected and actual blocks.
func (s *IntegrationTestSuite) displayBlock(txs [][]byte, expectedTxs []string) {
if len(expectedTxs) != 0 {
expectedBlock := fmt.Sprintf("Expected block:\n\t(%d, %s)\n", 0, expectedTxs[0])
for index, expectedTx := range expectedTxs[1:] {
expectedBlock += fmt.Sprintf("\t(%d, %s)\n", index+1, expectedTx)
}
s.T().Logf(expectedBlock)
}
// Display the actual block.
if len(txs) == 0 {
s.T().Logf("Actual block is empty")
return
}
hashBz := sha256.Sum256(txs[0])
hash := hex.EncodeToString(hashBz[:])
actualBlock := fmt.Sprintf("Actual block:\n\t(%d, %s)\n", 0, hash)
for index, tx := range txs[1:] {
hashBz := sha256.Sum256(tx)
txHash := hex.EncodeToString(hashBz[:])
actualBlock += fmt.Sprintf("\t(%d, %s)\n", index+1, txHash)
}
s.T().Logf(actualBlock)
}
// displayExpectedBundle displays the expected order of the bid and bundled transactions.
func (s *IntegrationTestSuite) displayExpectedBundle(prefix string, bidTx []byte, bundle [][]byte) {
// encode the bid transaction into a hash
hashes := s.bundleToTxHashes(bidTx, bundle)
expectedBundle := fmt.Sprintf("%s expected bundle:\n\t(%d, %s)\n", prefix, 0, hashes[0])
for index, bundleTx := range hashes[1:] {
expectedBundle += fmt.Sprintf("\t(%d, %s)\n", index+1, bundleTx)
}
s.T().Logf(expectedBundle)
}
// broadcastTx broadcasts a transaction to the network using the given validator.
func (s *IntegrationTestSuite) broadcastTx(tx []byte, valIdx int) {
node := s.valResources[valIdx]
gRPCURI := node.GetHostPort("9090/tcp")
grpcConn, err := grpc.Dial(
gRPCURI,
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
s.Require().NoError(err)
client := txtypes.NewServiceClient(grpcConn)
req := &txtypes.BroadcastTxRequest{TxBytes: tx, Mode: txtypes.BroadcastMode_BROADCAST_MODE_SYNC}
client.BroadcastTx(context.Background(), req)
}
// queryTx queries a transaction by its hash and returns whether there was an
// error in including the transaction in a block.
func (s *IntegrationTestSuite) queryTxPassed(txHash string) error {
queryClient := txtypes.NewServiceClient(s.createClientContext())
req := &txtypes.GetTxRequest{Hash: txHash}
resp, err := queryClient.GetTx(context.Background(), req)
if err != nil {
return err
}
if resp.TxResponse.Code != 0 {
return fmt.Errorf("tx failed: %s", resp.TxResponse.RawLog)
}
return nil
}
// queryBuilderParams returns the params of the builder module.
func (s *IntegrationTestSuite) queryBuilderParams() buildertypes.Params {
queryClient := buildertypes.NewQueryClient(s.createClientContext())
req := &buildertypes.QueryParamsRequest{}
resp, err := queryClient.Params(context.Background(), req)
s.Require().NoError(err)
return resp.Params
}
// queryBalancesOf returns the balances of an account.
func (s *IntegrationTestSuite) queryBalancesOf(address string) sdk.Coins {
queryClient := banktypes.NewQueryClient(s.createClientContext())
req := &banktypes.QueryAllBalancesRequest{Address: address}
resp, err := queryClient.AllBalances(context.Background(), req)
s.Require().NoError(err)
return resp.Balances
}
// queryBalanceOf returns the balance of an account for a specific denom.
func (s *IntegrationTestSuite) queryBalanceOf(address string, denom string) sdk.Coin {
queryClient := banktypes.NewQueryClient(s.createClientContext())
req := &banktypes.QueryBalanceRequest{Address: address, Denom: denom}
resp, err := queryClient.Balance(context.Background(), req)
s.Require().NoError(err)
return *resp.Balance
}
// queryAccount returns the account of an address.
func (s *IntegrationTestSuite) queryAccount(address sdk.AccAddress) *authtypes.BaseAccount {
queryClient := authtypes.NewQueryClient(s.createClientContext())
req := &authtypes.QueryAccountRequest{Address: address.String()}
resp, err := queryClient.Account(context.Background(), req)
s.Require().NoError(err)
account := &authtypes.BaseAccount{}
err = account.Unmarshal(resp.Account.Value)
s.Require().NoError(err)
return account
}
// queryCurrentHeight returns the current block height.
func (s *IntegrationTestSuite) queryCurrentHeight() uint64 {
queryClient := cmtclient.NewServiceClient(s.createClientContext())
req := &cmtclient.GetLatestBlockRequest{}
resp, err := queryClient.GetLatestBlock(context.Background(), req)
s.Require().NoError(err)
return uint64(resp.SdkBlock.Header.Height)
}
// queryBlockTxs returns the txs of the block at the given height.
func (s *IntegrationTestSuite) queryBlockTxs(height uint64) [][]byte {
queryClient := cmtclient.NewServiceClient(s.createClientContext())
req := &cmtclient.GetBlockByHeightRequest{Height: int64(height)}
resp, err := queryClient.GetBlockByHeight(context.Background(), req)
s.Require().NoError(err)
txs := resp.GetSdkBlock().Data.Txs
// The first transaction is the vote extension.
s.Require().Greater(len(txs), 0)
return txs[1:]
}
// queryTx returns information about a transaction.
func (s *IntegrationTestSuite) queryTx(txHash string) *txtypes.GetTxResponse {
queryClient := txtypes.NewServiceClient(s.createClientContext())
req := &txtypes.GetTxRequest{Hash: txHash}
resp, err := queryClient.GetTx(context.Background(), req)
s.Require().NoError(err)
return resp
}
// queryTxExecutionHeight returns the block height at which a transaction was executed.
func (s *IntegrationTestSuite) queryTxExecutionHeight(txHash string) uint64 {
txResp := s.queryTx(txHash)
return uint64(txResp.TxResponse.Height)
}
// queryValidators returns the validators of the network.
func (s *IntegrationTestSuite) queryValidators() []stakingtypes.Validator {
queryClient := stakingtypes.NewQueryClient(s.createClientContext())
req := &stakingtypes.QueryValidatorsRequest{}
resp, err := queryClient.Validators(context.Background(), req)
s.Require().NoError(err)
return resp.Validators
}
-121
View File
@@ -1,121 +0,0 @@
package e2e
import (
"encoding/json"
"fmt"
"os"
comettypes "github.com/cometbft/cometbft/types"
"github.com/cosmos/cosmos-sdk/server"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/genutil"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
"github.com/skip-mev/pob/x/builder/types"
)
func getGenDoc(path string) (*comettypes.GenesisDoc, error) {
serverCtx := server.NewDefaultContext()
config := serverCtx.Config
config.SetRoot(path)
genFile := config.GenesisFile()
doc := &comettypes.GenesisDoc{}
if _, err := os.Stat(genFile); err != nil {
if !os.IsNotExist(err) {
return nil, err
}
} else {
var err error
doc, err = comettypes.GenesisDocFromFile(genFile)
if err != nil {
return nil, fmt.Errorf("failed to read genesis doc from file: %w", err)
}
}
return doc, nil
}
func initGenesisFile(path, moniker, amountStr string, accAddr sdk.AccAddress, params types.Params) error {
serverCtx := server.NewDefaultContext()
config := serverCtx.Config
config.SetRoot(path)
config.Moniker = moniker
coins, err := sdk.ParseCoinsNormalized(amountStr)
if err != nil {
return fmt.Errorf("failed to parse coins: %w", err)
}
balances := banktypes.Balance{Address: accAddr.String(), Coins: coins.Sort()}
genAccount := authtypes.NewBaseAccount(accAddr, nil, 0, 0)
genFile := config.GenesisFile()
appState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFile)
if err != nil {
return fmt.Errorf("failed to unmarshal genesis state: %w", err)
}
authGenState := authtypes.GetGenesisStateFromAppState(cdc, appState)
accs, err := authtypes.UnpackAccounts(authGenState.Accounts)
if err != nil {
return fmt.Errorf("failed to get accounts from any: %w", err)
}
if accs.Contains(accAddr) {
return fmt.Errorf("failed to add account to genesis state; account already exists: %s", accAddr)
}
// Add the new account to the set of genesis accounts and sanitize the
// accounts afterwards.
accs = append(accs, genAccount)
accs = authtypes.SanitizeGenesisAccounts(accs)
genAccs, err := authtypes.PackAccounts(accs)
if err != nil {
return fmt.Errorf("failed to convert accounts into any's: %w", err)
}
authGenState.Accounts = genAccs
authGenStateBz, err := cdc.MarshalJSON(&authGenState)
if err != nil {
return fmt.Errorf("failed to marshal auth genesis state: %w", err)
}
appState[authtypes.ModuleName] = authGenStateBz
bankGenState := banktypes.GetGenesisStateFromAppState(cdc, appState)
bankGenState.Balances = append(bankGenState.Balances, balances)
bankGenState.Balances = banktypes.SanitizeGenesisBalances(bankGenState.Balances)
bankGenStateBz, err := cdc.MarshalJSON(bankGenState)
if err != nil {
return fmt.Errorf("failed to marshal bank genesis state: %w", err)
}
appState[banktypes.ModuleName] = bankGenStateBz
builderGenState := types.GetGenesisStateFromAppState(cdc, appState)
builderGenState.Params = params
builderGenStateBz, err := cdc.MarshalJSON(&builderGenState)
if err != nil {
return fmt.Errorf("failed to marshal builder genesis state: %w", err)
}
appState[types.ModuleName] = builderGenStateBz
appStateJSON, err := json.Marshal(appState)
if err != nil {
return fmt.Errorf("failed to marshal application genesis state: %w", err)
}
genDoc.AppState = appStateJSON
return genutil.ExportGenesisFile(genDoc, genFile)
}
-42
View File
@@ -1,42 +0,0 @@
package e2e
import (
"fmt"
"io"
"os"
)
func copyFile(src, dst string) (int64, error) {
sourceFileStat, err := os.Stat(src)
if err != nil {
return 0, err
}
if !sourceFileStat.Mode().IsRegular() {
return 0, fmt.Errorf("%s is not a regular file", src)
}
source, err := os.Open(src)
if err != nil {
return 0, err
}
defer source.Close()
destination, err := os.Create(dst)
if err != nil {
return 0, err
}
defer destination.Close()
nBytes, err := io.Copy(destination, source)
return nBytes, err
}
func writeFile(path string, body []byte) error {
_, err := os.Create(path)
if err != nil {
return err
}
return os.WriteFile(path, body, 0o600)
}
-19
View File
@@ -1,19 +0,0 @@
package e2e
import (
"github.com/cosmos/go-bip39"
)
func createMnemonic() (string, error) {
entropySeed, err := bip39.NewEntropy(256)
if err != nil {
return "", err
}
mnemonic, err := bip39.NewMnemonic(entropySeed)
if err != nil {
return "", err
}
return mnemonic, nil
}
-45
View File
@@ -1,45 +0,0 @@
package e2e
import (
"fmt"
"github.com/cosmos/cosmos-sdk/codec/unknownproto"
sdktx "github.com/cosmos/cosmos-sdk/types/tx"
)
func decodeTx(txBytes []byte) (*sdktx.Tx, error) {
var raw sdktx.TxRaw
// reject all unknown proto fields in the root TxRaw
err := unknownproto.RejectUnknownFieldsStrict(txBytes, &raw, encodingConfig.InterfaceRegistry)
if err != nil {
return nil, fmt.Errorf("failed to reject unknown fields: %w", err)
}
if err := cdc.Unmarshal(txBytes, &raw); err != nil {
return nil, err
}
var body sdktx.TxBody
if err := cdc.Unmarshal(raw.BodyBytes, &body); err != nil {
return nil, fmt.Errorf("failed to decode tx: %w", err)
}
var authInfo sdktx.AuthInfo
// reject all unknown proto fields in AuthInfo
err = unknownproto.RejectUnknownFieldsStrict(raw.AuthInfoBytes, &authInfo, encodingConfig.InterfaceRegistry)
if err != nil {
return nil, fmt.Errorf("failed to reject unknown fields: %w", err)
}
if err := cdc.Unmarshal(raw.AuthInfoBytes, &authInfo); err != nil {
return nil, fmt.Errorf("failed to decode auth info: %w", err)
}
return &sdktx.Tx{
Body: &body,
AuthInfo: &authInfo,
Signatures: raw.Signatures,
}, nil
}
-292
View File
@@ -1,292 +0,0 @@
package e2e
import (
"context"
"encoding/json"
"fmt"
"os"
"path"
"path/filepath"
"cosmossdk.io/math"
cometcfg "github.com/cometbft/cometbft/config"
"github.com/cometbft/cometbft/p2p"
"github.com/cometbft/cometbft/privval"
sdkcrypto "github.com/cosmos/cosmos-sdk/crypto"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
"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/server"
sdk "github.com/cosmos/cosmos-sdk/types"
sdktx "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
"github.com/cosmos/cosmos-sdk/x/genutil"
genutilstypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/skip-mev/pob/tests/app"
)
type validator struct {
chain *chain
index int
moniker string
mnemonic string
keyInfo keyring.Record
privateKey cryptotypes.PrivKey
consensusKey privval.FilePVKey
nodeKey p2p.NodeKey
}
func (v *validator) instanceName() string {
return fmt.Sprintf("%s%d", v.moniker, v.index)
}
func (v *validator) configDir() string {
return fmt.Sprintf("%s/%s", v.chain.configDir(), v.instanceName())
}
func (v *validator) createConfig() error {
p := path.Join(v.configDir(), "config")
return os.MkdirAll(p, 0o755)
}
func (v *validator) init() error {
if err := v.createConfig(); err != nil {
return err
}
serverCtx := server.NewDefaultContext()
config := serverCtx.Config
config.SetRoot(v.configDir())
config.Moniker = v.moniker
genDoc, err := getGenDoc(v.configDir())
if err != nil {
return err
}
appState, err := json.MarshalIndent(app.ModuleBasics.DefaultGenesis(cdc), "", " ")
if err != nil {
return fmt.Errorf("failed to JSON encode app genesis state: %w", err)
}
genDoc.ChainID = v.chain.id
genDoc.Validators = nil
genDoc.AppState = appState
if err := genDoc.SaveAs(config.GenesisFile()); err != nil {
return err
}
genAppState, err := genutilstypes.AppGenesisFromFile(config.GenesisFile())
if err != nil {
return fmt.Errorf("failed to unmarshal genesis state: %w", err)
}
if err = genutil.ExportGenesisFile(genAppState, config.GenesisFile()); err != nil {
return fmt.Errorf("failed to export app genesis state: %w", err)
}
cometcfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config)
return nil
}
func (v *validator) createNodeKey() error {
serverCtx := server.NewDefaultContext()
config := serverCtx.Config
config.SetRoot(v.configDir())
config.Moniker = v.moniker
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
if err != nil {
return err
}
v.nodeKey = *nodeKey
return nil
}
func (v *validator) createConsensusKey() error {
serverCtx := server.NewDefaultContext()
config := serverCtx.Config
config.SetRoot(v.configDir())
config.Moniker = v.moniker
pvKeyFile := config.PrivValidatorKeyFile()
if err := os.MkdirAll(filepath.Dir(pvKeyFile), 0o777); err != nil {
return fmt.Errorf("could not create directory %q: %w", filepath.Dir(pvKeyFile), err)
}
pvStateFile := config.PrivValidatorStateFile()
if err := os.MkdirAll(filepath.Dir(pvStateFile), 0o777); err != nil {
return fmt.Errorf("could not create directory %q: %w", filepath.Dir(pvStateFile), err)
}
filePV := privval.LoadOrGenFilePV(pvKeyFile, pvStateFile)
v.consensusKey = filePV.Key
return nil
}
func (v *validator) createKeyFromMnemonic(name, mnemonic string) error {
kb, err := keyring.New(keyringAppName, keyring.BackendTest, v.configDir(), nil, cdc)
if err != nil {
return err
}
keyringAlgos, _ := kb.SupportedAlgorithms()
algo, err := keyring.NewSigningAlgoFromString(string(hd.Secp256k1Type), keyringAlgos)
if err != nil {
return err
}
info, err := kb.NewAccount(name, mnemonic, "", sdk.FullFundraiserPath, algo)
if err != nil {
return err
}
privKeyArmor, err := kb.ExportPrivKeyArmor(name, keyringPassphrase)
if err != nil {
return err
}
privKey, _, err := sdkcrypto.UnarmorDecryptPrivKey(privKeyArmor, keyringPassphrase)
if err != nil {
return err
}
v.keyInfo = *info
v.mnemonic = mnemonic
v.privateKey = privKey
return nil
}
func (v *validator) createKey(name string) error {
mnemonic, err := createMnemonic()
if err != nil {
return err
}
return v.createKeyFromMnemonic(name, mnemonic)
}
func (v *validator) buildCreateValidatorMsg(amount sdk.Coin) (sdk.Msg, error) {
description := stakingtypes.NewDescription(v.moniker, "", "", "", "")
commissionRates := stakingtypes.CommissionRates{
Rate: math.LegacyMustNewDecFromStr("0.1"),
MaxRate: math.LegacyMustNewDecFromStr("0.2"),
MaxChangeRate: math.LegacyMustNewDecFromStr("0.01"),
}
// get the initial validator min self delegation
minSelfDelegation := math.NewInt(1)
valPubKey, err := cryptocodec.FromCmtPubKeyInterface(v.consensusKey.PubKey)
if err != nil {
return nil, err
}
valAddr, err := v.keyInfo.GetAddress()
if err != nil {
return nil, err
}
return stakingtypes.NewMsgCreateValidator(
sdk.ValAddress(valAddr),
valPubKey,
amount,
description,
commissionRates,
minSelfDelegation,
)
}
func (v *validator) signMsg(msgs ...sdk.Msg) (*sdktx.Tx, error) {
txBuilder := encodingConfig.TxConfig.NewTxBuilder()
if err := txBuilder.SetMsgs(msgs...); err != nil {
return nil, err
}
txBuilder.SetMemo(fmt.Sprintf("%s@%s:26656", v.nodeKey.ID(), v.instanceName()))
txBuilder.SetFeeAmount(sdk.NewCoins())
txBuilder.SetGasLimit(200_000)
pubKey, err := v.keyInfo.GetPubKey()
if err != nil {
return nil, err
}
signerData := authsigning.SignerData{
ChainID: v.chain.id,
AccountNumber: 0,
Sequence: 0,
PubKey: pubKey,
}
// For SIGN_MODE_DIRECT, calling SetSignatures calls setSignerInfos on
// TxBuilder under the hood, and SignerInfos is needed to generate the sign
// bytes. This is the reason for setting SetSignatures here, with a nil
// signature.
//
// Note: This line is not needed for SIGN_MODE_LEGACY_AMINO, but putting it
// also doesn't affect its generated sign bytes, so for code's simplicity
// sake, we put it here.
if err != nil {
return nil, err
}
sig := signing.SignatureV2{
PubKey: pubKey,
Data: &signing.SingleSignatureData{
SignMode: signing.SignMode_SIGN_MODE_DIRECT,
Signature: nil,
},
Sequence: 0,
}
if err := txBuilder.SetSignatures(sig); err != nil {
return nil, err
}
bytesToSign, err := authsigning.GetSignBytesAdapter(
context.Background(),
encodingConfig.TxConfig.SignModeHandler(),
signing.SignMode_SIGN_MODE_DIRECT,
signerData,
txBuilder.GetTx(),
)
if err != nil {
return nil, err
}
sigBytes, err := v.privateKey.Sign(bytesToSign)
if err != nil {
return nil, err
}
sig = signing.SignatureV2{
PubKey: pubKey,
Data: &signing.SingleSignatureData{
SignMode: signing.SignMode_SIGN_MODE_DIRECT,
Signature: sigBytes,
},
Sequence: 0,
}
if err := txBuilder.SetSignatures(sig); err != nil {
return nil, err
}
signedTx := txBuilder.GetTx()
bz, err := encodingConfig.TxConfig.TxEncoder()(signedTx)
if err != nil {
return nil, err
}
return decodeTx(bz)
}
+341
View File
@@ -0,0 +1,341 @@
package integration
import (
"context"
"encoding/hex"
"encoding/json"
"strings"
"testing"
"time"
rpctypes "github.com/cometbft/cometbft/rpc/core/types"
comettypes "github.com/cometbft/cometbft/types"
"github.com/cosmos/cosmos-sdk/client/tx"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
buildertypes "github.com/skip-mev/pob/x/builder/types"
interchaintest "github.com/strangelove-ventures/interchaintest/v7"
"github.com/strangelove-ventures/interchaintest/v7/chain/cosmos"
"github.com/strangelove-ventures/interchaintest/v7/ibc"
"github.com/strangelove-ventures/interchaintest/v7/testutil"
"github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
// ChainBuilderFromChainSpec creates an interchaintest chain builder factory given a ChainSpec
// and returns the associated chain
func ChainBuilderFromChainSpec(t *testing.T, spec *interchaintest.ChainSpec) ibc.Chain {
// require that NumFullNodes == NumValidators == 4
require.Equal(t, *spec.NumValidators, 4)
cf := interchaintest.NewBuiltinChainFactory(zaptest.NewLogger(t), []*interchaintest.ChainSpec{spec})
chains, err := cf.Chains(t.Name())
require.NoError(t, err)
require.Len(t, chains, 1)
chain := chains[0]
_, ok := chain.(*cosmos.CosmosChain)
require.True(t, ok)
return chain
}
// BuildPOBInterchain creates a new Interchain testing env with the configured POB CosmosChain
func BuildPOBInterchain(t *testing.T, ctx context.Context, chain ibc.Chain) *interchaintest.Interchain {
ic := interchaintest.NewInterchain()
ic.AddChain(chain)
// create docker network
client, networkID := interchaintest.DockerSetup(t)
ctx, cancel := context.WithTimeout(ctx, 2*time.Minute)
defer cancel()
// build the interchain
err := ic.Build(ctx, nil, interchaintest.InterchainBuildOptions{
SkipPathCreation: true,
Client: client,
NetworkID: networkID,
TestName: t.Name(),
})
require.NoError(t, err)
return ic
}
// CreateTx creates a new transaction to be signed by the given user, including a provided set of messages
func CreateTx(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, user cosmos.User, seqIncrement, height uint64, GasPrice int64, msgs ...sdk.Msg) []byte {
// create a broadcaster
broadcaster := cosmos.NewBroadcaster(t, chain)
// create tx factory + Client Context
txf, err := broadcaster.GetFactory(ctx, user)
require.NoError(t, err)
cc, err := broadcaster.GetClientContext(ctx, user)
require.NoError(t, err)
txf, err = txf.Prepare(cc)
require.NoError(t, err)
// set timeout height
if height != 0 {
txf = txf.WithTimeoutHeight(height)
}
// get gas for tx
_, gas, err := tx.CalculateGas(cc, txf, msgs...)
require.NoError(t, err)
txf.WithGas(gas)
// update sequence number
txf = txf.WithSequence(txf.Sequence() + seqIncrement)
txf = txf.WithGasPrices(sdk.NewDecCoins(sdk.NewDecCoin(chain.Config().Denom, sdk.NewInt(GasPrice))).String())
// sign the tx
txBuilder, err := txf.BuildUnsignedTx(msgs...)
require.NoError(t, err)
require.NoError(t, tx.Sign(txf, cc.GetFromName(), txBuilder, true))
// encode and return
bz, err := cc.TxConfig.TxEncoder()(txBuilder.GetTx())
require.NoError(t, err)
return bz
}
// SimulateTx simulates the provided messages, and checks whether the provided failure condition is met
func SimulateTx(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, user cosmos.User, height uint64, expectFail bool, msgs ...sdk.Msg) {
// create a broadcaster
broadcaster := cosmos.NewBroadcaster(t, chain)
// create tx factory + Client Context
txf, err := broadcaster.GetFactory(ctx, user)
require.NoError(t, err)
cc, err := broadcaster.GetClientContext(ctx, user)
require.NoError(t, err)
txf, err = txf.Prepare(cc)
require.NoError(t, err)
// set timeout height
if height != 0 {
txf = txf.WithTimeoutHeight(height)
}
// get gas for tx
_, _, err = tx.CalculateGas(cc, txf, msgs...)
require.Equal(t, err != nil, expectFail)
}
type Tx struct {
User cosmos.User
Msgs []sdk.Msg
GasPrice int64
SequenceIncrement uint64
Height uint64
SkipInclusionCheck bool
ExpectFail bool
}
// CreateAuctionBidMsg creates a new AuctionBid tx signed by the given user, the order of txs in the MsgAuctionBid will be determined by the contents + order of the MessageForUsers
func CreateAuctionBidMsg(t *testing.T, ctx context.Context, searcher cosmos.User, chain *cosmos.CosmosChain, bid sdk.Coin, txsPerUser []Tx) (*buildertypes.MsgAuctionBid, [][]byte) {
// for each MessagesForUser get the signed bytes
txs := make([][]byte, len(txsPerUser))
for i, tx := range txsPerUser {
txs[i] = CreateTx(t, ctx, chain, tx.User, tx.SequenceIncrement, tx.Height, tx.GasPrice, tx.Msgs...)
}
bech32SearcherAddress := searcher.FormattedAddress()
accAddr, err := sdk.AccAddressFromBech32(bech32SearcherAddress)
require.NoError(t, err)
// create a message auction bid
return buildertypes.NewMsgAuctionBid(
accAddr,
bid,
txs,
), txs
}
// BroadcastTxs broadcasts the given messages for each user. This function returns the broadcasted txs. If a message
// is not expected to be included in a block, set SkipInclusionCheck to true and the method
// will not block on the tx's inclusion in a block, otherwise this method will block on the tx's inclusion
func BroadcastTxs(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, msgsPerUser []Tx) [][]byte {
txs := make([][]byte, len(msgsPerUser))
for i, msg := range msgsPerUser {
txs[i] = CreateTx(t, ctx, chain, msg.User, msg.SequenceIncrement, msg.Height, msg.GasPrice, msg.Msgs...)
}
// broadcast each tx
require.True(t, len(chain.Nodes()) > 0)
client := chain.Nodes()[0].Client
for i, tx := range txs {
// broadcast tx
_, err := client.BroadcastTxSync(ctx, tx)
// check execution was successful
if !msgsPerUser[i].ExpectFail {
require.NoError(t, err)
} else {
require.Error(t, err)
}
}
// block on all txs being included in block
eg := errgroup.Group{}
for i, tx := range txs {
// if we don't expect this tx to be included.. skip it
if msgsPerUser[i].SkipInclusionCheck || msgsPerUser[i].ExpectFail {
continue
}
tx := tx // pin
eg.Go(func() error {
return testutil.WaitForCondition(4*time.Second, 500*time.Millisecond, func() (bool, error) {
res, err := client.Tx(context.Background(), comettypes.Tx(tx).Hash(), false)
if err != nil || res.TxResult.Code != uint32(0) {
return false, nil
}
return true, nil
})
})
}
require.NoError(t, eg.Wait())
return txs
}
// QueryBuilderParams queries the x/builder module's params
func QueryBuilderParams(t *testing.T, chain ibc.Chain) buildertypes.Params {
// cast chain to cosmos-chain
cosmosChain, ok := chain.(*cosmos.CosmosChain)
require.True(t, ok)
// get nodes
nodes := cosmosChain.Nodes()
require.True(t, len(nodes) > 0)
// make params query to first node
resp, _, err := nodes[0].ExecQuery(context.Background(), "builder", "params")
require.NoError(t, err)
// unmarshal params
var params buildertypes.Params
err = json.Unmarshal(resp, &params)
require.NoError(t, err)
return params
}
// QueryValidators queries for all of the network's validators
func QueryValidators(t *testing.T, chain *cosmos.CosmosChain) []sdk.ValAddress {
// get grpc client of the node
grpcAddr := chain.GetHostGRPCAddress()
cc, err := grpc.Dial(grpcAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
require.NoError(t, err)
client := stakingtypes.NewQueryClient(cc)
// query validators
resp, err := client.Validators(context.Background(), &stakingtypes.QueryValidatorsRequest{})
require.NoError(t, err)
addrs := make([]sdk.ValAddress, len(resp.Validators))
// unmarshal validators
for i, val := range resp.Validators {
addrBz, err := sdk.GetFromBech32(val.OperatorAddress, chain.Config().Bech32Prefix+sdk.PrefixValidator+sdk.PrefixOperator)
require.NoError(t, err)
addrs[i] = sdk.ValAddress(addrBz)
}
return addrs
}
// QueryAccountBalance queries a given account's balance on the chain
func QueryAccountBalance(t *testing.T, chain ibc.Chain, address, denom string) int64 {
// cast the chain to a cosmos-chain
cosmosChain, ok := chain.(*cosmos.CosmosChain)
require.True(t, ok)
// get nodes
balance, err := cosmosChain.GetBalance(context.Background(), address, denom)
require.NoError(t, err)
return balance
}
// QueryAccountSequence
func QueryAccountSequence(t *testing.T, chain *cosmos.CosmosChain, address string) uint64 {
// get nodes
nodes := chain.Nodes()
require.True(t, len(nodes) > 0)
resp, _, err := nodes[0].ExecQuery(context.Background(), "auth", "account", address)
require.NoError(t, err)
// unmarshal json response
var accResp codectypes.Any
require.NoError(t, json.Unmarshal(resp, &accResp))
// unmarshal into baseAccount
var acc authtypes.BaseAccount
require.NoError(t, acc.Unmarshal(accResp.Value))
return acc.GetSequence()
}
// Block returns the block at the given height
func Block(t *testing.T, chain *cosmos.CosmosChain, height int64) *rpctypes.ResultBlock {
// get nodes
nodes := chain.Nodes()
require.True(t, len(nodes) > 0)
client := nodes[0].Client
resp, err := client.Block(context.Background(), &height)
require.NoError(t, err)
return resp
}
// WaitForHeight waits for the chain to reach the given height
func WaitForHeight(t *testing.T, chain *cosmos.CosmosChain, height uint64) {
// wait for next height
err := testutil.WaitForCondition(30*time.Second, time.Second, func() (bool, error) {
pollHeight, err := chain.Height(context.Background())
if err != nil {
return false, err
}
return pollHeight == height, nil
})
require.NoError(t, err)
}
// VerifyBlock takes a Block and verifies that it contains the given bid at the 0-th index, and the bundled txs immediately after
func VerifyBlock(t *testing.T, block *rpctypes.ResultBlock, offset int, bidTxHash string, txs [][]byte) {
// verify the block
if bidTxHash != "" {
require.Equal(t, bidTxHash, TxHash(block.Block.Data.Txs[offset]))
offset += 1
}
// verify the txs in sequence
for i, tx := range txs {
require.Equal(t, TxHash(tx), TxHash(block.Block.Data.Txs[i+offset]))
}
}
func TxHash(tx []byte) string {
return strings.ToUpper(hex.EncodeToString(comettypes.Tx(tx).Hash()))
}
+246
View File
@@ -0,0 +1,246 @@
module github.com/skip-mev/pob/tests/integration
go 1.20
replace (
// interchaintest supports ICS features so we need this for now
// github.com/cosmos/cosmos-sdk => github.com/cosmos/cosmos-sdk v0.45.13-ics
github.com/ChainSafe/go-schnorrkel => github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d
github.com/ChainSafe/go-schnorrkel/1 => github.com/ChainSafe/go-schnorrkel v1.0.0
github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.22.2 //indirect
github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1
github.com/vedhavyas/go-subkey => github.com/strangelove-ventures/go-subkey v1.0.7
)
require (
cosmossdk.io/api v0.3.1 // indirect
cosmossdk.io/core v0.5.1 // indirect
cosmossdk.io/depinject v1.0.0-alpha.3 // indirect
cosmossdk.io/errors v1.0.0 // indirect
cosmossdk.io/log v1.1.1-0.20230704160919-88f2c830b0ca // indirect
cosmossdk.io/math v1.0.1 // indirect
cosmossdk.io/tools/rosetta v0.2.1 // indirect
github.com/cosmos/cosmos-sdk v0.47.4
github.com/skip-mev/pob v1.0.3 // reference local
github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20230721183422-fb937bb0e165
github.com/stretchr/testify v1.8.4
go.uber.org/zap v1.24.0
golang.org/x/sync v0.3.0
)
require (
github.com/cometbft/cometbft v0.37.2
google.golang.org/grpc v1.56.2
)
require (
cloud.google.com/go v0.110.4 // indirect
cloud.google.com/go/compute v1.20.1 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v1.1.0 // indirect
cloud.google.com/go/storage v1.30.1 // indirect
filippo.io/edwards25519 v1.0.0 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/99designs/keyring v1.2.2 // indirect
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/ChainSafe/go-schnorrkel v1.0.0 // indirect
github.com/ChainSafe/go-schnorrkel/1 v0.0.0-00010101000000-000000000000 // indirect
github.com/ComposableFi/go-subkey/v2 v2.0.0-tm03420 // indirect
github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect
github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect
github.com/Microsoft/go-winio v0.6.0 // indirect
github.com/StirlingMarketingGroup/go-namecase v1.0.0 // indirect
github.com/armon/go-metrics v0.4.1 // indirect
github.com/avast/retry-go/v4 v4.3.4 // indirect
github.com/aws/aws-sdk-go v1.44.203 // indirect
github.com/benbjohnson/clock v1.3.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chzyer/readline v1.5.1 // indirect
github.com/coinbase/rosetta-sdk-go/types v1.0.0 // indirect
github.com/cometbft/cometbft-db v0.8.0 // indirect
github.com/confio/ics23/go v0.9.0 // indirect
github.com/cosmos/btcutil v1.0.5 // indirect
github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect
github.com/cosmos/go-bip39 v1.0.0 // indirect
github.com/cosmos/gogogateway v1.2.0 // indirect
github.com/cosmos/gogoproto v1.4.10 // indirect
github.com/cosmos/iavl v0.20.0 // indirect
github.com/cosmos/ibc-go/v7 v7.2.0 // indirect
github.com/cosmos/ics23/go v0.10.0 // indirect
github.com/cosmos/ledger-cosmos-go v0.12.1 // indirect
github.com/cosmos/rosetta-sdk-go v0.10.0 // indirect
github.com/creachadair/taskgroup v0.4.2 // indirect
github.com/danieljoos/wincred v1.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/deckarep/golang-set v1.8.0 // indirect
github.com/decred/base58 v1.0.4 // indirect
github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v2 v2.0.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
github.com/docker/distribution v2.8.2+incompatible // indirect
github.com/docker/docker v24.0.4+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
github.com/ethereum/go-ethereum v1.10.20 // indirect
github.com/felixge/httpsnoop v1.0.2 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-kit/kit v0.12.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.3 // indirect
github.com/golang/glog v1.1.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/orderedcode v0.0.1 // indirect
github.com/google/s2a-go v0.1.4 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
github.com/googleapis/gax-go/v2 v2.11.0 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
github.com/gtank/merlin v0.1.1 // indirect
github.com/gtank/ristretto255 v0.1.2 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-getter v1.7.1 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-safetemp v1.0.0 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hdevalence/ed25519consensus v0.1.0 // indirect
github.com/huandu/skiplist v1.2.0 // indirect
github.com/icza/dyno v0.0.0-20220812133438-f0b6f8a18845 // indirect
github.com/improbable-eng/grpc-web v0.15.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/ipfs/go-cid v0.2.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/klauspost/compress v1.16.3 // indirect
github.com/klauspost/cpuid/v2 v2.2.3 // indirect
github.com/lib/pq v1.10.7 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/libp2p/go-libp2p v0.22.0 // indirect
github.com/libp2p/go-openssl v0.1.0 // indirect
github.com/linxGnu/grocksdb v1.7.16 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/manifoldco/promptui v0.9.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-pointer v0.0.1 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mimoo/StrobeGo v0.0.0-20220103164710-9a04d6ca976b // indirect
github.com/minio/highwayhash v1.0.2 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/misko9/go-substrate-rpc-client/v4 v4.0.0-20230413215336-5bd2aea337ae // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/mtibben/percent v0.2.1 // indirect
github.com/multiformats/go-base32 v0.0.4 // indirect
github.com/multiformats/go-base36 v0.1.0 // indirect
github.com/multiformats/go-multiaddr v0.6.0 // indirect
github.com/multiformats/go-multibase v0.1.1 // indirect
github.com/multiformats/go-multicodec v0.5.0 // indirect
github.com/multiformats/go-multihash v0.2.1 // indirect
github.com/multiformats/go-varint v0.0.6 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc2 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.9 // indirect
github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect
github.com/pierrec/xxHash v0.1.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.15.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.9.0 // indirect
github.com/rakyll/statik v0.1.7 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rs/cors v1.8.3 // indirect
github.com/rs/zerolog v1.29.1 // indirect
github.com/sasha-s/go-deadlock v0.3.1 // indirect
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/afero v1.9.5 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/cobra v1.7.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.16.0 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
github.com/tendermint/go-amino v0.16.0 // indirect
github.com/tidwall/btree v1.6.0 // indirect
github.com/tyler-smith/go-bip32 v1.0.0 // indirect
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
github.com/ulikunitz/xz v0.5.11 // indirect
github.com/zondax/hid v0.9.1 // indirect
github.com/zondax/ledger-go v0.14.1 // indirect
go.etcd.io/bbolt v1.3.7 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.11.0 // indirect
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.12.0 // indirect
golang.org/x/oauth2 v0.8.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/term v0.10.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/tools v0.11.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/api v0.126.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.1.7 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.40.0 // indirect
modernc.org/ccgo/v3 v3.16.13 // indirect
modernc.org/libc v1.22.5 // indirect
modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.5.0 // indirect
modernc.org/opt v0.1.3 // indirect
modernc.org/sqlite v1.24.0 // indirect
modernc.org/strutil v1.1.3 // indirect
modernc.org/token v1.0.1 // indirect
nhooyr.io/websocket v1.8.6 // indirect
pgregory.net/rapid v0.5.5 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)
File diff suppressed because it is too large Load Diff
+80
View File
@@ -0,0 +1,80 @@
package integration_test
import (
"fmt"
"testing"
testutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
buildertypes "github.com/skip-mev/pob/x/builder/types"
"github.com/strangelove-ventures/interchaintest/v7"
"github.com/skip-mev/pob/tests/integration"
"github.com/strangelove-ventures/interchaintest/v7/chain/cosmos"
"github.com/strangelove-ventures/interchaintest/v7/ibc"
"github.com/stretchr/testify/suite"
)
var (
// config params
numValidators = 4
numFullNodes = 0
denom = "stake"
image = ibc.DockerImage{
Repository: "pob-integration",
Version: "latest",
UidGid: "1000:1000",
}
encodingConfig = MakeEncodingConfig()
noHostMount = false
gasAdjustment = float64(2.0)
genesisKV = []cosmos.GenesisKV{
{
Key: "app_state.builder.params.max_bundle_size",
Value: 3,
},
}
// interchain specification
spec = &interchaintest.ChainSpec{
ChainName: "pob",
Name: "pob",
NumValidators: &numValidators,
NumFullNodes: &numFullNodes,
Version: "latest",
NoHostMount: &noHostMount,
GasAdjustment: &gasAdjustment,
ChainConfig: ibc.ChainConfig{
EncodingConfig: encodingConfig,
Images: []ibc.DockerImage{
image,
},
Type: "cosmos",
Name: "pob",
Denom: denom,
ChainID: "chain-id-0",
Bin: "testappd",
Bech32Prefix: "cosmos",
CoinType: "118",
GasAdjustment: gasAdjustment,
GasPrices: fmt.Sprintf("0%s", denom),
TrustingPeriod: "48h",
NoHostMount: noHostMount,
UsingNewGenesisCommand: true,
ModifyGenesis: cosmos.ModifyGenesis(genesisKV),
},
}
)
func MakeEncodingConfig() *testutil.TestEncodingConfig {
cfg := cosmos.DefaultEncoding()
// register builder types
buildertypes.RegisterInterfaces(cfg.InterfaceRegistry)
return &cfg
}
func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, integration.NewPOBIntegrationTestSuiteFromSpec(spec))
}
File diff suppressed because it is too large Load Diff