Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 112 additions & 57 deletions loadtest/main.go
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -37,6 +40,8 @@ var (

const BATCH_SIZE = 100

var FROM_MILI = sdk.NewDec(1000000)

func init() {
cdc := codec.NewLegacyAmino()
interfaceRegistry := types.NewInterfaceRegistry()
Expand All @@ -57,7 +62,7 @@ func init() {
func run(
contractAddress string,
numberOfAccounts uint64,
numberOfOrders uint64,
numberOfBlocks uint64,
longPriceFloor uint64,
longPriceCeiling uint64,
shortPriceFloor uint64,
Expand All @@ -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)
Expand All @@ -160,7 +215,7 @@ func main() {
run(
contractAddress,
numberOfAccounts,
numberOfOrders,
numberOfBlocks,
longPriceFloor,
longPriceCeiling,
shortPriceFloor,
Expand Down
3 changes: 2 additions & 1 deletion loadtest/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down
10 changes: 6 additions & 4 deletions loadtest/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
)
Expand All @@ -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,
},
)
Expand Down
20 changes: 10 additions & 10 deletions scripts/initialize_local_test_node.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
56 changes: 42 additions & 14 deletions x/dex/keeper/end_block_place_orders.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here if the number of contractOrderPlacements doesn't reach 50000 here, is the contractOrderPlacements discarded then?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh good catch

Copy link
Contributor

@LCyson LCyson Jun 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add a unit test for this one^

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
}
Loading