Skip to content

Commit

Permalink
add contract Chain interface methods. implement for wasm. stub out wa…
Browse files Browse the repository at this point in the history
…sm tests
  • Loading branch information
agouin committed Apr 5, 2022
1 parent 417d827 commit da3f9c2
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 31 deletions.
8 changes: 4 additions & 4 deletions cmd/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ e.g.
ibc-test-framework test
# Specify specific chains/versions, relayer implementation, and test cases
ibc-test-framework test --source osmosis:v7.0.4 --destination juno:v2.3.0 --relayer rly RelayPacketTest,RelayPacketTestHeightTimeout
ibc-test-framework test --src osmosis:v7.0.4 --dst juno:v2.3.0 --relayer rly RelayPacketTest,RelayPacketTestHeightTimeout
# Shorthand flags
ibc-test-framework test -src osmosis:v7.0.4 -dst juno:v2.3.0 -r rly RelayPacketTest
ibc-test-framework test -s osmosis:v7.0.4 -d juno:v2.3.0 -r rly RelayPacketTest
`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("IBC Test Framework")
Expand Down Expand Up @@ -101,7 +101,7 @@ ibc-test-framework test -src osmosis:v7.0.4 -dst juno:v2.3.0 -r rly RelayPacketT
var eg errgroup.Group
for i, testCase := range testCases {
testCase := testCase
testName := fmt.Sprintf("RelayTest%d", i)
testName := fmt.Sprintf("Test%d", i)
eg.Go(func() error {
return runTestCase(testName, testCase, relayerImplementation, srcChainName, srcChainVersion, srcChainID, srcVals, dstChainName, dstChainVersion, dstChainID, dstVals)
})
Expand All @@ -111,7 +111,7 @@ ibc-test-framework test -src osmosis:v7.0.4 -dst juno:v2.3.0 -r rly RelayPacketT
}
} else {
for i, testCase := range testCases {
testName := fmt.Sprintf("RelayTest%d", i)
testName := fmt.Sprintf("Test%d", i)
if err := runTestCase(testName, testCase, relayerImplementation, srcChainName, srcChainVersion, srcChainID, srcVals, dstChainName, dstChainVersion, dstChainID, dstVals); err != nil {
panic(err)
}
Expand Down
12 changes: 12 additions & 0 deletions ibc/Chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,22 @@ type Chain interface {
// fetches the bech32 address for a test key on the "user" node (either the first fullnode or the first validator if no fullnodes)
GetAddress(keyName string) ([]byte, error)

// send funds to wallet from user account
SendFunds(ctx context.Context, keyName string, amount WalletAmount) error

// sends an IBC transfer from a test key on the "user" node (either the first fullnode or the first validator if no fullnodes)
// returns tx hash
SendIBCTransfer(ctx context.Context, channelID, keyName string, amount WalletAmount, timeout *IBCTimeout) (string, error)

// takes file path to smart contract and initialization message. returns contract address
InstantiateContract(ctx context.Context, keyName string, amount WalletAmount, fileName, initMessage string) (string, error)

// executes a contract transaction with a message using it's address
ExecuteContract(ctx context.Context, keyName string, contractAddress string, message string) error

// create balancer pool
CreatePool(ctx context.Context, keyName string, contractAddress string, swapFee float64, exitFee float64, assets []WalletAmount) error

// waits for # of blocks to be produced
WaitForBlocks(number int64) error

Expand Down
20 changes: 20 additions & 0 deletions ibc/cosmos_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,31 @@ func (c *CosmosChain) GetAddress(keyName string) ([]byte, error) {
return keyInfo.GetAddress().Bytes(), nil
}

// Implements Chain interface
func (c *CosmosChain) SendFunds(ctx context.Context, keyName string, amount WalletAmount) error {
return c.getRelayerNode().SendFunds(ctx, keyName, amount)
}

// Implements Chain interface
func (c *CosmosChain) SendIBCTransfer(ctx context.Context, channelID, keyName string, amount WalletAmount, timeout *IBCTimeout) (string, error) {
return c.getRelayerNode().SendIBCTransfer(ctx, channelID, keyName, amount, timeout)
}

// Implements Chain interface
func (c *CosmosChain) InstantiateContract(ctx context.Context, keyName string, amount WalletAmount, fileName, initMessage string) (string, error) {
return c.getRelayerNode().InstantiateContract(ctx, keyName, amount, fileName, initMessage)
}

// Implements Chain interface
func (c *CosmosChain) ExecuteContract(ctx context.Context, keyName string, contractAddress string, message string) error {
return c.getRelayerNode().ExecuteContract(ctx, keyName, contractAddress, message)
}

// Implements Chain interface
func (c *CosmosChain) CreatePool(ctx context.Context, keyName string, contractAddress string, swapFee float64, exitFee float64, assets []WalletAmount) error {
return c.getRelayerNode().CreatePool(ctx, keyName, contractAddress, swapFee, exitFee, assets)
}

// Implements Chain interface
func (c *CosmosChain) WaitForBlocks(number int64) error {
return c.getRelayerNode().WaitForBlocks(number)
Expand Down
160 changes: 160 additions & 0 deletions ibc/test_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path"
"path/filepath"
"runtime"
"strings"
"time"
Expand Down Expand Up @@ -312,6 +314,164 @@ func (tn *ChainNode) SendIBCTransfer(ctx context.Context, channelID string, keyN
return output.TxHash, nil
}

func (tn *ChainNode) SendFunds(ctx context.Context, keyName string, amount WalletAmount) error {
command := []string{tn.Chain.Config().Bin, "tx", "bank", "send", keyName,
amount.Address, fmt.Sprintf("%d%s", amount.Amount, amount.Denom),
"--keyring-backend", keyring.BackendTest,
"--node", fmt.Sprintf("tcp://%s:26657", tn.Name()),
"--output", "json",
"-y",
"--home", tn.NodeHome(),
"--chain-id", tn.Chain.Config().ChainID,
}

return handleNodeJobError(tn.NodeJob(ctx, command))
}

func copy(src, dst string) (int64, error) {
sourceFileStat, err := os.Stat(src)
if err != nil {
return 0, err
}

if !sourceFileStat.Mode().IsRegular() {
return 0, fmt.Errorf("%s is not a regular file", src)
}

source, err := os.Open(src)
if err != nil {
return 0, err
}
defer source.Close()

destination, err := os.Create(dst)
if err != nil {
return 0, err
}
defer destination.Close()
nBytes, err := io.Copy(destination, source)
return nBytes, err
}

type InstantiateContractAttribute struct {
Value string `json:"value"`
}

type InstantiateContractEvent struct {
Attributes []InstantiateContractAttribute `json:"attributes"`
}

type InstantiateContractLog struct {
Events []InstantiateContractEvent `json:"event"`
}

type InstantiateContractResponse struct {
Logs []InstantiateContractLog `json:"log"`
}

type QueryContractResponse struct {
Contracts []string `json:"contracts"`
}

func (tn *ChainNode) InstantiateContract(ctx context.Context, keyName string, amount WalletAmount, fileName, initMessage string) (string, error) {
_, file := filepath.Split(fileName)
newFilePath := path.Join(tn.Dir(), file)
newFilePathContainer := path.Join(tn.NodeHome(), file)
if _, err := copy(fileName, newFilePath); err != nil {
return "", err
}
command := []string{tn.Chain.Config().Bin, "tx", "wasm", "store", newFilePathContainer,
"--from", keyName,
"--amount", fmt.Sprintf("%d%s", amount.Amount, amount.Denom),
"--keyring-backend", keyring.BackendTest,
"--node", fmt.Sprintf("tcp://%s:26657", tn.Name()),
"--output", "json",
"-y",
"--home", tn.NodeHome(),
"--chain-id", tn.Chain.Config().ChainID,
}

exitCode, stdout, stderr, err := tn.NodeJob(ctx, command)
if err != nil {
return "", handleNodeJobError(exitCode, stdout, stderr, err)
}

res := InstantiateContractResponse{}
if err := json.Unmarshal([]byte(stdout), &res); err != nil {
return "", err
}
attributes := res.Logs[0].Events[0].Attributes
codeID := attributes[len(attributes)-1].Value

command = []string{tn.Chain.Config().Bin,
"tx", "wasm", "instantiate", codeID, initMessage,
"--from", keyName,
"--keyring-backend", keyring.BackendTest,
"--node", fmt.Sprintf("tcp://%s:26657", tn.Name()),
"--output", "json",
"-y",
"--home", tn.NodeHome(),
"--chain-id", tn.Chain.Config().ChainID,
}

exitCode, stdout, stderr, err = tn.NodeJob(ctx, command)
if err != nil {
return "", handleNodeJobError(exitCode, stdout, stderr, err)
}

command = []string{tn.Chain.Config().Bin,
"query", "wasm", "list-contract-by-code", codeID,
"--node", fmt.Sprintf("tcp://%s:26657", tn.Name()),
"--output", "json",
"--home", tn.NodeHome(),
"--chain-id", tn.Chain.Config().ChainID,
}

exitCode, stdout, stderr, err = tn.NodeJob(ctx, command)
if err != nil {
return "", handleNodeJobError(exitCode, stdout, stderr, err)
}

contactsRes := QueryContractResponse{}
if err := json.Unmarshal([]byte(stdout), &contactsRes); err != nil {
return "", err
}

contractAddress := contactsRes.Contracts[len(contactsRes.Contracts)-1]
return contractAddress, nil
}

func (tn *ChainNode) ExecuteContract(ctx context.Context, keyName string, contractAddress string, message string) error {
command := []string{tn.Chain.Config().Bin,
"tx", "wasm", "execute", contractAddress, message,
"--from", keyName,
"--keyring-backend", keyring.BackendTest,
"--node", fmt.Sprintf("tcp://%s:26657", tn.Name()),
"--output", "json",
"-y",
"--home", tn.NodeHome(),
"--chain-id", tn.Chain.Config().ChainID,
}
return handleNodeJobError(tn.NodeJob(ctx, command))
}

func (tn *ChainNode) CreatePool(ctx context.Context, keyName string, contractAddress string, swapFee float64, exitFee float64, assets []WalletAmount) error {
// TODO generate --pool-file
poolFilePath := "TODO"
command := []string{tn.Chain.Config().Bin,
"tx", "gamm", "create-pool",
"--pool-file", poolFilePath,
"--from", keyName,
"--keyring-backend", keyring.BackendTest,
"--node", fmt.Sprintf("tcp://%s:26657", tn.Name()),
"--output", "json",
"-y",
"--home", tn.NodeHome(),
"--chain-id", tn.Chain.Config().ChainID,
}
return handleNodeJobError(tn.NodeJob(ctx, command))
}

func (tn *ChainNode) CreateNodeContainer() error {
chainCfg := tn.Chain.Config()
cmd := []string{chainCfg.Bin, "start", "--home", tn.NodeHome()}
Expand Down
27 changes: 0 additions & 27 deletions ibc/test_relay.go
Original file line number Diff line number Diff line change
@@ -1,39 +1,12 @@
package ibc

import (
"errors"
"fmt"
"reflect"
"time"

transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types"
)

// all methods on this struct have the same signature and are method names that will be called by the CLI
type IBCTestCase struct{}

// uses reflection to get test case
func GetTestCase(testCase string) (func(testName string, srcChain Chain, dstChain Chain, relayerImplementation RelayerImplementation) error, error) {
v := reflect.ValueOf(IBCTestCase{})
m := v.MethodByName(testCase)
if m.Kind() != reflect.Func {
return nil, fmt.Errorf("invalid test case: %s", testCase)
}

testCaseFunc := func(testName string, srcChain Chain, dstChain Chain, relayerImplementation RelayerImplementation) error {
args := []reflect.Value{reflect.ValueOf(testName), reflect.ValueOf(srcChain), reflect.ValueOf(dstChain), reflect.ValueOf(relayerImplementation)}
result := m.Call(args)
if len(result) != 1 || !result[0].CanInterface() {
return errors.New("error reflecting error return var")
}

err, _ := result[0].Interface().(error)
return err
}

return testCaseFunc, nil
}

func (ibc IBCTestCase) RelayPacketTest(testName string, srcChain Chain, dstChain Chain, relayerImplementation RelayerImplementation) error {
ctx, home, pool, network, cleanup, err := SetupTestRun(testName)
if err != nil {
Expand Down
28 changes: 28 additions & 0 deletions ibc/test_setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import (
"bytes"
"context"
"crypto/rand"
"errors"
"fmt"
"io/ioutil"
"math/big"
"net"
"os"
"reflect"
"strings"
"time"

Expand All @@ -32,6 +34,32 @@ const (
testPathName = "test-path"
)

// all methods on this struct have the same signature and are method names that will be called by the CLI
// func (ibc IBCTestCase) TestCaseName(testName string, srcChain Chain, dstChain Chain, relayerImplementation RelayerImplementation) error
type IBCTestCase struct{}

// uses reflection to get test case
func GetTestCase(testCase string) (func(testName string, srcChain Chain, dstChain Chain, relayerImplementation RelayerImplementation) error, error) {
v := reflect.ValueOf(IBCTestCase{})
m := v.MethodByName(testCase)
if m.Kind() != reflect.Func {
return nil, fmt.Errorf("invalid test case: %s", testCase)
}

testCaseFunc := func(testName string, srcChain Chain, dstChain Chain, relayerImplementation RelayerImplementation) error {
args := []reflect.Value{reflect.ValueOf(testName), reflect.ValueOf(srcChain), reflect.ValueOf(dstChain), reflect.ValueOf(relayerImplementation)}
result := m.Call(args)
if len(result) != 1 || !result[0].CanInterface() {
return errors.New("error reflecting error return var")
}

err, _ := result[0].Interface().(error)
return err
}

return testCaseFunc, nil
}

// RandLowerCaseLetterString returns a lowercase letter string of given length
func RandLowerCaseLetterString(length int) string {
chars := []rune("abcdefghijklmnopqrstuvwxyz")
Expand Down
9 changes: 9 additions & 0 deletions ibc/test_wasm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package ibc

func (ibc IBCTestCase) CW20IBCTest(testName string, srcChain Chain, dstChain Chain, relayerImplementation RelayerImplementation) error {

}

func (ibc IBCTestCase) IBCReflectTest(testName string, srcChain Chain, dstChain Chain, relayerImplementation RelayerImplementation) error {

}

0 comments on commit da3f9c2

Please sign in to comment.