Skip to content

Commit

Permalink
Merge pull request #66 from informalsystems/mergify/bp/v0.37.x/pr-60
Browse files Browse the repository at this point in the history
Add abci_info implementation (backport #60)
  • Loading branch information
p-offtermatt authored Oct 4, 2023
2 parents 9335b64 + 7e94d0b commit be168e6
Show file tree
Hide file tree
Showing 12 changed files with 252 additions and 44 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Automated Tests
on:
push:
branches:
- main
- v0.37.x
- v0.34.x
pull_request:
branches:
- main
- v0.37.x
- v0.34.x
jobs:
Automated_Tests:
runs-on: ubuntu-latest
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v4
- name: Make test
run: make test-docker
26 changes: 26 additions & 0 deletions Dockerfile-test
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# import simd from ibc-go
FROM ghcr.io/cosmos/simapp:v0.47 AS simapp-builder

FROM golang:1.20-alpine as cometmock-builder

ENV PACKAGES curl make git libc-dev bash gcc linux-headers
RUN apk add --no-cache $PACKAGES

ENV CGO_ENABLED=0
ENV GOOS=linux
ENV GOFLAGS="-buildvcs=false"

# cache gomodules for cometmock
ADD ./go.mod /go.mod
ADD ./go.sum /go.sum
RUN go mod download

# Add CometMock and install it
ADD . /CometMock
WORKDIR /CometMock
RUN go build -o /usr/local/bin/cometmock ./cometmock

RUN apk update
RUN apk add --no-cache which iputils procps-ng tmux net-tools htop jq gcompat

COPY --from=simapp-builder /usr/bin/simd /usr/local/bin/simd
13 changes: 12 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
install:
go install ./cometmock
go install ./cometmock

test-locally:
go test -timeout 600s ./e2e-tests -test.v

test-docker:
# Build the Docker image
docker build -f Dockerfile-test -t cometmock-test .

# Start a container and execute the test command inside
docker rm cometmock-test-instance || true
docker run --name cometmock-test-instance --workdir /CometMock cometmock-test go test -timeout 600s ./e2e-tests -test.v
25 changes: 25 additions & 0 deletions cometmock/abci_client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,31 @@ func (a *AbciClient) callClientWithTimeout(client AbciCounterpartyClient, f func
}
}

func (a *AbciClient) SendAbciInfo() (*abcitypes.ResponseInfo, error) {
if verbose {
a.Logger.Info("Sending Info to clients")
}
// send Info to all clients and collect the responses
f := func(client AbciCounterpartyClient) (interface{}, error) {
return client.Client.InfoSync(abcitypes.RequestInfo{})
}
responses, err := a.callClientsWithTimeout(f, 500*time.Millisecond)
if err != nil {
return nil, err
}

if a.ErrorOnUnequalResponses {
// return an error if the responses are not all equal
for i := 1; i < len(responses); i++ {
if !reflect.DeepEqual(responses[i], responses[0]) {
return nil, fmt.Errorf("responses are not all equal: %v is not equal to %v", responses[i], responses[0])
}
}
}

return responses[0].(*abcitypes.ResponseInfo), nil
}

func (a *AbciClient) SendBeginBlock(block *types.Block) (*abcitypes.ResponseBeginBlock, error) {
if verbose {
a.Logger.Info("Sending BeginBlock to clients")
Expand Down
9 changes: 9 additions & 0 deletions cometmock/rpc_server/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ var Routes = map[string]*rpc.RPCFunc{

// abci API
"abci_query": rpc.NewRPCFunc(ABCIQuery, "path,data,height,prove"),
"abci_info": rpc.NewRPCFunc(ABCIInfo, ""),

// cometmock specific API
"advance_blocks": rpc.NewRPCFunc(AdvanceBlocks, "num_blocks"),
Expand Down Expand Up @@ -501,6 +502,14 @@ func BroadcastTx(tx *types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
}, nil
}

func ABCIInfo(ctx *rpctypes.Context) (*ctypes.ResultABCIInfo, error) {
abci_client.GlobalClient.Logger.Info(
"ABCIInfo called")

response, err := abci_client.GlobalClient.SendAbciInfo()
return &ctypes.ResultABCIInfo{Response: *response}, err
}

func ABCIQuery(
ctx *rpctypes.Context,
path string,
Expand Down
File renamed without changes.
6 changes: 3 additions & 3 deletions local-testnet-debug.sh → e2e-tests/local-testnet-debug.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ PROVIDER_COMETMOCK_ADDR=tcp://$NODE_IP:22331
CONSUMER_COMETMOCK_ADDR=tcp://$NODE_IP:22332

# Clean start
pkill -f interchain-security-pd &> /dev/null || true
pkill -f cometmock &> /dev/null || true
pkill -f ^interchain-security-pd &> /dev/null || true
pkill -f ^cometmock &> /dev/null || true
sleep 1
rm -rf ${PROV_NODES_ROOT_DIR}
rm -rf ${CONS_NODES_ROOT_DIR}
Expand Down Expand Up @@ -255,7 +255,7 @@ done
# # ## CONSUMER CHAIN ##

# # Clean start
pkill -f interchain-security-cd &> /dev/null || true
pkill -f ^interchain-security-cd &> /dev/null || true
sleep 1
rm -rf ${CONS_NODES_ROOT_DIR}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ PROVIDER_COMETMOCK_ADDR=tcp://$NODE_IP:22331
CONSUMER_COMETMOCK_ADDR=tcp://$NODE_IP:22332

# Clean start
pkill -f $BINARY_NAME &> /dev/null || true
pkill -f cometmock &> /dev/null || true
pkill -f ^$BINARY_NAME &> /dev/null || true
pkill -f ^cometmock &> /dev/null || true
sleep 1
rm -rf ${PROV_NODES_ROOT_DIR}
rm -rf ${CONS_NODES_ROOT_DIR}
Expand Down Expand Up @@ -202,7 +202,7 @@ done
PROVIDER_NODE_LISTEN_ADDR_STR=${PROVIDER_NODE_LISTEN_ADDR_STR::${#PROVIDER_NODE_LISTEN_ADDR_STR}-1}
PROV_NODES_HOME_STR=${PROV_NODES_HOME_STR::${#PROV_NODES_HOME_STR}-1}

echo "Testnet applications are set up! Run the following command to start CometMock:"
cometmock $PROVIDER_NODE_LISTEN_ADDR_STR ${LEAD_VALIDATOR_PROV_DIR}/config/genesis.json $PROVIDER_COMETMOCK_ADDR $PROV_NODES_HOME_STR grpc
echo "Testnet applications are set up! Starting CometMock..."
cometmock $PROVIDER_NODE_LISTEN_ADDR_STR ${LEAD_VALIDATOR_PROV_DIR}/config/genesis.json $PROVIDER_COMETMOCK_ADDR $PROV_NODES_HOME_STR grpc &> ${LEAD_VALIDATOR_PROV_DIR}/cometmock_log &

sleep 5
43 changes: 39 additions & 4 deletions local-testnet.sh → e2e-tests/local-testnet.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ PROVIDER_COMETMOCK_ADDR=tcp://$NODE_IP:22331
CONSUMER_COMETMOCK_ADDR=tcp://$NODE_IP:22332

# Clean start
pkill -f interchain-security-pd &> /dev/null || true
pkill -f cometmock &> /dev/null || true
pkill -f ^interchain-security-pd &> /dev/null || true
pkill -f ^cometmock &> /dev/null || true
sleep 1
rm -rf ${PROV_NODES_ROOT_DIR}
rm -rf ${CONS_NODES_ROOT_DIR}
Expand Down Expand Up @@ -68,7 +68,6 @@ do
${PROV_NODE_DIR}/config/genesis.json > \
${PROV_NODE_DIR}/edited_genesis.json && mv ${PROV_NODE_DIR}/edited_genesis.json ${PROV_NODE_DIR}/config/genesis.json


sleep 1

# Create account keypair
Expand Down Expand Up @@ -252,7 +251,7 @@ done
# # ## CONSUMER CHAIN ##

# # Clean start
pkill -f interchain-security-cd &> /dev/null || true
pkill -f ^interchain-security-cd &> /dev/null || true
sleep 1
rm -rf ${CONS_NODES_ROOT_DIR}

Expand Down Expand Up @@ -407,6 +406,42 @@ rm -r ~/.relayer
# initialize gorelayer
rly config init

# add chain configs

echo "{
\"type\": \"cosmos\",
\"value\": {
\"key\": \"default\",
\"chain-id\": \"provider\",
\"rpc-addr\": \"${PROVIDER_COMETMOCK_ADDR}\",
\"account-prefix\": \"cosmos\",
\"keyring-backend\": \"test\",
\"gas-adjustment\": 1.2,
\"gas-prices\": \"0.01stake\",
\"debug\": true,
\"timeout\": \"20s\",
\"output-format\": \"json\",
\"sign-mode\": \"direct\"
}
}" > go_rly_provider.json

echo "{
\"type\": \"cosmos\",
\"value\": {
\"key\": \"default\",
\"chain-id\": \"consumer\",
\"rpc-addr\": \"${CONSUMER_COMETMOCK_ADDR}\",
\"account-prefix\": \"cosmos\",
\"keyring-backend\": \"test\",
\"gas-adjustment\": 1.2,
\"gas-prices\": \"0.01stake\",
\"debug\": true,
\"timeout\": \"20s\",
\"output-format\": \"json\",
\"sign-mode\": \"direct\"
}
}" > go_rly_consumer.json

# add chains
rly chains add --file go_rly_provider.json provider
rly chains add --file go_rly_consumer.json consumer
Expand Down
114 changes: 114 additions & 0 deletions e2e-tests/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package main

import (
"bytes"
"encoding/json"
"fmt"
"os/exec"
"strconv"
"testing"
"time"
)

func runCommandWithOutput(cmd *exec.Cmd) (string, error) {
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr

err := cmd.Run()
if err != nil {
return "", fmt.Errorf("error running command: %v\nstdout: %s\nstderr: %s", err, stdout.String(), stderr.String())
}

return stdout.String(), nil
}

// From the output of the AbciInfo command, extract the latest block height.
// The json bytes should look e.g. like this:
// {"jsonrpc":"2.0","id":1,"result":{"response":{"data":"interchain-security-p","last_block_height":"2566","last_block_app_hash":"R4Q3Si7+t7TIidl2oTHcQRDNEz+lP0IDWhU5OI89psg="}}}
func extractHeightFromInfo(jsonBytes []byte) (int, error) {
// Use a generic map to represent the JSON structure
var data map[string]interface{}

if err := json.Unmarshal(jsonBytes, &data); err != nil {
return -1, fmt.Errorf("Failed to unmarshal JSON %s \n error was %v", string(jsonBytes), err)
}

// Navigate the map and use type assertions to get the last_block_height
result, ok := data["result"].(map[string]interface{})
if !ok {
return -1, fmt.Errorf("Failed to navigate abci_info output structure trying to access result: json was %s", string(jsonBytes))
}

response, ok := result["response"].(map[string]interface{})
if !ok {
return -1, fmt.Errorf("Failed to navigate abci_info output structure trying to access response: json was %s", string(jsonBytes))
}

lastBlockHeight, ok := response["last_block_height"].(string)
if !ok {
return -1, fmt.Errorf("Failed to navigate abci_info output structure trying to access last_block_height: json was %s", string(jsonBytes))
}

return strconv.Atoi(lastBlockHeight)
}

// Tests happy path functionality for Abci Info.
func TestAbciInfo(t *testing.T) {
// execute the local-testnet-singlechain.sh script
t.Log("Running local-testnet-singlechain.sh")
cmd := exec.Command("./local-testnet-singlechain.sh", "simd")
_, err := runCommandWithOutput(cmd)
if err != nil {
t.Fatalf("Error running local-testnet-singlechain.sh: %v", err)
}

t.Log("Done starting testnet")

// wait until we are producing blocks
for {
out, err := exec.Command("bash", "-c", "simd q block --node tcp://127.0.0.1:22331 | jq -r '.block.header.height'").Output()
if err == nil {
t.Log("We are producing blocks: ", string(out))
break
}
t.Log("Waiting for blocks to be produced, latest output: ", string(out))
time.Sleep(1 * time.Second)
}

// call the abci_info command by calling curl on the REST endpoint
// curl -H 'Content-Type: application/json' -H 'Accept:application/json' --data '{"jsonrpc":"2.0","method":"abci_info","id":1}' 127.0.0.1:22331
args := []string{"bash", "-c", "curl -H 'Content-Type: application/json' -H 'Accept:application/json' --data '{\"jsonrpc\":\"2.0\",\"method\":\"abci_info\",\"id\":1}' 127.0.0.1:22331"}
cmd = exec.Command(args[0], args[1:]...)
out, err := runCommandWithOutput(cmd)
if err != nil {
t.Fatalf("Error running curl\ncommand: %v\noutput: %v\nerror: %v", cmd, string(out), err)
}

// extract the latest block height from the output
height, err := extractHeightFromInfo([]byte(out))
if err != nil {
t.Fatalf("Error extracting block height from abci_info output: %v", err)
}

// wait a bit to make sure the block height has increased
time.Sleep(2 * time.Second)

// call the abci_info command again
cmd2 := exec.Command(args[0], args[1:]...)
out2, err := runCommandWithOutput(cmd2)
if err != nil {
t.Fatalf("Error running curl\ncommand: %v\noutput: %v\nerror: %v", cmd2, string(out2), err)
}

// extract the latest block height from the output
height2, err := extractHeightFromInfo([]byte(out2))
if err != nil {
t.Fatalf("Error extracting block height from abci_info output: %v", err)
}

// check that the block height has increased
if height2 <= height {
t.Fatalf("Expected block height to increase, but it did not. First height was %v, second height was %v", height, height2)
}
}
16 changes: 0 additions & 16 deletions go_rly_consumer.json

This file was deleted.

16 changes: 0 additions & 16 deletions go_rly_provider.json

This file was deleted.

0 comments on commit be168e6

Please sign in to comment.