Skip to content

Commit

Permalink
feat!: x/clock v2 - permissionless (#893)
Browse files Browse the repository at this point in the history
* Update Clock Proto

* Add Keeper Logic

* Update Msg Server, Querier, & Params

* Add Tx Cmds

* Ensure Sender is Admin

* Add Clock CLI Queries, Update Txs

* Update Clock Codec

* Fix Get All & Manager Check

* Update Genesis, Fix Genesis Export

* Jail Contract on Error

* Pass Clock Interchain Tests (Tests are Incomplete)

* Error Check on Jail Contract

* Test Msg Server

* Test Msg Server with Admin

* Test Querier

* Test Params

* Test Genesis

* Update Codec Tests

* Fix Msg Tests

* Refactor Stores into Singular Store

* Lint

* Update Tx CLI Desc, More Lint

* Update Clock SubCmd Descs

* Remove Contracts from Genesis

* Refactor Request Validation

* Use Logger in EndBlocker

* Init EndBlocker Tests

* Test Clock End Blocker

* Upload Clock Contract (No Sudo)

* Add Interchain Clock Helper

* Add Clock Interchain Tests

* Test Unregister Clock

* Update Spec Docs

* remove `SetupContractWithAdmin` and instead use extraFlags

* wait for 2 blocks in the Clock helpers (ictest thing)

* fix: updateParams contractGasLimit

* patch e2e no admin flag

* Extract Anon Func

---------

Co-authored-by: Reece Williams <[email protected]>
  • Loading branch information
joelsmith-2019 and Reecepbcups authored Dec 14, 2023
1 parent 68e08e7 commit 3dadeb5
Show file tree
Hide file tree
Showing 50 changed files with 4,852 additions and 523 deletions.
1 change: 1 addition & 0 deletions app/keepers/keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,7 @@ func NewAppKeepers(
appKeepers.ClockKeeper = clockkeeper.NewKeeper(
appKeepers.keys[clocktypes.StoreKey],
appCodec,
appKeepers.WasmKeeper,
appKeepers.ContractKeeper,
govModAddress,
)
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
120 changes: 120 additions & 0 deletions interchaintest/helpers/clock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package helpers

import (
"context"
"encoding/json"
"fmt"
"testing"

"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/strangelove-ventures/interchaintest/v7/chain/cosmos"
"github.com/strangelove-ventures/interchaintest/v7/ibc"
"github.com/strangelove-ventures/interchaintest/v7/testutil"
"github.com/stretchr/testify/require"
)

// Register the clock contract
func RegisterClockContract(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, user ibc.Wallet, contract string) {
cmd := []string{
"junod", "tx", "clock", "register", contract,
"--node", chain.GetRPCAddress(),
"--home", chain.HomeDir(),
"--chain-id", chain.Config().ChainID,
"--fees", "500ujuno",
"--from", user.KeyName(),
"--keyring-dir", chain.HomeDir(),
"--keyring-backend", keyring.BackendTest,
"-y",
}
stdout, _, err := chain.Exec(ctx, cmd, nil)
require.NoError(t, err)

debugOutput(t, string(stdout))

err = testutil.WaitForBlocks(ctx, 2, chain)
require.NoError(t, err)
}

// Unregister the clock contract
func UnregisterClockContract(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, user ibc.Wallet, contract string) {
cmd := []string{
"junod", "tx", "clock", "unregister", contract,
"--node", chain.GetRPCAddress(),
"--home", chain.HomeDir(),
"--chain-id", chain.Config().ChainID,
"--fees", "500ujuno",
"--from", user.KeyName(),
"--keyring-dir", chain.HomeDir(),
"--keyring-backend", keyring.BackendTest,
"-y",
}
stdout, _, err := chain.Exec(ctx, cmd, nil)
require.NoError(t, err)

debugOutput(t, string(stdout))

err = testutil.WaitForBlocks(ctx, 2, chain)
require.NoError(t, err)
}

// Unjail the clock contract
func UnjailClockContract(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, user ibc.Wallet, contract string) {
cmd := []string{
"junod", "tx", "clock", "unjail", contract,
"--node", chain.GetRPCAddress(),
"--home", chain.HomeDir(),
"--chain-id", chain.Config().ChainID,
"--fees", "500ujuno",
"--from", user.KeyName(),
"--keyring-dir", chain.HomeDir(),
"--keyring-backend", keyring.BackendTest,
"-y",
}
stdout, _, err := chain.Exec(ctx, cmd, nil)
require.NoError(t, err)

debugOutput(t, string(stdout))

err = testutil.WaitForBlocks(ctx, 2, chain)
require.NoError(t, err)
}

type ClockContract struct {
ClockContract struct {
ContractAddress string `json:"contract_address"`
IsJailed bool `json:"is_jailed"`
} `json:"clock_contract"`
}

// Get the clock contract
func GetClockContract(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, contract string) ClockContract {
var res ClockContract

cmd := getClockQueryCommand(chain, contract)
stdout, _, err := chain.Exec(ctx, cmd, nil)
require.NoError(t, err)

fmt.Println(string(stdout))

if err := json.Unmarshal(stdout, &res); err != nil {
t.Fatal(err)
}

return res
}

// Validate a contract is not registered with the clock module
func ValidateNoClockContract(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, contract string) {
cmd := getClockQueryCommand(chain, contract)
_, _, err := chain.Exec(ctx, cmd, nil)
require.Error(t, err)
}

// Get the clock query command
func getClockQueryCommand(chain *cosmos.CosmosChain, contract string) []string {
return []string{"junod", "query", "clock", "contract", contract,
"--node", chain.GetRPCAddress(),
"--chain-id", chain.Config().ChainID,
"--output", "json",
}
}
48 changes: 46 additions & 2 deletions interchaintest/helpers/cosmwasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,61 @@ func SmartQueryString(t *testing.T, ctx context.Context, chain *cosmos.CosmosCha
return err
}

func SetupContract(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, keyname string, fileLoc string, message string) (codeId, contract string) {
func StoreContract(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, keyname string, fileLoc string) (codeId string) {
codeId, err := chain.StoreContract(ctx, keyname, fileLoc)
if err != nil {
t.Fatal(err)
}
return codeId
}

func SetupContract(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, keyname string, fileLoc string, message string, extraFlags ...string) (codeId, contract string) {
codeId = StoreContract(t, ctx, chain, keyname, fileLoc)

needsNoAdminFlag := true
// if extraFlags contains "--admin", switch to false
for _, flag := range extraFlags {
if flag == "--admin" {
needsNoAdminFlag = false
}
}

contractAddr, err := chain.InstantiateContract(ctx, keyname, codeId, message, needsNoAdminFlag, extraFlags...)
if err != nil {
t.Fatal(err)
}

contractAddr, err := chain.InstantiateContract(ctx, keyname, codeId, message, true)
return codeId, contractAddr
}

func MigrateContract(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, keyname string, contractAddr string, fileLoc string, message string) (codeId, contract string) {
codeId, err := chain.StoreContract(ctx, keyname, fileLoc)
if err != nil {
t.Fatal(err)
}

// Execute migrate tx
cmd := []string{
"junod", "tx", "wasm", "migrate", contractAddr, codeId, message,
"--node", chain.GetRPCAddress(),
"--home", chain.HomeDir(),
"--chain-id", chain.Config().ChainID,
"--from", keyname,
"--gas", "500000",
"--keyring-dir", chain.HomeDir(),
"--keyring-backend", keyring.BackendTest,
"-y",
}

stdout, _, err := chain.Exec(ctx, cmd, nil)
require.NoError(t, err)

debugOutput(t, string(stdout))

if err := testutil.WaitForBlocks(ctx, 2, chain); err != nil {
t.Fatal(err)
}

return codeId, contractAddr
}

Expand Down
96 changes: 87 additions & 9 deletions interchaintest/module_clock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"github.com/strangelove-ventures/interchaintest/v7"
"github.com/strangelove-ventures/interchaintest/v7/chain/cosmos"
"github.com/strangelove-ventures/interchaintest/v7/ibc"
"github.com/strangelove-ventures/interchaintest/v7/testutil"
"github.com/stretchr/testify/require"

helpers "github.com/CosmosContracts/juno/tests/interchaintest/helpers"
Expand All @@ -33,40 +32,119 @@ func TestJunoClock(t *testing.T) {
users := interchaintest.GetAndFundTestUsers(t, ctx, "default", int64(10_000_000_000), juno, juno)
user := users[0]

// Upload & init contract payment to another address
//
// -- REGULAR GAS CONTRACT --
// Ensure logic works as expected for a contract that uses less than the gas limit
// and has a valid sudo message entry point.
//

// Setup contract
_, contractAddr := helpers.SetupContract(t, ctx, juno, user.KeyName(), "contracts/clock_example.wasm", `{}`)

// Ensure config is 0
res := helpers.GetClockContractValue(t, ctx, juno, contractAddr)
fmt.Printf("- res: %v\n", res.Data.Val)
require.Equal(t, uint32(0), res.Data.Val)

// Submit the proposal to add it to the allowed contracts list
SubmitParamChangeProp(t, ctx, juno, user, []string{contractAddr})
// Register the contract
helpers.RegisterClockContract(t, ctx, juno, user, contractAddr)

// Wait 1 block
_ = testutil.WaitForBlocks(ctx, 1, juno)
// Validate contract is not jailed
contract := helpers.GetClockContract(t, ctx, juno, contractAddr)
require.False(t, contract.ClockContract.IsJailed)

// Validate the contract is now auto incrementing from the end blocker
res = helpers.GetClockContractValue(t, ctx, juno, contractAddr)
fmt.Printf("- res: %v\n", res.Data.Val)
require.GreaterOrEqual(t, res.Data.Val, uint32(1))

// Unregister the contract & ensure it is removed from the store
helpers.UnregisterClockContract(t, ctx, juno, user, contractAddr)
helpers.ValidateNoClockContract(t, ctx, juno, contractAddr)

//
// -- HIGH GAS CONTRACT --
// Ensure contracts that exceed the gas limit are jailed.
//

// Setup contract
_, contractAddr = helpers.SetupContract(t, ctx, juno, user.KeyName(), "contracts/clock_example_high_gas.wasm", `{}`, "--admin", user.FormattedAddress())

// Ensure config is 0
res = helpers.GetClockContractValue(t, ctx, juno, contractAddr)
fmt.Printf("- res: %v\n", res.Data.Val)
require.Equal(t, uint32(0), res.Data.Val)

// Register the contract
helpers.RegisterClockContract(t, ctx, juno, user, contractAddr)

// Validate contract is jailed
contract = helpers.GetClockContract(t, ctx, juno, contractAddr)
require.True(t, contract.ClockContract.IsJailed)

//
// -- MIGRATE CONTRACT --
// Ensure migrations can patch contracts that error or exceed gas limit
// so they can be unjailed.
//

// Migrate the high gas contract to a contract with lower gas usage
helpers.MigrateContract(t, ctx, juno, user.KeyName(), contractAddr, "contracts/clock_example_migrate.wasm", `{}`)

// Unjail the contract
helpers.UnjailClockContract(t, ctx, juno, user, contractAddr)

// Validate contract is not jailed
contract = helpers.GetClockContract(t, ctx, juno, contractAddr)
require.False(t, contract.ClockContract.IsJailed)

// Validate the contract is now auto incrementing from the end blocker
res = helpers.GetClockContractValue(t, ctx, juno, contractAddr)
fmt.Printf("- res: %v\n", res.Data.Val)
require.GreaterOrEqual(t, res.Data.Val, uint32(1))

//
// -- NO SUDO CONTRACT --
// Ensure contracts that do not have a sudo message entry point are jailed.
//

// Setup contract
_, contractAddr = helpers.SetupContract(t, ctx, juno, user.KeyName(), "contracts/clock_example_no_sudo.wasm", `{}`)

// Ensure config is 0
res = helpers.GetClockContractValue(t, ctx, juno, contractAddr)
fmt.Printf("- res: %v\n", res.Data.Val)
require.Equal(t, uint32(0), res.Data.Val)

// Register the contract
helpers.RegisterClockContract(t, ctx, juno, user, contractAddr)

// Validate contract is jailed
contract = helpers.GetClockContract(t, ctx, juno, contractAddr)
require.True(t, contract.ClockContract.IsJailed)

// Validate contract is not auto incrementing
res = helpers.GetClockContractValue(t, ctx, juno, contractAddr)
fmt.Printf("- res: %v\n", res.Data.Val)
require.Equal(t, uint32(0), res.Data.Val)

t.Cleanup(func() {
_ = ic.Close()
})
}

func SubmitParamChangeProp(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, user ibc.Wallet, contracts []string) string {
func SubmitParamChangeProp(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, user ibc.Wallet, gasLimit uint64) string {
govAcc := "juno10d07y265gmmuvt4z0w9aw880jnsr700jvss730"
updateParams := []cosmosproto.Message{
&clocktypes.MsgUpdateParams{
Authority: govAcc,
Params: clocktypes.NewParams(contracts, 1_000_000_000),
Params: clocktypes.Params{
ContractGasLimit: gasLimit,
},
},
}

proposal, err := chain.BuildProposal(updateParams, "Params Add Contract", "params", "ipfs://CID", fmt.Sprintf(`500000000%s`, chain.Config().Denom))
proposal, err := chain.BuildProposal(updateParams, "Params Update Gas Limit", "params", "ipfs://CID", fmt.Sprintf(`500000000%s`, chain.Config().Denom))
require.NoError(t, err, "error building proposal")

txProp, err := chain.SubmitProposal(ctx, user.KeyName(), proposal)
Expand Down
13 changes: 13 additions & 0 deletions proto/juno/clock/v1/clock.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
syntax = "proto3";
package juno.clock.v1;

option go_package = "github.com/CosmosContracts/juno/x/clock/types";

// This object is used to store the contract address and the
// jail status of the contract.
message ClockContract {
// The address of the contract.
string contract_address = 1;
// The jail status of the contract.
bool is_jailed = 2;
}
10 changes: 3 additions & 7 deletions proto/juno/clock/v1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package juno.clock.v1;

import "gogoproto/gogo.proto";
import "cosmos/base/v1beta1/coin.proto";
import "juno/clock/v1/clock.proto";

option go_package = "github.com/CosmosContracts/juno/x/clock/types";

Expand All @@ -17,13 +18,8 @@ message GenesisState {

// Params defines the set of module parameters.
message Params {
// contract_addresses stores the list of executable contracts to be ticked on every block.
repeated string contract_addresses = 1 [
(gogoproto.jsontag) = "contract_addresses,omitempty",
(gogoproto.moretags) = "yaml:\"contract_addresses\""
];

uint64 contract_gas_limit = 2 [
// contract_gas_limit defines the maximum amount of gas that can be used by a contract.
uint64 contract_gas_limit = 1 [
(gogoproto.jsontag) = "contract_gas_limit,omitempty",
(gogoproto.moretags) = "yaml:\"contract_gas_limit\""
];
Expand Down
Loading

0 comments on commit 3dadeb5

Please sign in to comment.