From 4c825e77f7e7726d4bae56d093f00becd6b413db Mon Sep 17 00:00:00 2001 From: Xiaoyu Chen Date: Sat, 11 Jun 2022 14:17:32 -0700 Subject: [PATCH 1/2] Fix loadtest scripts --- loadtest/main.go | 169 ++++++++++++++++--------- loadtest/sign.go | 3 +- loadtest/tx.go | 10 +- scripts/initialize_local_test_node.sh | 20 +-- x/dex/keeper/end_block_place_orders.go | 56 ++++++-- 5 files changed, 172 insertions(+), 86 deletions(-) diff --git a/loadtest/main.go b/loadtest/main.go index 5b7fa007ab..030868be6d 100644 --- a/loadtest/main.go +++ b/loadtest/main.go @@ -1,12 +1,15 @@ package main import ( + "encoding/json" "fmt" "math/rand" "os" + "os/exec" "path/filepath" "strconv" "sync" + "time" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" @@ -37,6 +40,8 @@ var ( const BATCH_SIZE = 100 +var FROM_MILI = sdk.NewDec(1000000) + func init() { cdc := codec.NewLegacyAmino() interfaceRegistry := types.NewInterfaceRegistry() @@ -57,7 +62,7 @@ func init() { func run( contractAddress string, numberOfAccounts uint64, - numberOfOrders uint64, + numberOfBlocks uint64, longPriceFloor uint64, longPriceCeiling uint64, shortPriceFloor uint64, @@ -80,75 +85,125 @@ func run( return } TX_HASH_FILE = file - - var wg sync.WaitGroup var mu sync.Mutex - var senders []func() - - for i := uint64(0); i < numberOfOrders/BATCH_SIZE; i++ { - fmt.Println(fmt.Sprintf("Preparing %d-th order", i)) - accountIdx := i % numberOfAccounts - key := GetKey(accountIdx) - orderPlacements := []*dextypes.OrderPlacement{} - longPrice := i%(longPriceCeiling-longPriceFloor) + longPriceFloor - longQuantity := uint64(rand.Intn(int(quantityCeiling)-int(quantityFloor))) + quantityFloor - shortPrice := i%(shortPriceCeiling-shortPriceFloor) + shortPriceFloor - shortQuantity := uint64(rand.Intn(int(quantityCeiling)-int(quantityFloor))) + quantityFloor - for j := 0; j < BATCH_SIZE; j++ { - orderPlacements = append(orderPlacements, &dextypes.OrderPlacement{ - Long: true, - Price: longPrice, - Quantity: longQuantity, - PriceDenom: "ust", - AssetDenom: "luna", - Open: true, - Limit: true, - Leverage: "1", - }, &dextypes.OrderPlacement{ - Long: false, - Price: shortPrice, - Quantity: shortQuantity, - PriceDenom: "ust", - AssetDenom: "luna", - Open: true, - Limit: true, - Leverage: "1", + + var activeAccounts = []int{} + var inactiveAccounts = []int{} + for i := 0; i < int(numberOfAccounts); i++ { + if i%2 == 0 { + activeAccounts = append(activeAccounts, i) + } else { + inactiveAccounts = append(inactiveAccounts, i) + } + } + wgs := []*sync.WaitGroup{} + sendersList := [][]func(){} + for i := 0; i < int(numberOfBlocks); i++ { + fmt.Println(fmt.Sprintf("Preparing %d-th block", i)) + var wg *sync.WaitGroup = &sync.WaitGroup{} + var senders []func() + wgs = append(wgs, wg) + for j, account := range activeAccounts { + key := GetKey(uint64(account)) + orderPlacements := []*dextypes.OrderPlacement{} + longPrice := uint64(j)%(longPriceCeiling-longPriceFloor) + longPriceFloor + longQuantity := uint64(rand.Intn(int(quantityCeiling)-int(quantityFloor))) + quantityFloor + shortPrice := uint64(j)%(shortPriceCeiling-shortPriceFloor) + shortPriceFloor + shortQuantity := uint64(rand.Intn(int(quantityCeiling)-int(quantityFloor))) + quantityFloor + for j := 0; j < BATCH_SIZE; j++ { + orderPlacements = append(orderPlacements, &dextypes.OrderPlacement{ + PositionDirection: dextypes.PositionDirection_LONG, + Price: sdk.NewDec(int64(longPrice)).Quo(FROM_MILI), + Quantity: sdk.NewDec(int64(longQuantity)).Quo(FROM_MILI), + PriceDenom: dextypes.Denom_USDC, + AssetDenom: dextypes.Denom_SEI, + PositionEffect: dextypes.PositionEffect_OPEN, + OrderType: dextypes.OrderType_LIMIT, + Leverage: sdk.NewDec(1), + }, &dextypes.OrderPlacement{ + PositionDirection: dextypes.PositionDirection_SHORT, + Price: sdk.NewDec(int64(shortPrice)).Quo(FROM_MILI), + Quantity: sdk.NewDec(int64(shortQuantity)).Quo(FROM_MILI), + PriceDenom: dextypes.Denom_USDC, + AssetDenom: dextypes.Denom_SEI, + PositionEffect: dextypes.PositionEffect_OPEN, + OrderType: dextypes.OrderType_LIMIT, + Leverage: sdk.NewDec(1), + }) + } + amount, err := sdk.ParseCoinsNormalized(fmt.Sprintf("%d%s", longPrice*longQuantity+shortPrice*shortQuantity, "usei")) + if err != nil { + panic(err) + } + msg := dextypes.MsgPlaceOrders{ + Creator: sdk.AccAddress(key.PubKey().Address()).String(), + Orders: orderPlacements, + ContractAddr: contractAddress, + Funds: amount, + } + txBuilder := TEST_CONFIG.TxConfig.NewTxBuilder() + _ = txBuilder.SetMsgs(&msg) + seqDelta := uint64(i / 2) + SignTx(&txBuilder, key, seqDelta) + mode := typestx.BroadcastMode_BROADCAST_MODE_SYNC + if j == len(activeAccounts)-1 { + mode = typestx.BroadcastMode_BROADCAST_MODE_BLOCK + } + sender := SendTx(key, &txBuilder, mode, seqDelta, &mu) + wg.Add(1) + senders = append(senders, func() { + defer wg.Done() + sender() }) } - amount, err := sdk.ParseCoinsNormalized(fmt.Sprintf("%d%s", longPrice*longQuantity+shortPrice*shortQuantity, "ust")) - if err != nil { - panic(err) + sendersList = append(sendersList, senders) + + tmp := inactiveAccounts + inactiveAccounts = activeAccounts + activeAccounts = tmp + } + + lastHeight := getLastHeight() + for i := 0; i < int(numberOfBlocks); i++ { + newHeight := getLastHeight() + for newHeight == lastHeight { + time.Sleep(50 * time.Millisecond) + newHeight = getLastHeight() } - msg := dextypes.MsgPlaceOrders{ - Creator: sdk.AccAddress(key.PubKey().Address()).String(), - Orders: orderPlacements, - ContractAddr: contractAddress, - Nonce: i, - Funds: amount, + fmt.Println(fmt.Sprintf("Sending %d-th block", i)) + + senders := sendersList[i] + wg := wgs[i] + + for _, sender := range senders { + go sender() } - txBuilder := TEST_CONFIG.TxConfig.NewTxBuilder() - _ = txBuilder.SetMsgs(&msg) - SignTx(&txBuilder, key) - sender := SendTx(key, &txBuilder, &mu) - wg.Add(1) - senders = append(senders, func() { - defer wg.Done() - sender() - }) + wg.Wait() } +} - for _, sender := range senders { - go sender() +func getLastHeight() int { + out, err := exec.Command("curl", "http://localhost:26657/blockchain").Output() + if err != nil { + panic(err) } - - wg.Wait() + var dat map[string]interface{} + if err := json.Unmarshal(out, &dat); err != nil { + panic(err) + } + result := dat["result"].(map[string]interface{}) + height, err := strconv.Atoi(result["last_height"].(string)) + if err != nil { + panic(err) + } + return height } func main() { args := os.Args[1:] contractAddress := args[0] numberOfAccounts, _ := strconv.ParseUint(args[1], 10, 64) - numberOfOrders, _ := strconv.ParseUint(args[2], 10, 64) + numberOfBlocks, _ := strconv.ParseUint(args[2], 10, 64) longPriceFloor, _ := strconv.ParseUint(args[3], 10, 64) longPriceCeiling, _ := strconv.ParseUint(args[4], 10, 64) shortPriceFloor, _ := strconv.ParseUint(args[5], 10, 64) @@ -160,7 +215,7 @@ func main() { run( contractAddress, numberOfAccounts, - numberOfOrders, + numberOfBlocks, longPriceFloor, longPriceCeiling, shortPriceFloor, diff --git a/loadtest/sign.go b/loadtest/sign.go index 4d0f71d0b4..efa2fce19f 100644 --- a/loadtest/sign.go +++ b/loadtest/sign.go @@ -49,9 +49,10 @@ func GetKey(accountIdx uint64) cryptotypes.PrivKey { return algo.Generate()(derivedPriv) } -func SignTx(txBuilder *client.TxBuilder, privKey cryptotypes.PrivKey) { +func SignTx(txBuilder *client.TxBuilder, privKey cryptotypes.PrivKey, seqDelta uint64) { var sigsV2 []signing.SignatureV2 accountNum, seqNum := GetAccountNumberSequenceNumber(privKey) + seqNum += seqDelta sigV2 := signing.SignatureV2{ PubKey: privKey.PubKey(), Data: &signing.SingleSignatureData{ diff --git a/loadtest/tx.go b/loadtest/tx.go index 413de91fc7..76ae95a53d 100644 --- a/loadtest/tx.go +++ b/loadtest/tx.go @@ -26,19 +26,21 @@ const ( func SendTx( key cryptotypes.PrivKey, txBuilder *client.TxBuilder, + mode typestx.BroadcastMode, + seqDelta uint64, mu *sync.Mutex, ) func() { (*txBuilder).SetGasLimit(2000000) (*txBuilder).SetFeeAmount([]sdk.Coin{ - sdk.NewCoin("ust", sdk.NewInt(1000)), + sdk.NewCoin("usei", sdk.NewInt(100000)), }) - SignTx(txBuilder, key) + SignTx(txBuilder, key, seqDelta) txBytes, _ := TEST_CONFIG.TxConfig.TxEncoder()((*txBuilder).GetTx()) return func() { grpcRes, err := TX_CLIENT.BroadcastTx( context.Background(), &typestx.BroadcastTxRequest{ - Mode: typestx.BroadcastMode_BROADCAST_MODE_SYNC, + Mode: mode, TxBytes: txBytes, }, ) @@ -52,7 +54,7 @@ func SendTx( grpcRes, err = TX_CLIENT.BroadcastTx( context.Background(), &typestx.BroadcastTxRequest{ - Mode: typestx.BroadcastMode_BROADCAST_MODE_SYNC, + Mode: mode, TxBytes: txBytes, }, ) diff --git a/scripts/initialize_local_test_node.sh b/scripts/initialize_local_test_node.sh index 637d47e1dc..8e6f25da0e 100644 --- a/scripts/initialize_local_test_node.sh +++ b/scripts/initialize_local_test_node.sh @@ -26,20 +26,20 @@ docker run -d --name jaeger \ jaegertracing/all-in-one:1.33 echo "Building..." -go build -o build/seid ./cmd/seid/ +make install echo $password | sudo -S rm -r ~/.sei/ echo $password | sudo -S rm -r ~/test_accounts/ -./build/seid unsafe-reset-all -./build/seid init demo --chain-id sei-chain -yes | ./build/seid keys add $keyname -yes | ./build/seid keys add faucet -./build/seid add-genesis-account $(./build/seid keys show $keyname -a) 100000000000000000000usei -./build/seid add-genesis-account $(./build/seid keys show faucet -a) 100000000000000000000usei +~/go/bin/seid unsafe-reset-all +~/go/bin/seid init demo --chain-id sei-chain +yes | ~/go/bin/seid keys add $keyname +yes | ~/go/bin/seid keys add faucet +~/go/bin/seid add-genesis-account $(~/go/bin/seid keys show $keyname -a) 100000000000000000000usei +~/go/bin/seid add-genesis-account $(~/go/bin/seid keys show faucet -a) 100000000000000000000usei python ./loadtest/scripts/populate_genesis_accounts.py $numtestaccount loc -./build/seid gentx $keyname 70000000000000000000usei --chain-id sei-chain -./build/seid collect-gentxs +~/go/bin/seid gentx $keyname 70000000000000000000usei --chain-id sei-chain +~/go/bin/seid collect-gentxs cat ~/.sei/config/genesis.json | jq '.app_state["crisis"]["constant_fee"]["denom"]="usei"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json cat ~/.sei/config/genesis.json | jq '.app_state["gov"]["deposit_params"]["min_deposit"][0]["denom"]="usei"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json cat ~/.sei/config/genesis.json | jq '.app_state["mint"]["params"]["mint_denom"]="usei"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json cat ~/.sei/config/genesis.json | jq '.app_state["staking"]["params"]["bond_denom"]="usei"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json -./build/seid start --trace +~/go/bin/seid start --trace diff --git a/x/dex/keeper/end_block_place_orders.go b/x/dex/keeper/end_block_place_orders.go index 17f8128b9e..8b25ec90ea 100644 --- a/x/dex/keeper/end_block_place_orders.go +++ b/x/dex/keeper/end_block_place_orders.go @@ -12,19 +12,29 @@ import ( otrace "go.opentelemetry.io/otel/trace" ) +const MAX_ORDERS_PER_SUDO_CALL = 50000 + func (k *Keeper) HandleEBPlaceOrders(ctx context.Context, sdkCtx sdk.Context, tracer *otrace.Tracer, contractAddr string, registeredPairs []types.Pair) { _, span := (*tracer).Start(ctx, "SudoPlaceOrders") span.SetAttributes(attribute.String("contractAddr", contractAddr)) - msg := k.getPlaceSudoMsg(contractAddr, registeredPairs) - data := k.CallContractSudo(sdkCtx, contractAddr, msg) - response := types.SudoOrderPlacementResponse{} - json.Unmarshal(data, &response) - sdkCtx.Logger().Info(fmt.Sprintf("Sudo response data: %s", response)) + msgs := k.getPlaceSudoMsg(contractAddr, registeredPairs) + k.CallContractSudo(sdkCtx, contractAddr, msgs[0]) // deposit + + responses := []types.SudoOrderPlacementResponse{} + for _, msg := range msgs[1:] { + data := k.CallContractSudo(sdkCtx, contractAddr, msg) + response := types.SudoOrderPlacementResponse{} + json.Unmarshal(data, &response) + sdkCtx.Logger().Info(fmt.Sprintf("Sudo response data: %s", response)) + responses = append(responses, response) + } for _, pair := range registeredPairs { pairStr := pair.String() if orderPlacements, ok := k.OrderPlacements[contractAddr][pairStr]; ok { - orderPlacements.FilterOutIds(response.UnsuccessfulOrderIds) + for _, response := range responses { + orderPlacements.FilterOutIds(response.UnsuccessfulOrderIds) + } for _, orderPlacement := range orderPlacements.Orders { switch orderPlacement.OrderType { case types.OrderType_LIMIT: @@ -52,25 +62,43 @@ func (k *Keeper) HandleEBPlaceOrders(ctx context.Context, sdkCtx sdk.Context, tr span.End() } -func (k *Keeper) getPlaceSudoMsg(contractAddr string, registeredPairs []types.Pair) types.SudoOrderPlacementMsg { +func (k *Keeper) getPlaceSudoMsg(contractAddr string, registeredPairs []types.Pair) []types.SudoOrderPlacementMsg { + contractDepositInfo := []types.ContractDepositInfo{} + for _, depositInfo := range k.DepositInfo[contractAddr].DepositInfoList { + contractDepositInfo = append(contractDepositInfo, dexcache.ToContractDepositInfo(depositInfo)) + } contractOrderPlacements := []types.ContractOrderPlacement{} + msgs := []types.SudoOrderPlacementMsg{ + { + OrderPlacements: types.OrderPlacementMsgDetails{ + Orders: []types.ContractOrderPlacement{}, + Deposits: contractDepositInfo, + }, + }, + } for _, pair := range registeredPairs { if orderPlacements, ok := k.OrderPlacements[contractAddr][pair.String()]; ok { for _, orderPlacement := range orderPlacements.Orders { if !orderPlacement.Liquidation { contractOrderPlacements = append(contractOrderPlacements, dexcache.ToContractOrderPlacement(orderPlacement)) + if len(contractOrderPlacements) == MAX_ORDERS_PER_SUDO_CALL { + msgs = append(msgs, types.SudoOrderPlacementMsg{ + OrderPlacements: types.OrderPlacementMsgDetails{ + Orders: contractOrderPlacements, + Deposits: []types.ContractDepositInfo{}, + }, + }) + contractOrderPlacements = []types.ContractOrderPlacement{} + } } } } } - contractDepositInfo := []types.ContractDepositInfo{} - for _, depositInfo := range k.DepositInfo[contractAddr].DepositInfoList { - contractDepositInfo = append(contractDepositInfo, dexcache.ToContractDepositInfo(depositInfo)) - } - return types.SudoOrderPlacementMsg{ + msgs = append(msgs, types.SudoOrderPlacementMsg{ OrderPlacements: types.OrderPlacementMsgDetails{ Orders: contractOrderPlacements, - Deposits: contractDepositInfo, + Deposits: []types.ContractDepositInfo{}, }, - } + }) + return msgs } From 8c57d6a2aa222865f7f1d638fd4e751a3b2dfb28 Mon Sep 17 00:00:00 2001 From: Xiaoyu Chen Date: Sat, 11 Jun 2022 16:15:03 -0700 Subject: [PATCH 2/2] tests --- x/dex/keeper/end_block_place_orders.go | 4 +-- x/dex/keeper/end_block_place_orders_test.go | 35 +++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 x/dex/keeper/end_block_place_orders_test.go diff --git a/x/dex/keeper/end_block_place_orders.go b/x/dex/keeper/end_block_place_orders.go index 8b25ec90ea..4785fea6e1 100644 --- a/x/dex/keeper/end_block_place_orders.go +++ b/x/dex/keeper/end_block_place_orders.go @@ -18,7 +18,7 @@ func (k *Keeper) HandleEBPlaceOrders(ctx context.Context, sdkCtx sdk.Context, tr _, span := (*tracer).Start(ctx, "SudoPlaceOrders") span.SetAttributes(attribute.String("contractAddr", contractAddr)) - msgs := k.getPlaceSudoMsg(contractAddr, registeredPairs) + msgs := k.GetPlaceSudoMsg(contractAddr, registeredPairs) k.CallContractSudo(sdkCtx, contractAddr, msgs[0]) // deposit responses := []types.SudoOrderPlacementResponse{} @@ -62,7 +62,7 @@ func (k *Keeper) HandleEBPlaceOrders(ctx context.Context, sdkCtx sdk.Context, tr span.End() } -func (k *Keeper) getPlaceSudoMsg(contractAddr string, registeredPairs []types.Pair) []types.SudoOrderPlacementMsg { +func (k *Keeper) GetPlaceSudoMsg(contractAddr string, registeredPairs []types.Pair) []types.SudoOrderPlacementMsg { contractDepositInfo := []types.ContractDepositInfo{} for _, depositInfo := range k.DepositInfo[contractAddr].DepositInfoList { contractDepositInfo = append(contractDepositInfo, dexcache.ToContractDepositInfo(depositInfo)) diff --git a/x/dex/keeper/end_block_place_orders_test.go b/x/dex/keeper/end_block_place_orders_test.go new file mode 100644 index 0000000000..16036f9e80 --- /dev/null +++ b/x/dex/keeper/end_block_place_orders_test.go @@ -0,0 +1,35 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" + dex "github.com/sei-protocol/sei-chain/x/dex/cache" + "github.com/sei-protocol/sei-chain/x/dex/types" + "github.com/stretchr/testify/require" +) + +func TestGetPlaceSudoMsg(t *testing.T) { + pair := types.Pair{PriceDenom: TEST_PRICE_DENOM, AssetDenom: TEST_ASSET_DENOM} + keeper, _ := keepertest.DexKeeper(t) + keeper.DepositInfo[TEST_CONTRACT] = dex.NewDepositInfo() + keeper.OrderPlacements[TEST_CONTRACT] = map[string]*dex.OrderPlacements{} + keeper.OrderPlacements[TEST_CONTRACT][pair.String()] = dex.NewOrderPlacements() + keeper.OrderPlacements[TEST_CONTRACT][pair.String()].Orders = append( + keeper.OrderPlacements[TEST_CONTRACT][pair.String()].Orders, + dex.OrderPlacement{ + Id: 1, + Price: sdk.OneDec(), + Quantity: sdk.OneDec(), + PriceDenom: TEST_PRICE_DENOM, + AssetDenom: TEST_ASSET_DENOM, + OrderType: types.OrderType_LIMIT, + Direction: types.PositionDirection_LONG, + Effect: types.PositionEffect_OPEN, + Leverage: sdk.OneDec(), + }, + ) + msgs := keeper.GetPlaceSudoMsg(TEST_CONTRACT, []types.Pair{pair}) + require.Equal(t, 2, len(msgs)) +}