Skip to content

Commit

Permalink
feat: add integration test to the signing
Browse files Browse the repository at this point in the history
  • Loading branch information
boodyvo committed Aug 26, 2024
1 parent 338243b commit d25084f
Show file tree
Hide file tree
Showing 6 changed files with 251 additions and 3 deletions.
15 changes: 15 additions & 0 deletions .github/scripts/wait-for-node-init.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
get_block_number() {
local BLOCK_NUMBER=$(curl -sS -X POST \
--data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
-H "Content-Type: application/json" \
http://localhost:8545 | jq .result)
echo $BLOCK_NUMBER
}

BLOCK_NUMBER=$(get_block_number)

while [ "$BLOCK_NUMBER" == "" ]
do
BLOCK_NUMBER=$(get_block_number)
sleep 0.5
done
61 changes: 60 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,63 @@ jobs:
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
args: --timeout=10m
args: --timeout=10m

integration-tests:
runs-on: ubuntu-latest
steps:
- name: Checkout go-tools-kava
uses: actions/checkout@v4
with:
path: go-tools

# TODO(yevhenii): consider reusing already built kava docker image instead of rebuilding it
- name: Checkout kava
uses: actions/checkout@v4
with:
repository: Kava-Labs/kava
# There are 2 cases here:
# - workflow was triggered by repository_dispatch event which was sent by kava repo, in that case we're using
# kava version provided in event: github.event.client_payload.ref
# - workflow was triggered by commit in rosetta-kava repo, in that case github.event.client_payload.ref will be empty
# and default branch will be used instead
ref: ${{ github.event.client_payload.ref }}
path: kava
submodules: 'true'

- name: Print kava version
run: |
git branch
git rev-parse HEAD
working-directory: ./kava

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go-tools/go.mod

- name: Cache Go Modules
uses: actions/cache@v4
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('./rosetta-kava/**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Build kava docker image
run: make docker-build
working-directory: ./kava

- name: Install kvtool
run: make install
working-directory: ./kava/tests/e2e/kvtool

- name: Run kava docker container
run: KAVA_TAG=local kvtool t bootstrap

- name: Wait until kava node is ready to serve traffic
run: bash ${GITHUB_WORKSPACE}/go-tools/.github/scripts/wait-for-node-init.sh

- name: Run integration tests
run: KAVA_RPC_URL=http://localhost:26657 NETWORK=kava-local PORT=4000 SKIP_LIVE_NODE_TESTS=true make test-integration
working-directory: ./go-tools
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,7 @@ vet:
.PHONY: test
test:
go test -v ./...

.PHONY: test-integration
test-integration:
cd signing/testing && go test -v -tags=integration -count=1
2 changes: 1 addition & 1 deletion signing/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/cosmos/cosmos-sdk v0.47.10
github.com/kava-labs/kava v0.26.1
github.com/rs/zerolog v1.32.0
golang.org/x/sync v0.6.0
google.golang.org/grpc v1.63.2
)

Expand Down Expand Up @@ -193,7 +194,6 @@ require (
golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/oauth2 v0.17.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/term v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
Expand Down
2 changes: 1 addition & 1 deletion signing/testing/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func main() {
if err != nil {
panic(err)
}
msg := banktypes.NewMsgSend(accAddr, toAddr, sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1))))
msg := banktypes.NewMsgSend(accAddr, toAddr, sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(321))))

for i := 0; i < 1000; i++ {
requests <- signing.MsgRequest{
Expand Down
170 changes: 170 additions & 0 deletions signing/testing/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
//go:build integration

package main_test

import (
"context"
"fmt"
"github.com/stretchr/testify/require"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc/credentials/insecure"
"log"
"os"
"testing"
"time"

"github.com/kava-labs/go-tools/signing"

"github.com/cosmos/cosmos-sdk/client/grpc/tmservice"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"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"
"github.com/kava-labs/kava/app"
"github.com/rs/zerolog"
"google.golang.org/grpc"
)

const (
inflightLimit = 100
grpcUrl = "localhost:9090"
mnemonic = "season bone lucky dog depth pond royal decide unknown device fruit inch clock trap relief horse morning taxi bird session throw skull avocado private"
toAddress = "kava1mq9qxlhze029lm0frzw2xr6hem8c3k9ts54w0w"

testNumber = 1000
amountSend = 321
)

func TestSigningTransactions(t *testing.T) {
app.SetSDKConfig()
encodingConfig := app.MakeEncodingConfig()

conn, err := grpc.Dial(grpcUrl, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
t.Fatalf("failed to connect to grpc server: %s", err)
}
defer conn.Close()

tmClient := tmservice.NewServiceClient(conn)
nodeInfoResponse, err := tmClient.GetNodeInfo(context.Background(), &tmservice.GetNodeInfoRequest{})
if err != nil {
log.Fatal(err)
}

txClient := txtypes.NewServiceClient(conn)
authClient := authtypes.NewQueryClient(conn)

hdPath := hd.CreateHDPath(app.Bip44CoinType, 0, 0)
privKeyBytes, err := hd.Secp256k1.Derive()(mnemonic, "", hdPath.String())
if err != nil {
t.Fatalf("failed to derive private key: %s", err)
}

privKey := &secp256k1.PrivKey{Key: privKeyBytes}
accAddr := sdk.AccAddress(privKey.PubKey().Address())

logger := zerolog.New(os.Stderr)

signer := signing.NewSigner(
nodeInfoResponse.DefaultNodeInfo.Network,
signing.EncodingConfigAdapter{EncodingConfig: encodingConfig},
authClient,
txClient,
privKey,
inflightLimit,
logger,
)
requests := make(chan signing.MsgRequest)
responses, err := signer.Run(requests)
if err != nil {
t.Fatalf("failed to start signer: %s", err)
}

group := errgroup.Group{}

group.Go(func() error {
counter := 0

for {
select {
case response := <-responses:
counter++
if counter == testNumber {
log.Printf("received all responses")

return nil
}

if response.Err != nil {
t.Errorf("response error: %s", response.Err)

return response.Err
}

// if we cannot receive all responses in 10 seconds, we fail the test
case <-time.After(10 * time.Second):
t.Fatalf("timeout waiting for responses")
}
}
})

toAddr, err := sdk.AccAddressFromBech32(toAddress)
if err != nil {
t.Fatalf("failed to parse address: %s", err)
}

grpcClient := banktypes.NewQueryClient(conn)
addressBefore, err := getAddress(context.Background(), grpcClient, toAddress)
require.NoError(t, err)

log.Printf("address before: %v", addressBefore.Amount.Int64())

msg := banktypes.NewMsgSend(accAddr, toAddr, sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(amountSend))))

for i := 0; i < testNumber; i++ {
requests <- signing.MsgRequest{
Msgs: []sdk.Msg{msg},
GasLimit: 200000,
FeeAmount: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1000))),
}
}

log.Printf("all transactions sent")

if err := group.Wait(); err != nil {
t.Fatalf("failed to sign transactions: %s", err)
}

log.Printf("all transactions sent, waiting for block generation")

// we need to wait for a block to be generated after last transactions
time.Sleep(10 * time.Second)

address, err := getAddress(context.Background(), grpcClient, toAddress)
require.NoError(t, err)
log.Printf("address after: %v", address.Amount.Int64())
require.Equal(t, addressBefore.Amount.Int64()+int64(amountSend)*testNumber, address.Amount.Int64())

log.Printf("all transactions sent, waiting for block generation")
}

// getAddress gets the balance of the given address
func getAddress(
ctx context.Context,
//grpcClient *kavagrpc.KavaGrpcClient,
grpcClient banktypes.QueryClient,
address string,
) (*sdk.Coin, error) {
// Get the current pool state
res, err := grpcClient.Balance(ctx, &banktypes.QueryBalanceRequest{
Address: address,
Denom: "ukava",
})
if err != nil {
return nil, fmt.Errorf("query bank: %v", err)
}

return res.Balance, nil
}

0 comments on commit d25084f

Please sign in to comment.