Skip to content

Commit

Permalink
feat: add the ability to specifiy the txsim master account (#2292)
Browse files Browse the repository at this point in the history
## Overview

This PR adds the ability to specify a specific account to use as master
for txsim. This is useful for when we don't want to always use the
account with the most funds in our wallet.

closes #2286
kinda sorta blocking #2197 

## Checklist

- [x] New and updated code has appropriate documentation
- [x] New and updated code has new and/or updated testing
- [x] Required CI checks are passing
- [x] Visual proof for any user facing features like CLI or
documentation updates
- [x] Linked issues closed with keywords
  • Loading branch information
evan-forbes authored Aug 17, 2023
1 parent c30990d commit 2102189
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 22 deletions.
1 change: 1 addition & 0 deletions app/test/square_size_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ func (s *SquareSizeIntegrationTest) fillBlocks(blobSize, blobsPerPFB, pfbsPerBlo
[]string{s.rpcAddr},
[]string{s.grpcAddr},
s.cctx.Keyring,
"",
rand.Int63(),
time.Second,
seqs...,
Expand Down
31 changes: 19 additions & 12 deletions test/cmd/txsim/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,23 @@ import (

// A set of environment variables that can be used instead of flags
const (
TxsimGRPC = "TXSIM_GRPC"
TxsimRPC = "TXSIM_RPC"
TxsimSeed = "TXSIM_SEED"
TxsimPoll = "TXSIM_POLL"
TxsimKeypath = "TXSIM_KEYPATH"
TxsimMnemonic = "TXSIM_MNEMONIC"
TxsimGRPC = "TXSIM_GRPC"
TxsimRPC = "TXSIM_RPC"
TxsimSeed = "TXSIM_SEED"
TxsimPoll = "TXSIM_POLL"
TxsimKeypath = "TXSIM_KEYPATH"
TxsimMasterAccName = "TXSIM_MASTER_ACC_NAME"
TxsimMnemonic = "TXSIM_MNEMONIC"
)

// Values for all flags
var (
keyPath, keyMnemonic, rpcEndpoints, grpcEndpoints string
blobSizes, blobAmounts string
seed int64
pollTime time.Duration
send, sendIterations, sendAmount int
stake, stakeValue, blob int
keyPath, masterAccName, keyMnemonic, rpcEndpoints, grpcEndpoints string
blobSizes, blobAmounts string
seed int64
pollTime time.Duration
send, sendIterations, sendAmount int
stake, stakeValue, blob int
)

func main() {
Expand Down Expand Up @@ -101,6 +102,10 @@ well funded account that can act as the master account. The command runs until a
}
}

if masterAccName == "" {
masterAccName = os.Getenv(TxsimMasterAccName)
}

if stake == 0 && send == 0 && blob == 0 {
return errors.New("no sequences specified. Use --stake, --send or --blob")
}
Expand Down Expand Up @@ -154,6 +159,7 @@ well funded account that can act as the master account. The command runs until a
strings.Split(rpcEndpoints, ","),
strings.Split(grpcEndpoints, ","),
keys,
masterAccName,
seed,
pollTime,
sequences...,
Expand All @@ -172,6 +178,7 @@ well funded account that can act as the master account. The command runs until a
func flags() *flag.FlagSet {
flags := &flag.FlagSet{}
flags.StringVar(&keyPath, "key-path", "", "path to the keyring")
flags.StringVar(&masterAccName, "master", "", "the account name of the master account. Leaving empty will result in using the account with the most funds.")
flags.StringVar(&keyMnemonic, "key-mnemonic", "", "space separated mnemonic for the keyring. The hdpath used is an empty string")
flags.StringVar(&rpcEndpoints, "rpc-endpoints", "", "comma separated list of rpc endpoints")
flags.StringVar(&grpcEndpoints, "grpc-endpoints", "", "comma separated list of grpc endpoints")
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/simple_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func TestE2ESimple(t *testing.T) {

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
err = txsim.Run(ctx, testnet.RPCEndpoints(), testnet.GRPCEndpoints(), kr, seed, 3*time.Second, sequences...)
err = txsim.Run(ctx, testnet.RPCEndpoints(), testnet.GRPCEndpoints(), kr, "", seed, 3*time.Second, sequences...)
require.True(t, errors.Is(err, context.DeadlineExceeded), err.Error())

blockchain, err := testnode.ReadBlockchain(context.Background(), testnet.Node(0).AddressRPC())
Expand Down
60 changes: 52 additions & 8 deletions test/txsim/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ type Account struct {
Balance int64
}

func NewAccountManager(ctx context.Context, keys keyring.Keyring, txClient *TxClient, queryClient *QueryClient) (*AccountManager, error) {
func NewAccountManager(ctx context.Context, keys keyring.Keyring, masterAccName string, txClient *TxClient, queryClient *QueryClient) (*AccountManager, error) {
records, err := keys.List()
if err != nil {
return nil, err
Expand All @@ -60,8 +60,14 @@ func NewAccountManager(ctx context.Context, keys keyring.Keyring, txClient *TxCl
query: queryClient,
}

if err := am.setupMasterAccount(ctx); err != nil {
return nil, err
if masterAccName == "" {
if err := am.setupDefaultMasterAccount(ctx); err != nil {
return nil, err
}
} else {
if err := am.setupSpecifiedMasterAccount(ctx, masterAccName); err != nil {
return nil, err
}
}

log.Info().
Expand All @@ -73,10 +79,10 @@ func NewAccountManager(ctx context.Context, keys keyring.Keyring, txClient *TxCl
return am, nil
}

// setupMasterAccount loops through all accounts in the keyring and picks out the one with
// setupDefaultMasterAccount loops through all accounts in the keyring and picks out the one with
// the highest balance as the master account. Accounts that don't yet exist on chain are
// ignored.
func (am *AccountManager) setupMasterAccount(ctx context.Context) error {
func (am *AccountManager) setupDefaultMasterAccount(ctx context.Context) error {
am.mtx.Lock()
defer am.mtx.Unlock()

Expand Down Expand Up @@ -126,6 +132,44 @@ func (am *AccountManager) setupMasterAccount(ctx context.Context) error {
return nil
}

func (am *AccountManager) setupSpecifiedMasterAccount(ctx context.Context, masterAccName string) error {
masterRecord, err := am.keys.Key(masterAccName)
if err != nil {
return fmt.Errorf("error getting specified master account %s: %w", masterAccName, err)
}

masterAddress, err := masterRecord.GetAddress()
if err != nil {
return fmt.Errorf("error getting address for account %s: %w", masterAccName, err)
}

// search for the account on chain
masterBalance, err := am.getBalance(ctx, masterAddress)
if err != nil {
return fmt.Errorf("error getting specified master account %s balance: %w", masterAccName, err)
}

accountNumber, sequence, err := am.getAccountDetails(ctx, masterAddress)
if err != nil {
return fmt.Errorf("error getting account details for account %s: %w", masterRecord.Name, err)
}

pk, err := masterRecord.GetPubKey()
if err != nil {
return fmt.Errorf("error getting public key for account %s: %w", masterRecord.Name, err)
}

am.masterAccount = &Account{
Address: masterAddress,
PubKey: pk,
Sequence: sequence,
AccountNumber: accountNumber,
Balance: masterBalance,
}

return nil
}

// AllocateAccounts is used by sequences to specify the number of accounts
// and the balance of each of those accounts. Not concurrently safe.
func (am *AccountManager) AllocateAccounts(n, balance int) []types.AccAddress {
Expand Down Expand Up @@ -220,8 +264,8 @@ func (am *AccountManager) Submit(ctx context.Context, op Operation) error {
return nil
}

// Generate the pending accounts by sending the adequate funds and setting up the feegrant permissions.
// This operation is not concurrently safe.
// Generate the pending accounts by sending the adequate funds. This operation
// is not concurrently safe.
func (am *AccountManager) GenerateAccounts(ctx context.Context) error {
if len(am.pending) == 0 {
return nil
Expand All @@ -231,7 +275,7 @@ func (am *AccountManager) GenerateAccounts(ctx context.Context) error {
// batch together all the messages needed to create all the accounts
for _, acc := range am.pending {
if am.masterAccount.Balance < acc.Balance {
return fmt.Errorf("master account has insufficient funds")
return fmt.Errorf("master account has insufficient funds needed: %v", acc.Balance)
}

bankMsg := bank.NewMsgSend(am.masterAccount.Address, acc.Address, types.NewCoins(types.NewInt64Coin(appconsts.BondDenom, acc.Balance)))
Expand Down
3 changes: 2 additions & 1 deletion test/txsim/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func Run(
ctx context.Context,
rpcEndpoints, grpcEndpoints []string,
keys keyring.Keyring,
masterAccName string,
seed int64,
pollTime time.Duration,
sequences ...Sequence,
Expand All @@ -45,7 +46,7 @@ func Run(
defer queryClient.Close()

// Create the account manager to handle account transactions.
manager, err := NewAccountManager(ctx, keys, txClient, queryClient)
manager, err := NewAccountManager(ctx, keys, masterAccName, txClient, queryClient)
if err != nil {
return err
}
Expand Down
1 change: 1 addition & 0 deletions test/txsim/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ func TestTxSimulator(t *testing.T) {
[]string{rpcAddr},
[]string{grpcAddr},
keyring,
"",
9001,
time.Second,
tc.sequences...,
Expand Down

0 comments on commit 2102189

Please sign in to comment.