Merge branch 'master' into adr_gov_split_vote

This commit is contained in:
Sunny Aggarwal 2020-11-06 11:43:20 -04:00 committed by GitHub
commit bf508d9699
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
80 changed files with 2598 additions and 2382 deletions

View File

@ -180,7 +180,7 @@ jobs:
if: env.GIT_DIFF
- name: test & coverage report creation
run: |
cat pkgs.txt.part.${{ matrix.part }} | xargs go test -mod=readonly -timeout 30m -race -tags='cgo ledger test_ledger_mock' > ${{ matrix.part }}-race-output.txt
cat pkgs.txt.part.${{ matrix.part }} | xargs go test -mod=readonly -json -timeout 30m -race -tags='cgo ledger test_ledger_mock' > ${{ matrix.part }}-race-output.txt
if: env.GIT_DIFF
- uses: actions/upload-artifact@v2
with:

View File

@ -36,15 +36,18 @@ Ref: https://keepachangelog.com/en/1.0.0/
## [Unreleased]
### Improvements
* (tendermint) [\#7828](https://github.com/cosmos/cosmos-sdk/pull/7828) Update tendermint dependency to v0.34.0-rc6
## [v0.40.0-rc2](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.40.0-rc2) - 2020-11-02
### Client Breaking
* (x/staking) [\#7499](https://github.com/cosmos/cosmos-sdk/pull/7499) `BondStatus` is now a protobuf `enum` instead of an `int32`, and JSON serialized using its protobuf name, so expect names like `BOND_STATUS_UNBONDING` as opposed to `Unbonding`.
* (x/evidence) [\#7538](https://github.com/cosmos/cosmos-sdk/pull/7538) The ABCI's `Result.Data` field of `MsgSubmitEvidence` does not contain the raw evidence's hash, but the encoded `MsgSubmitEvidenceResponse` struct.
* (x/upgrade) [#7697](https://github.com/cosmos/cosmos-sdk/pull/7697) Rename flag name "--time" to "--upgrade-time", "--info" to "--upgrade-info", to keep it consistent with help message.
* (x/auth) [#7788](https://github.com/cosmos/cosmos-sdk/pull/7788) Remove `tx auth` subcommands, all auth subcommands exist as `tx <subcommand>`
### API Breaking
* (AppModule) [\#7518](https://github.com/cosmos/cosmos-sdk/pull/7518) [\#7584](https://github.com/cosmos/cosmos-sdk/pull/7584) Rename `AppModule.RegisterQueryServices` to `AppModule.RegisterServices`, as this method now registers multiple services (the gRPC query service and the protobuf Msg service). A `Configurator` struct is used to hold the different services.
* (x/staking/types) [\#7447](https://github.com/cosmos/cosmos-sdk/issues/7447) Remove bech32 PubKey support:
* `ValidatorI` interface update. `GetConsPubKey` renamed to `TmConsPubKey` (consensus public key must be a tendermint key). `TmConsPubKey`, `GetConsAddr` methods return error.
* `Validator` update. Methods changed in `ValidatorI` (as described above) and `ToTmValidator` return error.
@ -52,19 +55,69 @@ Ref: https://keepachangelog.com/en/1.0.0/
* `MsgCreateValidator.Pubkey` type changed from `string` to `codectypes.Any`.
* Deprecating and renaming `MakeEncodingConfig` to `MakeTestEncodingConfig` (both in `simapp` and `simapp/params` packages).
* (tx) [\#7688](https://github.com/cosmos/cosmos-sdk/pull/7688) The gRPC simulate service method has been moved from `cosmos.base.v1beta1.simulate` to `cosmos.tx.v1beta1`, as a method in the Tx service.
* [#7764](https://github.com/cosmos/cosmos-sdk/pull/7764) Added module initialization options:
* `server/types.AppExporter` requires extra argument: `AppOptions`.
* `server.AddCommands` requires extra argument: `addStartFlags types.ModuleInitFlags`
* `x/crisis.NewAppModule` has a new attribute: `skipGenesisInvariants`. [PR](https://github.com/cosmos/cosmos-sdk/pull/7764)
### Features
* (tx) [\#7688](https://github.com/cosmos/cosmos-sdk/pull/7688) Add a new Tx gRPC service with methods `Simulate` and `GetTx` (by hash).
* __Modules__
* `x/crisis` has a new function: `AddModuleInitFlags`, which will register optional crisis module flags for the start command.
### Bug Fixes
* (client) [\#7699](https://github.com/cosmos/cosmos-sdk/pull/7699) Fix panic in context when setting invalid nodeURI. `WithNodeURI` does not set the `Client` in the context.
* (x/gov) [#7641](https://github.com/cosmos/cosmos-sdk/pull/7641) Fix tally calculation precision error.
### Improvements
* (rest) [#7649](https://github.com/cosmos/cosmos-sdk/pull/7649) Return an unsigned tx in legacy GET /tx endpoint when signature conversion fails
* (cli) [#7764](https://github.com/cosmos/cosmos-sdk/pull/7764) Update x/banking and x/crisis InitChain to improve node startup time
## [v0.40.0-rc1](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.40.0-rc1) - 2020-10-19
### Client Breaking Changes
* __Modules__
* (x/staking) [\#7499](https://github.com/cosmos/cosmos-sdk/pull/7499) `BondStatus` is now a protobuf `enum` instead
of an `int32`, and JSON serialized using its protobuf name, so expect names like `BOND_STATUS_UNBONDING` as opposed
to `Unbonding`.
* (x/staking) [\#7556](https://github.com/cosmos/cosmos-sdk/pull/7556) The ABCI's `Result.Data` field for
`MsgBeginRedelegate` and `MsgUndelegate` responses does not contain custom binary marshaled `completionTime`, but the
protobuf encoded `MsgBeginRedelegateResponse` and `MsgUndelegateResponse` structs respectively
* (x/evidence) [\#7538](https://github.com/cosmos/cosmos-sdk/pull/7538) The ABCI's `Result.Data` field for
`MsgSubmitEvidence` responses does not contain the raw evidence's hash, but the protobuf encoded
`MsgSubmitEvidenceResponse` struct.
* (x/gov) [\#7533](https://github.com/cosmos/cosmos-sdk/pull/7533) The ABCI's `Result.Data` field for
`MsgSubmitProposal` responses does not contain a raw binary encoding of the `proposalID`, but the protobuf encoded
`MsgSubmitSubmitProposalResponse` struct.
### API Breaking
* (AppModule) [\#7518](https://github.com/cosmos/cosmos-sdk/pull/7518) [\#7584](https://github.com/cosmos/cosmos-sdk/pull/7584) Rename `AppModule.RegisterQueryServices` to `AppModule.RegisterServices`, as this method now registers multiple services (the gRPC query service and the protobuf Msg service). A `Configurator` struct is used to hold the different services.
### Features
* (modules) [\#7540](https://github.com/cosmos/cosmos-sdk/issues/7540) Protobuf service definitions can now be used for
packing `Msg`s in transactions as defined in [ADR 031](./docs/architecture/adr-031-msg-service.md). All modules now
define a `Msg` protobuf service.
* (codec) [\#7519](https://github.com/cosmos/cosmos-sdk/pull/7519) `InterfaceRegistry` now inherits `jsonpb.AnyResolver`, and has a `RegisterCustomTypeURL` method to support ADR 031 packing of `Any`s. `AnyResolver` is now a required parameter to `RejectUnknownFields`.
* (baseapp) [\#7519](https://github.com/cosmos/cosmos-sdk/pull/7519) Add `ServiceMsgRouter` to BaseApp to handle routing of protobuf service `Msg`s. The two new types defined in ADR 031, `sdk.ServiceMsg` and `sdk.MsgRequest` are introduced with this router.
* (tx) [\#7688](https://github.com/cosmos/cosmos-sdk/pull/7688) Add a new Tx gRPC service with methods `Simulate` and `GetTx` (by hash).
* (cli) [\#7221](https://github.com/cosmos/cosmos-sdk/pull/7221) Add the option of emitting amino encoded json from the CLI
### Bug Fixes
* (kvstore) [\#7415](https://github.com/cosmos/cosmos-sdk/pull/7415) Allow new stores to be registered during on-chain upgrades.
* (client) [\#7699](https://github.com/cosmos/cosmos-sdk/pull/7699) Fix panic in context when setting invalid nodeURI. `WithNodeURI` does not set the `Client` in the context.
* (x/gov) [#7641](https://github.com/cosmos/cosmos-sdk/pull/7641) Fix tally calculation precision error.
* (rest) [\#7730](https://github.com/cosmos/cosmos-sdk/pull/7730) Fix fetch txs by height on legacy REST endpoint
### Improvements
* (tendermint) [\#7527](https://github.com/cosmos/cosmos-sdk/pull/7527) Update sdk to tendermint 0.34-rc5
* (iavl) [\#7549](https://github.com/cosmos/cosmos-sdk/pull/7549) Update sdk to IAVL 0.15.0-rc4
## [v0.40.0-rc0](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.40.0-rc0) - 2020-10-13

View File

@ -389,7 +389,7 @@ proto-check-breaking-docker:
@$(DOCKER_BUF) check breaking --against-input $(HTTPS_GIT)#branch=master
.PHONY: proto-check-breaking-ci
TM_URL = https://raw.githubusercontent.com/tendermint/tendermint/v0.34.0-rc5/proto/tendermint
TM_URL = https://raw.githubusercontent.com/tendermint/tendermint/v0.34.0-rc6/proto/tendermint
GOGO_PROTO_URL = https://raw.githubusercontent.com/regen-network/protobuf/cosmos
COSMOS_PROTO_URL = https://raw.githubusercontent.com/regen-network/cosmos-proto/master
CONFIO_URL = https://raw.githubusercontent.com/confio/ics23/v0.6.3

View File

@ -354,6 +354,10 @@ func (app *BaseApp) halt() {
// snapshot takes a snapshot of the current state and prunes any old snapshottypes.
func (app *BaseApp) snapshot(height int64) {
if app.snapshotManager == nil {
app.logger.Info("snapshot manager not configured")
return
}
app.logger.Info("Creating state snapshot", "height", height)
snapshot, err := app.snapshotManager.Create(uint64(height))
if err != nil {
@ -447,6 +451,11 @@ func (app *BaseApp) LoadSnapshotChunk(req abci.RequestLoadSnapshotChunk) abci.Re
// OfferSnapshot implements the ABCI interface. It delegates to app.snapshotManager if set.
func (app *BaseApp) OfferSnapshot(req abci.RequestOfferSnapshot) abci.ResponseOfferSnapshot {
if app.snapshotManager == nil {
app.logger.Error("snapshot manager not configured")
return abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_ABORT}
}
if req.Snapshot == nil {
app.logger.Error("Received nil snapshot")
return abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_REJECT}
@ -481,6 +490,11 @@ func (app *BaseApp) OfferSnapshot(req abci.RequestOfferSnapshot) abci.ResponseOf
// ApplySnapshotChunk implements the ABCI interface. It delegates to app.snapshotManager if set.
func (app *BaseApp) ApplySnapshotChunk(req abci.RequestApplySnapshotChunk) abci.ResponseApplySnapshotChunk {
if app.snapshotManager == nil {
app.logger.Error("snapshot manager not configured")
return abci.ResponseApplySnapshotChunk{Result: abci.ResponseApplySnapshotChunk_ABORT}
}
_, err := app.snapshotManager.RestoreChunk(req.Chunk)
switch {
case err == nil:
@ -537,9 +551,24 @@ func gRPCErrorToSDKError(err error) error {
}
}
func checkNegativeHeight(height int64) error {
if height < 0 {
// Reject invalid heights.
return sdkerrors.Wrap(
sdkerrors.ErrInvalidRequest,
"cannot query with height < 0; please provide a valid height",
)
}
return nil
}
// createQueryContext creates a new sdk.Context for a query, taking as args
// the block height and whether the query needs a proof or not.
func (app *BaseApp) createQueryContext(height int64, prove bool) (sdk.Context, error) {
if err := checkNegativeHeight(height); err != nil {
return sdk.Context{}, err
}
// when a client did not provide a query height, manually inject the latest
if height == 0 {
height = app.LastBlockHeight()

View File

@ -1,6 +1,7 @@
package baseapp
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
@ -116,3 +117,25 @@ func TestGetBlockRentionHeight(t *testing.T) {
})
}
}
// Test and ensure that negative heights always cause errors.
// See issue https://github.com/cosmos/cosmos-sdk/issues/7662.
func TestBaseAppCreateQueryContextRejectsNegativeHeights(t *testing.T) {
t.Parallel()
logger := defaultLogger()
db := dbm.NewMemDB()
name := t.Name()
app := NewBaseApp(name, logger, db, nil)
proves := []bool{
false, true,
}
for _, prove := range proves {
t.Run(fmt.Sprintf("prove=%t", prove), func(t *testing.T) {
sctx, err := app.createQueryContext(-10, true)
require.Error(t, err)
require.Equal(t, sctx, sdk.Context{})
})
}
}

View File

@ -11,6 +11,7 @@ import (
"google.golang.org/grpc/status"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
)
@ -33,6 +34,11 @@ func (app *BaseApp) RegisterGRPCServer(server gogogrpc.Server) {
if heightHeaders := md.Get(grpctypes.GRPCBlockHeightHeader); len(heightHeaders) > 0 {
height, err = strconv.ParseInt(heightHeaders[0], 10, 64)
if err != nil {
return nil, sdkerrors.Wrapf(
sdkerrors.ErrInvalidRequest,
"Baseapp.RegisterGRPCServer: invalid height header %q: %v", grpctypes.GRPCBlockHeightHeader, err)
}
if err := checkNegativeHeight(height); err != nil {
return nil, err
}
}

View File

@ -204,6 +204,10 @@ func (app *BaseApp) SetSnapshotStore(snapshotStore *snapshots.Store) {
if app.sealed {
panic("SetSnapshotStore() on sealed BaseApp")
}
if snapshotStore == nil {
app.snapshotManager = nil
return
}
app.snapshotManager = snapshots.NewManager(snapshotStore, app.cms)
}

View File

@ -15,6 +15,7 @@ import (
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
"github.com/cosmos/cosmos-sdk/codec/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
var _ gogogrpc.ClientConn = Context{}
@ -35,6 +36,11 @@ func (ctx Context) Invoke(grpcCtx gocontext.Context, method string, args, reply
if err != nil {
return err
}
if height < 0 {
return sdkerrors.Wrapf(
sdkerrors.ErrInvalidRequest,
"client.Context.Invoke: height (%d) from %q must be >= 0", height, grpctypes.GRPCBlockHeightHeader)
}
ctx = ctx.WithHeight(height)
}

View File

@ -173,7 +173,10 @@ func DerivePrivateKeyForPath(privKeyBytes, chainCode [32]byte, path string) ([]b
part = part[:len(part)-1]
}
idx, err := strconv.ParseUint(part, 10, 32)
// As per the extended keys specification in
// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#extended-keys
// index values are in the range [0, 1<<31-1] aka [0, max(int32)]
idx, err := strconv.ParseUint(part, 10, 31)
if err != nil {
return []byte{}, fmt.Errorf("invalid BIP 32 path: %s", err)
}

View File

@ -213,3 +213,65 @@ func TestCreateHDPath(t *testing.T) {
})
}
}
// Tests to ensure that any index value is in the range [0, max(int32)] as per
// the extended keys specification. If the index belongs to that of a hardened key,
// its 0x80000000 bit will be set, so we can still accept values in [0, max(int32)] and then
// increase its value as deriveKeyPath already augments.
// See issue https://github.com/cosmos/cosmos-sdk/issues/7627.
func TestDeriveHDPathRange(t *testing.T) {
seed := mnemonicToSeed("I am become Death, the destroyer of worlds!")
tests := []struct {
path string
wantErr string
}{
{
path: "1'/2147483648/0'/0/0",
wantErr: "out of range",
},
{
path: "2147483648'/1/0/0",
wantErr: "out of range",
},
{
path: "2147483648'/2147483648/0'/0/0",
wantErr: "out of range",
},
{
path: "1'/-5/0'/0/0",
wantErr: "invalid syntax",
},
{
path: "-2147483646'/1/0/0",
wantErr: "invalid syntax",
},
{
path: "-2147483648'/-2147483648/0'/0/0",
wantErr: "invalid syntax",
},
{
// Should pass.
path: "1'/2147483647/0'/0/0",
},
{
// Should pass.
path: "2147483647'/1/0'/0/0",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.path, func(t *testing.T) {
master, ch := hd.ComputeMastersFromSeed(seed)
_, err := hd.DerivePrivateKeyForPath(master, ch, tt.path)
if tt.wantErr == "" {
require.Nil(t, err, "unexpected error")
} else {
require.NotNil(t, err, "expected a report of an int overflow")
require.Contains(t, err.Error(), tt.wantErr)
}
})
}
}

View File

@ -32,7 +32,7 @@
// that the keyring keyring may be kept unlocked for the whole duration of the user
// session.
// file This backend more closely resembles the previous keyring storage used prior to
// v0.38.1. It stores the keyring encrypted within the apps configuration directory.
// v0.38.1. It stores the keyring encrypted within the app's configuration directory.
// This keyring will request a password each time it is accessed, which may occur
// multiple times in a single command resulting in repeated password prompts.
// kwallet This backend uses KDE Wallet Manager as a credentials management application:

View File

@ -71,3 +71,4 @@ Read about the [PROCESS](./PROCESS.md).
- [ADR 028: Public Key Addresses](./adr-028-public-key-addresses.md)
- [ADR 031: Protobuf Msg Services](./adr-031-msg-service.md)
- [ADR 032: Typed Events](./adr-032-typed-events.md)
- [ADR 035: Rosetta API Support](./adr-035-rosetta-api-support.md)

View File

@ -0,0 +1,274 @@
# ADR 035: Rosetta API Support
## Authors
- Jonathan Gimeno (@jgimeno)
- David Grierson (@senormonito)
- Alessio Treglia (@alessio)
## Context
[Rosetta API](https://www.rosetta-api.org/) is an open-source specification and set of tools developed by Coinbase to
standardise blockchain interactions.
Through the use of a standard API for integrating blockchain applications it will
* Be easier for a user to interact with a given blockchain
* Allow exchanges to integrate new blockchains quickly and easily
* Enable application developers to build cross-blockchain applications such as block explorers, wallets and dApps at
considerably lower cost and effort.
## Decision
It is clear that adding Rosetta API support to the Cosmos SDK will bring value to all the developers and
Cosmos SDK based chains in the ecosystem. How it is implemented is key.
The driving principles of the proposed design are:
1. **Extensibility:** it must be as riskless and painless as possible for application developers to set-up network
configurations to expose Rosetta API-compliant services.
2. **Long term support:** This proposal aims to provide support for all the supported Cosmos SDK release series.
3. **Cost-efficiency:** Backporting changes to Rosetta API specifications from `master` to the various stable
branches of Cosmos SDK is a cost that needs to be reduced.
We will achieve these delivering on these principles by the following:
1. There will be an external repo called [cosmos-rosetta-gateway](https://github.com/tendermint/cosmos-rosetta-gateway)
for the implementation of the core Rosetta API features, particularly:
a. The types and interfaces. This separates design from implementation detail.
b. Some core implementations: specifically, the `Service` functionality as this is independent of the Cosmos SDK version.
2. Due to differences between the Cosmos release series, each series will have its own specific API implementations of `Network` struct and `Adapter` interface.
3. There will be two options for starting an API service in applications:
a. API shares the application process
b. API-specific process.
## Architecture
### The External Repo
As section will describe the proposed external library, including the service implementation, plus the defined types and interfaces.
#### Service
`Service` is a simple `struct` that is started and listens to the port specified in the options. This is meant to be used across all the Cosmos SDK versions that are actively supported.
The constructor follows:
`func New(options Options, network Network) (*Service, error)`
#### Types
`Service` accepts an `Options` `struct` that holds service configuration values, such as the port the service would be listening to:
```golang
type Options struct {
ListenAddress string
}
```
The `Network` type holds network-specific properties (i.e. configuration values) and adapters. Pre-configured concrete types will be available for each Cosmos SDK release. Applications can also create their own custom types.
```golang
type Network struct {
Properties rosetta.NetworkProperties
Adapter rosetta.Adapter
}
```
A `NetworkProperties` `struct` comprises basic values that are required by a Rosetta API `Service`:
```golang
type NetworkProperties struct {
// Mandatory properties
Blockchain string
Network string
SupportedOperations []string
}
```
Rosetta API services use `Blockchain` and `Network` as identifiers, e.g. the developers of _gaia_, the application that powers the Cosmos Hub, may want to set those to `Cosmos Hub` and `cosmos-hub-3` respectively.
`SupportedOperations` contains the transaction types that are supported by the library. At the present time,
only `cosmos-sdk/MsgSend` is supported in Launchpad. Additional operations will be added in due time.
For Launchpad we will map the amino type name to the operation supported, in Stargate we will use the protoc one.
#### Interfaces
Every SDK version uses a different format to connect (rpc, gRpc, etc), we have abstracted this in what is called the
Adapter. This is an interface that defines the methods an adapter implementation must provide in order to be used
in the `Network` interface.
Each Cosmos SDK release series will have their own Adapter implementations.
Developers can implement their own custom adapters as required.
```golang
type Adapter interface {
DataAPI
ConstructionAPI
}
type DataAPI interface {
server.NetworkAPIServicer
server.AccountAPIServicer
server.MempoolAPIServicer
server.BlockAPIServicer
server.ConstructionAPIServicer
}
type ConstructionAPI interface {
server.ConstructionAPIServicer
}
```
Example in pseudo-code of an Adapter interface:
```golang
type SomeAdapter struct {
cosmosClient client
tendermintClient client
}
func NewSomeAdapter(cosmosClient client, tendermintClient client) rosetta.Adapter {
return &SomeAdapter{cosmosClient: cosmosClient, tendermintClient: tendermintClient}
}
func (s SomeAdapter) NetworkStatus(ctx context.Context, request *types.NetworkRequest) (*types.NetworkStatusResponse, *types.Error) {
resp := s.tendermintClient.CallStatus()
// ... Parse status Response
// build NetworkStatusResponse
return networkStatusResp, nil
}
func (s SomeAdapter) AccountBalance(ctx context.Context, request *types.AccountBalanceRequest) (*types.AccountBalanceResponse, *types.Error) {
resp := s.cosmosClient.Account()
// ... Parse cosmos specific account response
// build AccountBalanceResponse
return AccountBalanceResponse, nil
}
// And we repeat for all the methods defined in the interface.
```
For further information about the `Servicer` interfaces, please refer to the [Coinbase's rosetta-sdk-go's documentation](https://pkg.go.dev/github.com/coinbase/rosetta-sdk-go@v0.5.9/server).
### 2. Cosmos SDK Implementation
As described, each Cosmos SDK release series will have version specific implementations of `Network` and `Adapter`, as
well as a `NewNetwork` constructor.
Due to separation of interface and implementation, application developers have the option to override as needed,
using this code as reference.
```golang
// NewNetwork returns the default application configuration.
func NewNetwork(options Options) service.Network {
cosmosClient := cosmos.NewClient(fmt.Sprintf("http://%s", options.CosmosEndpoint))
tendermintClient := tendermint.NewClient(fmt.Sprintf("http://%s", options.TendermintEndpoint))
return service.Network{
Properties: rosetta.NetworkProperties{
Blockchain: options.Blockchain,
Network: options.Network,
SupportedOperations: []string{OperationTransfer},
},
Adapter: newAdapter(
cosmosClient,
tendermintClient,
properties{
Blockchain: options.Blockchain,
Network: options.Network,
OfflineMode: options.OfflineMode,
},
),
}
}
```
### 3. API service invocation
As stated at the start, application developers will have two methods for invocation of the Rosetta API service:
1. Shared process for both application and API
2. Standalone API service
#### Shared Process (Only Stargate)
Rosetta API service could run within the same execution process as the application. New configuration option and
command line flags would be provided to support this:
```golang
if config.Rosetta.Enable {
....
get contecxt, flags, etc
...
h, err := service.New(
service.Options{ListenAddress: config.Rosetta.ListenAddress},
rosetta.NewNetwork(cdc, options),
)
if err != nil {
}
...
go func() {
if err := h.Start(config); err != nil {
errCh <- err
}
}()
}
```
#### Separate API service
Client application developers can write a new command to launch a Rosetta API server as a separate process too:
```golang
func RosettaCommand(cdc *codec.Codec) *cobra.Command {
...
cmd := &cobra.Command{
Use: "rosetta",
....
RunE: func(cmd *cobra.Command, args []string) error {
....
get contecxt, flags, etc
...
h, err := service.New(
service.Options{Endpoint: endpoint},
rosetta.NewNetwork(cdc, options),
)
if err != nil {
return err
}
...
h.Start()
}
}
...
}
```
## Status
Proposed
## Consequences
### Positive
- Out-of-the-box Rosetta API support within Cosmos SDK.
- Blockchain interface standardisation
## References
- https://www.rosetta-api.org/
- https://github.com/tendermint/cosmos-rosetta-gateway

View File

@ -148,7 +148,8 @@ AppModule 在模块上公开了一组有用的方法,这些方法有助于将
模块的`处理程序`通常在名为 `handler.go` 的文件中定义,并包括:
- NewHandler 将消息发到对应的回调 `handler`。 该函数返回一个 `handler` 函数,此前这个函数在 `AppModule` 中注册,以在应用程序的模块管理器中用于初始化应用程序的路由器。接下来是 [nameservice tutorial](https://github.com/cosmos/sdk-tutorials/tree/master/nameservice) 的一个例子。
+++ https://github.com/cosmos/sdk-tutorials/blob/master/nameservice/x/nameservice/handler.go#L12-L26
+++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/internal/keeper/querier.go#L19-L32
- 模块定义的每种消息类型的处理函数。开发人员在这些函数中编写消息处理逻辑。这通常包括进行状态检查以确保消息有效,并调用 [`keeper`](https://docs.cosmos.network/master/basics/app-anatomy.html#keeper) 的方法来更新状态。

View File

@ -1,7 +1,7 @@
<!--
order: false
parent:
order: 5
order: 6
-->
# Interfaces
@ -12,4 +12,3 @@ This repository contains documentation on interfaces for Cosmos SDK applications
2. [Lifecycle of a Query](./query-lifecycle.md)
3. [Command-Line Interface](./cli.md)
4. [Rest Interface](./rest.md)

1577
docs/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,6 @@
"author": "",
"license": "ISC",
"dependencies": {
"vuepress-theme-cosmos": "^1.0.173"
"vuepress-theme-cosmos": "^1.0.175"
}
}

13
docs/run-node/README.md Normal file
View File

@ -0,0 +1,13 @@
<!--
order: false
parent:
order: 5
-->
# Running a Node
This folder contains documentation on how to run a node and interact with it.
1. [Setting up the keyring](./keyring.md)
2. [Running a Node](./run-node.md)
3. [Interacting with a Node](./interact-node.md)

View File

@ -0,0 +1,46 @@
<!--
order: 3
-->
# Interacting with the Node
## Pre-requisite Readings
- [Running a Node](./run-node.md) {prereq}
## Via CLI
Now that your chain is running, it is time to try sending tokens from the first account you created to a second account. In a new terminal window, start by running the following query command:
```bash
simd query account $MY_VALIDATOR_ADDRESS --chain-id my-test-chain
```
You should see the current balance of the account you created, equal to the original balance of `stake` you granted it minus the amount you delegated via the `gentx`. Now, create a second account:
```bash
simd keys add recipient --keyring-backend test
# Put the generated address in a variable for later use.
RECIPIENT=$(simd keys show recipient -a --keyring-backend test)
```
The command above creates a local key-pair that is not yet registered on the chain. An account is created the first time it receives tokens from another account. Now, run the following command to send tokens to the `recipient` account:
```bash
simd tx send $MY_VALIDATOR_ADDRESS $RECIPIENT 1000stake --chain-id my-test-chain
# Check that the recipient account did receive the tokens.
simd query account $RECIPIENT --chain-id my-test-chain
```
Finally, delegate some of the stake tokens sent to the `recipient` account to the validator:
```bash
simd tx staking delegate $(simd keys show my_validator --bech val -a --keyring-backend test) 500stake --from recipient --chain-id my-test-chain
# Query the total delegations to `validator`.
simd query staking delegations-to $(simd keys show my_validator --bech val -a --keyring-backend test) --chain-id my-test-chain
```
You should see two delegations, the first one made from the `gentx`, and the second one you just performed from the `recipient` account.

View File

@ -1,28 +1,32 @@
<!--
order: 3
order: 1
-->
# The keyring
# Setting up the keyring
This document describes how to configure and use the keyring and its various backends for an [**application**](../basics/app-anatomy.md). A separate document for implementing a CLI for an SDK [**module**](../building-modules/intro.md) can be found [here](#../building-modules/module-interfaces.md#cli). {synopsis}
This document describes how to configure and use the keyring and its various backends for an [**application**](../basics/app-anatomy.md). {synopsis}
The keyring holds the private/public keypairs used to interact with a node. For instance, a validator key needs to be set up before running the blockchain node, so that blocks can be correctly signed. The private key can be stored in different locations, called "backends", such as a file or the operating system's own key storage.
## Available backends for the keyring
Starting with the v0.38.0 release, Cosmos SDK comes with a new keyring implementation
that provides a set of commands to manage cryptographic keys in a secure fashion. The
new keyring supports multiple storage backends, some of which may not be available on
all operating systems.
## The `os` backend
### The `os` backend
The `os` backend relies on operating system-specific defaults to handle key storage
securely. Typically, operating systems credentials sub-systems handle passwords prompt,
private keys storage, and user sessions according to their users password policies. Here
securely. Typically, an operating system's credential sub-system handles password prompts,
private keys storage, and user sessions according to the user's password policies. Here
is a list of the most popular operating systems and their respective passwords manager:
* macOS (since Mac OS 8.6): [Keychain](https://support.apple.com/en-gb/guide/keychain-access/welcome/mac)
* Windows: [Credentials Management API](https://docs.microsoft.com/en-us/windows/win32/secauthn/credentials-management)
* GNU/Linux:
* [libsecret](https://gitlab.gnome.org/GNOME/libsecret)
* [kwallet](https://api.kde.org/frameworks/kwallet/html/index.html)
- macOS (since Mac OS 8.6): [Keychain](https://support.apple.com/en-gb/guide/keychain-access/welcome/mac)
- Windows: [Credentials Management API](https://docs.microsoft.com/en-us/windows/win32/secauthn/credentials-management)
- GNU/Linux:
- [libsecret](https://gitlab.gnome.org/GNOME/libsecret)
- [kwallet](https://api.kde.org/frameworks/kwallet/html/index.html)
GNU/Linux distributions that use GNOME as default desktop environment typically come with
[Seahorse](https://wiki.gnome.org/Apps/Seahorse). Users of KDE based distributions are
@ -34,10 +38,10 @@ client.
designed to meet users' most common needs and provide them with a comfortable
experience without compromising on security.
## The `file` backend
### The `file` backend
The `file` backend more closely resembles the keybase implementation used prior to
v0.38.1. It stores the keyring encrypted within the apps configuration directory. This
v0.38.1. It stores the keyring encrypted within the app's configuration directory. This
keyring will request a password each time it is accessed, which may occur multiple
times in a single command resulting in repeated password prompts. If using bash scripts
to execute commands using the `file` option you may want to utilize the following format
@ -54,7 +58,7 @@ $ echo $KEYPASSWD | gaiacli keys show me # single promp
The first time you add a key to an empty keyring, you will be prompted to type the password twice.
:::
## The `pass` backend
### The `pass` backend
The `pass` backend uses the [pass](https://www.passwordstore.org/) utility to manage on-disk
encryption of keys' sensitive data and metadata. Keys are stored inside `gpg` encrypted files
@ -78,15 +82,42 @@ $ pass init <GPG_KEY_ID>
Replace `<GPG_KEY_ID>` with your GPG key ID. You can use your personal GPG key or an alternative
one you may want to use specifically to encrypt the password store.
## The `test` backend
### The `test` backend
The `test` backend is a password-less variation of the `file` backend. Keys are stored
unencrypted on disk. This backend is meant for testing purposes only and **should never be used
in production environments**.
## The `kwallet` backend
### The `kwallet` backend
The `kwallet` backend uses `KDE Wallet Manager`, which comes installed by default on the
GNU/Linux distributions that ships KDE as default desktop environment. Please refer to
[KWallet Handbook](https://docs.kde.org/stable5/en/kdeutils/kwallet5/index.html) for more
information.
## Adding keys to the keyring
::: warning
Make sure you can build your own binary, and replace `simd` with the name of your binary in the snippets.
:::
Applications developed using the Cosmos SDK come with the `keys` subcommand. For the purpose of this tutorial, we're running the `simd` CLI, which is an application built using the Cosmos SDK for testing and educational purposes. For more information, see [`simapp`](https://github.com/cosmos/cosmos-sdk/tree/v0.40.0-rc2/simapp).
You can use `simd keys` for help about the keys command and `simd keys [command] --help` for more information about a particular subcommand.
::: tip
You can also enable auto-completion with the `simd completion` command. For example, at the start of a bash session, run `. <(simd completion)`, and all `simd` subcommands will be auto-completed.
:::
To create a new key in the keyring, run the `add` subcommand with a `<key_name>` argument. For the purpose of this tutorial, we will solely use the `test` backend, and call our new key `my_validator`. This key will be used in the next section.
```bash
$ simd keys add my_validator --keyring-backend test
# Put the generated address in a variable for later use.
MY_VALIDATOR_ADDRESS=$(simd keys show my_validator -a --keyring-backend test)
```
This command generates a new 24-word mnemonic phrase, persists it to the relevant backend, and outputs information about the keypair. If this keypair will be used to hold value-bearing tokens, be sure to write down the mnemonic phrase somewhere safe!
By default, the keyring generates a `secp256k1` keypair. The keyring also supports `ed25519` keys, which may be created by passing the `--algo ed25519` flag. A keyring can of course hold both types of keys simultaneously, and the Cosmos SDK's `x/auth` module (in particular its [AnteHandlers](../core/baseapp.md#antehandler)) supports natively these two public key algorithms.

90
docs/run-node/run-node.md Normal file
View File

@ -0,0 +1,90 @@
<!--
order: 2
-->
# Running a Node
Now that the application is ready and the keyring populated, it's time to see how to run the blockchain node. In this section, the application we are running is called [`simapp`](https://github.com/cosmos/cosmos-sdk/tree/v0.40.0-rc2/simapp), and its corresponding CLI binary `simd`. {synopsis}
## Pre-requisite Readings
- [Anatomy of an SDK Application](../basics/app-anatomy.md) {prereq}
- [Setting up the keyring](./keyring.md) {prereq}
## Initialize the Chain
::: warning
Make sure you can build your own binary, and replace `simd` with the name of your binary in the snippets.
:::
Before actually running the node, we need to initialize the chain, and most importantly its genesis file. This is done with the `init` subcommand:
```bash
# The argument <moniker> is the custom username of your node, it should be human-readable.
simd init <moniker> --chain-id my-test-chain
```
The command above creates all the configuration files needed for your node to run, as well as a default genesis file, which defines the initial state of the network. All these configuration files are in `~/.simapp` by default, but you can overwrite the location of this folder by passing the `--home` flag.
The `~/.simapp` folder has the following structure:
```bash
. # ~/.simapp
|- data # Contains the databases used by the node.
|- config/
|- app.toml # Application-related configuration file.
|- config.toml # Tendermint-related configuration file.
|- genesis.json # The genesis file.
|- node_key.json # Private key to use for node authentication in the p2p protocol.
|- priv_validator_key.json # Private key to use as a validator in the consensus protocol.
```
Before starting the chain, you need to populate the state with at least one account. To do so, first [create a new account in the keyring](./keyring.md#adding-keys-to-the-keyring) named `my_validator` under the `test` keyring backend (feel free to choose another name and another backend).
Now that you have created a local account, go ahead and grant it some `stake` tokens in your chain's genesis file. Doing so will also make sure your chain is aware of this account's existence:
```bash
simd add-genesis-account $MY_VALIDATOR_ADDRESS 100000000stake
```
Recall that `$MY_VALIDATOR_ADDRESS` is a variable that holds the address of the `my_validator` key in the [keyring](./keyring.md#adding-keys-to-the-keyring). Also note that the tokens in the SDK have the `{amount}{denom}` format: `amount` is is a 18-digit-precision decimal number, and `denom` is the unique token identifier with its denomination key (e.g. `atom` or `uatom`). Here, we are granting `stake` tokens, as `stake` is the token identifier used for staking in [`simapp`](https://github.com/cosmos/cosmos-sdk/tree/v0.40.0-rc2/simapp). For your own chain with its own staking denom, that token identifier should be used instead.
Now that your account has some tokens, you need to add a validator to your chain. Validators are special full-nodes that participate in the consensus process (implemented in the [underlying consensus engine](../intro/sdk-app-architecture.md#tendermint)) in order to add new blocks to the chain. Any account can declare its intention to become a validator operator, but only those with sufficient delegation get to enter the active set (for example, only the top 125 validator candidates with the most delegation get to be validators in the Cosmos Hub). For this guide, you will add your local node (created via the `init` command above) as a validator of your chain. Validators can be declared before a chain is first started via a special transaction included in the genesis file called a `gentx`:
```bash
# Create a gentx.
simd gentx my_validator --amount 100000stake --chain-id my-test-chain --keyring-backend test
# Add the gentx to the genesis file.
simd collect-gentxs
```
A `gentx` does three things:
1. Registers the `validator` account you created as a validator operator account (i.e. the account that controls the validator).
2. Self-delegates the provided `amount` of staking tokens.
3. Link the operator account with a Tendermint node pubkey that will be used for signing blocks. If no `--pubkey` flag is provided, it defaults to the local node pubkey created via the `simd init` command above.
For more information on `gentx`, use the following command:
```bash
simd gentx --help
```
## Run a Localnet
Now that everything is set up, you can finally start your node:
```bash
simd start
```
You should see blocks come in.
The previous command allow you to run a single node. This is enough for the next section on interacting with this node, but you may wish to run multiple nodes at the same time, and see how consensus happens between them.
The naive way would be to run the same commands again in separate terminal windows. This is possible, however in the SDK, we leverage the power of [Docker Compose](https://docs.docker.com/compose/) to run a localnet. If you need inspiration on how to set up your own localnet with Docker Compose, you can have a look at the SDK's [`docker-compose.yml`](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc2/docker-compose.yml).
## Next {hide}
Read about the [Interacting with your Node](./interact-node.md) {hide}

View File

@ -33,7 +33,7 @@ if there was an error.
## Data Folder Layout
`$DAEMON_HOME/cosmovisor` is expected to belong completely to `cosmovisor` and
subprocesses the controlled by it. The folder content is organised as follows:
subprocesses that are controlled by it. The folder content is organised as follows:
```
.

View File

@ -1,160 +0,0 @@
# Quick Start
This guide serves as a practical introduction to building blockchains with the Cosmos SDK. It shows how to scaffold the code for a basic blockchain node, build and run it. Several important concepts of the Cosmos SDK are introduced along the way.
## Setup
::: tip
To follow this guide, you need to [install golang](https://golang.org/doc/install) and set [your \$GOPATH environment variable](https://golang.org/doc/code.html#GOPATH)
:::
::: warning
Make sure you are using the latest stable version of golang available on https://golang.org/dl/
:::
First, download the [`scaffold`](https://github.com/cosmos/scaffold) tool:
```bash
git clone https://github.com/cosmos/scaffold
```
The `scaffold` tool lets you easily scaffold boilerplate Cosmos SDK applications. Once you have downloaded it, simply install it on your machine:
```bash
cd scaffold
make
```
## Create a Basic Cosmos SDK Blockchain
To create a basic Cosmos SDK application, simply type in the following command:
```bash
scaffold app <lvl> <username|org> <repo>
```
There are multiple levels of apps to choose from, they can be found [here](https://github.com/cosmos/scaffold/blob/master/docs/app.md).
where `username|org` is the name of your github/gitlab/atlassian username or organisation, and `repo` the name of the distant repository you would push your application too. These arguments are used to configure the imports so that people can easily download and install your application once (if) you upload it.
The command above creates a starter application in a new folder named after the `repo` argument. This application contains the [basic logic most SDK applications](../intro/sdk-app-architecture.md) need as well as a set of standard [modules](../building-modules/intro.md) already hooked up. You can find which level consists of which modules [here](https://github.com/cosmos/scaffold/blob/master/docs/app.md)
The structure of the generated app will look like similar to the [recommended folder structure](../building-modules/structure.md). Below you will find a simple break down of some of the files.
- `app.go` is the [main file](../basics/app-anatomy.md#core-application-file) defining the application logic. This is where the state is instantiated and modules are declared. This is also where the Cosmos SDK is imported as a dependency to help build the application.
- `export.go` is a helper file used to export the state of the application into a new genesis file. It is helpful when you want to upgrade your chain to a new (breaking) version.
- `acli/main.go` builds the command-line interface for your blockchain application. It enables end-users to create transactions and query the chain for information.
- `aud/main.go` builds the main [daemon client](../basics/app-anatomy.md#node-client) of the chain. It is used to run a full-node that will connect to peers and sync its local application state with the latest state of the network.
- `go.mod` helps manage dependencies. The two main dependencies used are the Cosmos SDK to help build the application, and Tendermint to replicate it.
- `x/` is the folder to place all the custom modules built specifically for the application. In general, most of the modules used in an application have already been built by third-party developers and only need to be imported in `app.go`. These modules do not need to be cloned into the application's `x/` folder. This is why the basic application shown above, which uses several modules, works despite having an empty `x/` folder.
## Run your Blockchain
First, install the two main entry points of your blockchain, `aud` and `acli`:
```bash
go mod tidy
make install
```
Make sure the clients are properly installed:
```bash
acli --help
aud --help
```
Now that you have your daemon client `aud` and your command-line interface `acli` installed, go ahead and initialize your chain:
```bash
aud init <node-moniker> --chain-id test
```
The command above creates all the configuration files needed for your node to run, as well as a default genesis file, which defines the initial state of the network. Before starting the chain, you need to populate the state with at least one account. To do so, first create a new [account](../basics/accounts.md) named `validator` (feel free to choose another name):
```bash
acli keys add validator
```
Now that you have created a local account, go ahead and grant it `stake` tokens in your chain's genesis file. Doing so will also make sure your chain is aware of this account's existence:
```bash
aud add-genesis-account $(acli keys show validator -a) 100000000stake
```
Now that your account has some tokens, you need to add a validator to your chain. Validators are special full-nodes that participate in the consensus process (implemented in the [underlying consensus engine](../intro/sdk-app-architecture.md#tendermint)) in order to add new blocks to the chain. Any account can declare its intention to become a validator operator, but only those with sufficient delegation get to enter the active set (for example, only the top 125 validator candidates with the most delegation get to be validators in the Cosmos Hub). For this guide, you will add your local node (created via the `init` command above) as a validator of your chain. Validators can be declared before a chain is first started via a special transaction included in the genesis file called a `gentx`:
```bash
// create a gentx
aud gentx --name validator --amount 100000stake
// add the gentx to the genesis file
aud collect-gentxs
```
A `gentx` does three things:
1. Makes the `validator` account you created into a validator operator account (i.e. the account that controls the validator).
2. Self-delegates the provided `amount` of staking tokens.
3. Link the operator account with a Tendermint node pubkey that will be used for signing blocks. If no `--pubkey` flag is provided, it defaults to the local node pubkey created via the `aud init` command above.
For more on `gentx`, use the following command:
```bash
aud gentx --help
```
Now that everything is set up, you can finally start your node:
```bash
aud start
```
You should see blocks come in.
## Send Tokens and Increase Delegation
Now that your chain is running, it is time to try sending tokens from the first account you created to a second account. In a new terminal window, start by running the following query command:
```bash
acli query account $(acli keys show validator -a) --chain-id test
```
You should see the current balance of the account you created, equal to the original balance of `stake` you granted it minus the amount you delegated via the `gentx`. Now, create a second account:
```bash
acli keys add receiver
```
The command above creates a local key-pair that is not yet registered on the chain. An account is registered the first time it receives tokens from another account. Now, run the following command to send tokens to the second account:
```bash
acli tx send $(acli keys show validator -a) $(acli keys show receiver -a) 1000stake --chain-id test
```
Check that the second account did receive the tokens:
```bash
acli query account $(acli keys show receiver -a) --chain-id test
```
Finally, delegate some of the stake tokens sent to the `receiver` account to the validator:
```bash
acli tx staking delegate $(acli keys show validator --bech val -a) 500stake --from receiver --chain-id test
```
Try to query the total delegations to `validator`:
```bash
acli query staking delegations-to $(acli keys show validator --bech val -a) --chain-id test
```
You should see two delegations, the first one made from the `gentx`, and the second one you just performed from the `receiver` account.
## Next
Congratulations on making it to the end of this short introduction guide! If you want to learn more, check out the following resources:
- [How to build a full SDK application from scratch](https://tutorials.cosmos.network/nameservice/tutorial/00-intro.html).
- [Read the Cosmos SDK Documentation](../intro/overview.md).

2
go.mod
View File

@ -45,7 +45,7 @@ require (
github.com/tendermint/btcd v0.1.1
github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15
github.com/tendermint/go-amino v0.16.0
github.com/tendermint/tendermint v0.34.0-rc5
github.com/tendermint/tendermint v0.34.0-rc6
github.com/tendermint/tm-db v0.6.2
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee
golang.org/x/net v0.0.0-20200930145003-4acb6c075d10 // indirect

10
go.sum
View File

@ -105,6 +105,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/confio/ics23/go v0.0.0-20200817220745-f173e6211efb/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg=
github.com/confio/ics23/go v0.6.3 h1:PuGK2V1NJWZ8sSkNDq91jgT/cahFEW9RGp4Y5jxulf0=
github.com/confio/ics23/go v0.6.3/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
@ -119,6 +120,7 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU=
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y=
github.com/cosmos/iavl v0.15.0-rc3.0.20201009144442-230e9bdf52cd/go.mod h1:3xOIaNNX19p0QrX0VqWa6voPRoJRGGYtny+DH8NEPvE=
github.com/cosmos/iavl v0.15.0-rc4 h1:P1wmET7BueqCzfxsn+BzVkDWDLY9ij2JNwkbIdM7RG8=
github.com/cosmos/iavl v0.15.0-rc4/go.mod h1:5CsecJdh44Uj4vZ6WSPeWq84hNW5BwRI36ZsAbfJvRw=
github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4=
@ -274,12 +276,14 @@ github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0U
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.1/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.5 h1:UImYN5qQ8tuGpGE16ZmjvcTtTw24zw1QAp/SlnNrZhI=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.14.7/go.mod h1:oYZKL012gGh6LMyg/xA7Q2yq6j8bu0wa+9w14EEthWU=
github.com/grpc-ecosystem/grpc-gateway v1.15.2 h1:HC+hWRWf+v5zTMPyoaYTKIJih+4sd4XRWmj0qlG87Co=
github.com/grpc-ecosystem/grpc-gateway v1.15.2/go.mod h1:vO11I9oWA+KsxmfFQPhLnnIb1VDE24M+pdxZFiuZcA8=
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU=
@ -593,6 +597,8 @@ github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoM
github.com/tendermint/tendermint v0.34.0-rc4/go.mod h1:yotsojf2C1QBOw4dZrTcxbyxmPUrT4hNuOQWX9XUwB4=
github.com/tendermint/tendermint v0.34.0-rc5 h1:2bnQfWyOMfTCbol5pwB8CgM2nxi6/Kz6zqlS6Udm/Cg=
github.com/tendermint/tendermint v0.34.0-rc5/go.mod h1:yotsojf2C1QBOw4dZrTcxbyxmPUrT4hNuOQWX9XUwB4=
github.com/tendermint/tendermint v0.34.0-rc6 h1:SVuKGvvE22KxfuK8QUHctUrmOWJsncZSYXIYtcnoKN0=
github.com/tendermint/tendermint v0.34.0-rc6/go.mod h1:ugzyZO5foutZImv0Iyx/gOFCX6mjJTgbLHTwi17VDVg=
github.com/tendermint/tm-db v0.6.2 h1:DOn8jwCdjJblrCFJbtonEIPD1IuJWpbRUUdR8GWE4RM=
github.com/tendermint/tm-db v0.6.2/go.mod h1:GYtQ67SUvATOcoY8/+x6ylk8Qo02BQyLrAs+yAcLvGI=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@ -638,6 +644,7 @@ golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee h1:4yd7jl+vXjalO5ztz6Vc1VADv+S/80LGJmyl1ROJ2AI=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -802,6 +809,7 @@ google.golang.org/genproto v0.0.0-20200324203455-a04cca1dde73/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201014134559-03b6142f0dc9 h1:fG84H9C3EXfuDlzkG+VEPDYHHExklP6scH1QZ5gQTqU=
google.golang.org/genproto v0.0.0-20201014134559-03b6142f0dc9/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
@ -819,6 +827,7 @@ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.0 h1:IBKSUNL2uBS2DkJBncPP+TwT0sp9tgA8A75NjHt6umg=
@ -838,6 +847,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=

View File

@ -68,7 +68,7 @@ func ExportCmd(appExporter types.AppExporter, defaultNodeHome string) *cobra.Com
forZeroHeight, _ := cmd.Flags().GetBool(FlagForZeroHeight)
jailAllowedAddrs, _ := cmd.Flags().GetStringSlice(FlagJailAllowedAddrs)
exported, err := appExporter(serverCtx.Logger, db, traceWriter, height, forZeroHeight, jailAllowedAddrs)
exported, err := appExporter(serverCtx.Logger, db, traceWriter, height, forZeroHeight, jailAllowedAddrs, serverCtx.Viper)
if err != nil {
return fmt.Errorf("error exporting state: %v", err)
}

View File

@ -129,7 +129,7 @@ func setupApp(t *testing.T, tempDir string) (*simapp.SimApp, context.Context, *t
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
db := dbm.NewMemDB()
encCfg := simapp.MakeTestEncodingConfig()
app := simapp.NewSimApp(logger, db, nil, true, map[int64]bool{}, tempDir, 0, encCfg)
app := simapp.NewSimApp(logger, db, nil, true, map[int64]bool{}, tempDir, 0, encCfg, simapp.EmptyAppOptions{})
serverCtx := server.NewDefaultContext()
serverCtx.Config.RootDir = tempDir
@ -148,18 +148,18 @@ func setupApp(t *testing.T, tempDir string) (*simapp.SimApp, context.Context, *t
app.Commit()
cmd := server.ExportCmd(
func(_ log.Logger, _ dbm.DB, _ io.Writer, height int64, forZeroHeight bool, jailAllowedAddrs []string) (types.ExportedApp, error) {
func(_ log.Logger, _ dbm.DB, _ io.Writer, height int64, forZeroHeight bool, jailAllowedAddrs []string, appOptons types.AppOptions) (types.ExportedApp, error) {
encCfg := simapp.MakeTestEncodingConfig()
var simApp *simapp.SimApp
if height != -1 {
simApp = simapp.NewSimApp(logger, db, nil, false, map[int64]bool{}, "", 0, encCfg)
simApp = simapp.NewSimApp(logger, db, nil, false, map[int64]bool{}, "", 0, encCfg, appOptons)
if err := simApp.LoadHeight(height); err != nil {
return types.ExportedApp{}, err
}
} else {
simApp = simapp.NewSimApp(logger, db, nil, true, map[int64]bool{}, "", 0, encCfg)
simApp = simapp.NewSimApp(logger, db, nil, true, map[int64]bool{}, "", 0, encCfg, appOptons)
}
return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs)

View File

@ -7,6 +7,7 @@ import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
@ -48,6 +49,7 @@ func (s *IntegrationTestSuite) TestGRPCServer() {
grpc.WithInsecure(), // Or else we get "no transport security set"
)
s.Require().NoError(err)
defer conn.Close()
// gRPC query to test service should work
testClient := testdata.NewQueryClient(conn)
@ -99,6 +101,42 @@ func (s *IntegrationTestSuite) TestGRPCServer() {
s.Require().True(servicesMap["cosmos.bank.v1beta1.Query"])
}
// Test and enforce that we upfront reject any connections to baseapp containing
// invalid initial x-cosmos-block-height that aren't positive and in the range [0, max(int64)]
// See issue https://github.com/cosmos/cosmos-sdk/issues/7662.
func (s *IntegrationTestSuite) TestGRPCServerInvalidHeaderHeights() {
t := s.T()
val0 := s.network.Validators[0]
// We should reject connections with invalid block heights off the bat.
invalidHeightStrs := []struct {
value string
wantErr string
}{
{"-1", "height < 0"},
{"9223372036854775808", "value out of range"}, // > max(int64) by 1
{"-10", "height < 0"},
{"18446744073709551615", "value out of range"}, // max uint64, which is > max(int64)
{"-9223372036854775809", "value out of range"}, // Out of the range of for negative int64
}
for _, tt := range invalidHeightStrs {
t.Run(tt.value, func(t *testing.T) {
conn, err := grpc.Dial(
val0.AppConfig.GRPC.Address,
grpc.WithInsecure(), // Or else we get "no transport security set"
)
defer conn.Close()
testClient := testdata.NewQueryClient(conn)
ctx := metadata.AppendToOutgoingContext(context.Background(), grpctypes.GRPCBlockHeightHeader, tt.value)
testRes, err := testClient.Echo(ctx, &testdata.EchoRequest{Message: "hello"})
require.Error(t, err)
require.Nil(t, testRes)
require.Contains(t, err.Error(), tt.wantErr)
})
}
}
func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
}

View File

@ -193,6 +193,25 @@ func startStandAlone(ctx *Context, appCreator types.AppCreator) error {
func startInProcess(ctx *Context, clientCtx client.Context, appCreator types.AppCreator) error {
cfg := ctx.Config
home := cfg.RootDir
var cpuProfileCleanup func()
if cpuProfile := ctx.Viper.GetString(flagCPUProfile); cpuProfile != "" {
f, err := os.Create(cpuProfile)
if err != nil {
return err
}
ctx.Logger.Info("starting CPU profiler", "profile", cpuProfile)
if err := pprof.StartCPUProfile(f); err != nil {
return err
}
cpuProfileCleanup = func() {
ctx.Logger.Info("stopping CPU profiler", "profile", cpuProfile)
pprof.StopCPUProfile()
f.Close()
}
}
traceWriterFile := ctx.Viper.GetString(flagTraceStore)
db, err := openDB(home)
@ -226,10 +245,12 @@ func startInProcess(ctx *Context, clientCtx client.Context, appCreator types.App
if err != nil {
return err
}
ctx.Logger.Debug("Initialization: tmNode created")
if err := tmNode.Start(); err != nil {
return err
}
ctx.Logger.Debug("Initialization: tmNode started")
// Add the tx service to the gRPC router.
app.RegisterTxService(clientCtx)
@ -273,26 +294,6 @@ func startInProcess(ctx *Context, clientCtx client.Context, appCreator types.App
}
}
var cpuProfileCleanup func()
if cpuProfile := ctx.Viper.GetString(flagCPUProfile); cpuProfile != "" {
f, err := os.Create(cpuProfile)
if err != nil {
return err
}
ctx.Logger.Info("starting CPU profiler", "profile", cpuProfile)
if err := pprof.StartCPUProfile(f); err != nil {
return err
}
cpuProfileCleanup = func() {
ctx.Logger.Info("stopping CPU profiler", "profile", cpuProfile)
pprof.StopCPUProfile()
f.Close()
}
}
defer func() {
if tmNode.IsRunning() {
_ = tmNode.Stop()

View File

@ -114,7 +114,7 @@ against which this app has been compiled.
BlockProtocol uint64
P2PProtocol uint64
}{
Tendermint: tversion.Version,
Tendermint: tversion.TMCoreSemVer,
ABCI: tversion.ABCIVersion,
BlockProtocol: tversion.BlockProtocol,
P2PProtocol: tversion.P2PProtocol,

View File

@ -5,6 +5,7 @@ import (
"io"
"github.com/gogo/protobuf/grpc"
"github.com/spf13/cobra"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types"
@ -48,6 +49,9 @@ type (
// application using various configurations.
AppCreator func(log.Logger, dbm.DB, io.Writer, AppOptions) Application
// ModuleInitFlags takes a start command and adds modules specific init flags.
ModuleInitFlags func(startCmd *cobra.Command)
// ExportedApp represents an exported app state, along with
// validators, consensus params and latest app height.
ExportedApp struct {
@ -63,5 +67,5 @@ type (
// AppExporter is a function that dumps all app state to
// JSON-serializable structure and returns the current validator set.
AppExporter func(log.Logger, dbm.DB, io.Writer, int64, bool, []string) (ExportedApp, error)
AppExporter func(log.Logger, dbm.DB, io.Writer, int64, bool, []string, AppOptions) (ExportedApp, error)
)

View File

@ -76,6 +76,7 @@ func InterceptConfigsPreRunHandler(cmd *cobra.Command) error {
if err != nil {
return err
}
basename := path.Base(executableName)
// Configure the viper instance
@ -201,7 +202,7 @@ func interceptConfigs(rootViper *viper.Viper) (*tmcfg.Config, error) {
}
// add server commands
func AddCommands(rootCmd *cobra.Command, defaultNodeHome string, appCreator types.AppCreator, appExport types.AppExporter) {
func AddCommands(rootCmd *cobra.Command, defaultNodeHome string, appCreator types.AppCreator, appExport types.AppExporter, addStartFlags types.ModuleInitFlags) {
tendermintCmd := &cobra.Command{
Use: "tendermint",
Short: "Tendermint subcommands",
@ -213,9 +214,11 @@ func AddCommands(rootCmd *cobra.Command, defaultNodeHome string, appCreator type
ShowAddressCmd(),
VersionCmd(),
)
startCmd := StartCmd(appCreator, defaultNodeHome)
addStartFlags(startCmd)
rootCmd.AddCommand(
StartCmd(appCreator, defaultNodeHome),
startCmd,
UnsafeResetAllCmd(),
flags.LineBreak,
tendermintCmd,

View File

@ -8,6 +8,7 @@ import (
"github.com/gorilla/mux"
"github.com/rakyll/statik/fs"
"github.com/spf13/cast"
abci "github.com/tendermint/tendermint/abci/types"
tmjson "github.com/tendermint/tendermint/libs/json"
"github.com/tendermint/tendermint/libs/log"
@ -197,7 +198,8 @@ func init() {
// NewSimApp returns a reference to an initialized SimApp.
func NewSimApp(
logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, skipUpgradeHeights map[int64]bool,
homePath string, invCheckPeriod uint, encodingConfig simappparams.EncodingConfig, baseAppOptions ...func(*baseapp.BaseApp),
homePath string, invCheckPeriod uint, encodingConfig simappparams.EncodingConfig,
appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp),
) *SimApp {
// TODO: Remove cdc in favor of appCodec once all modules are migrated.
@ -317,6 +319,12 @@ func NewSimApp(
// If evidence needs to be handled for the app, set routes in router here and seal
app.EvidenceKeeper = *evidenceKeeper
/**** Module Options ****/
// NOTE: we may consider parsing `appOpts` inside module constructors. For the moment
// we prefer to be more strict in what arguments the modules expect.
var skipGenesisInvariants = cast.ToBool(appOpts.Get(crisis.FlagSkipGenesisInvariants))
// NOTE: Any module instantiated in the module manager that is later modified
// must be passed by reference here.
app.mm = module.NewManager(
@ -328,7 +336,7 @@ func NewSimApp(
vesting.NewAppModule(app.AccountKeeper, app.BankKeeper),
bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper),
capability.NewAppModule(appCodec, *app.CapabilityKeeper),
crisis.NewAppModule(&app.CrisisKeeper),
crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants),
gov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper),
mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper),
slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),

View File

@ -14,7 +14,7 @@ import (
func TestSimAppExport(t *testing.T) {
db := dbm.NewMemDB()
app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, MakeTestEncodingConfig())
app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, MakeTestEncodingConfig(), EmptyAppOptions{})
genesisState := NewDefaultGenesisState()
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
@ -30,7 +30,7 @@ func TestSimAppExport(t *testing.T) {
app.Commit()
// Making a new app object with the db, so that initchain hasn't been called
app2 := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, MakeTestEncodingConfig())
app2 := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, MakeTestEncodingConfig(), EmptyAppOptions{})
_, err = app2.ExportAppStateAndValidators(false, []string{})
require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
}
@ -38,7 +38,7 @@ func TestSimAppExport(t *testing.T) {
// ensure that blocked addresses are properly set in bank keeper
func TestBlockedAddrs(t *testing.T) {
db := dbm.NewMemDB()
app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, MakeTestEncodingConfig())
app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, MakeTestEncodingConfig(), EmptyAppOptions{})
for acc := range maccPerms {
require.Equal(t, !allowedReceivingModAcc[acc], app.BankKeeper.BlockedAddr(app.AccountKeeper.GetModuleAddress(acc)))

View File

@ -27,7 +27,7 @@ func BenchmarkFullAppSimulation(b *testing.B) {
}
}()
app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), interBlockCacheOpt())
app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), EmptyAppOptions{}, interBlockCacheOpt())
// run randomized simulation
_, simParams, simErr := simulation.SimulateFromSeed(
@ -72,7 +72,7 @@ func BenchmarkInvariants(b *testing.B) {
}
}()
app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), interBlockCacheOpt())
app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), EmptyAppOptions{}, interBlockCacheOpt())
// run randomized simulation
_, simParams, simErr := simulation.SimulateFromSeed(

View File

@ -68,7 +68,7 @@ func TestFullAppSimulation(t *testing.T) {
require.NoError(t, os.RemoveAll(dir))
}()
app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), fauxMerkleModeOpt)
app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), EmptyAppOptions{}, fauxMerkleModeOpt)
require.Equal(t, "SimApp", app.Name())
// run randomized simulation
@ -106,7 +106,7 @@ func TestAppImportExport(t *testing.T) {
require.NoError(t, os.RemoveAll(dir))
}()
app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), fauxMerkleModeOpt)
app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), EmptyAppOptions{}, fauxMerkleModeOpt)
require.Equal(t, "SimApp", app.Name())
// Run randomized simulation
@ -146,7 +146,7 @@ func TestAppImportExport(t *testing.T) {
require.NoError(t, os.RemoveAll(newDir))
}()
newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), fauxMerkleModeOpt)
newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), EmptyAppOptions{}, fauxMerkleModeOpt)
require.Equal(t, "SimApp", newApp.Name())
var genesisState GenesisState
@ -203,7 +203,7 @@ func TestAppSimulationAfterImport(t *testing.T) {
require.NoError(t, os.RemoveAll(dir))
}()
app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), fauxMerkleModeOpt)
app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), EmptyAppOptions{}, fauxMerkleModeOpt)
require.Equal(t, "SimApp", app.Name())
// Run randomized simulation
@ -248,7 +248,7 @@ func TestAppSimulationAfterImport(t *testing.T) {
require.NoError(t, os.RemoveAll(newDir))
}()
newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), fauxMerkleModeOpt)
newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), EmptyAppOptions{}, fauxMerkleModeOpt)
require.Equal(t, "SimApp", newApp.Name())
newApp.InitChain(abci.RequestInitChain{
@ -299,7 +299,7 @@ func TestAppStateDeterminism(t *testing.T) {
}
db := dbm.NewMemDB()
app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), interBlockCacheOpt())
app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), EmptyAppOptions{}, interBlockCacheOpt())
fmt.Printf(
"running non-determinism simulation; seed %d: %d/%d, attempt: %d/%d\n",

View File

@ -6,10 +6,6 @@ import (
"os"
"path/filepath"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/cosmos/cosmos-sdk/snapshots"
"github.com/spf13/cast"
"github.com/spf13/cobra"
tmcli "github.com/tendermint/tendermint/libs/cli"
@ -22,9 +18,12 @@ import (
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/client/rpc"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/server"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/cosmos/cosmos-sdk/snapshots"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
@ -32,6 +31,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth/types"
vestingcli "github.com/cosmos/cosmos-sdk/x/auth/vesting/client/cli"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/crisis"
genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
)
@ -74,9 +74,12 @@ func Execute(rootCmd *cobra.Command) error {
// and a Tendermint RPC. This requires the use of a pointer reference when
// getting and setting the client.Context. Ideally, we utilize
// https://github.com/spf13/cobra/pull/1118.
srvCtx := server.NewDefaultContext()
ctx := context.Background()
ctx = context.WithValue(ctx, client.ClientContextKey, &client.Context{})
ctx = context.WithValue(ctx, server.ServerContextKey, server.NewDefaultContext())
ctx = context.WithValue(ctx, server.ServerContextKey, srvCtx)
rootCmd.PersistentFlags().String("log_level", srvCtx.Config.LogLevel, "The logging level in the format of <module>:<level>,...")
executor := tmcli.PrepareBaseCmd(rootCmd, "", simapp.DefaultNodeHome)
return executor.ExecuteContext(ctx)
@ -97,7 +100,7 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) {
debug.Cmd(),
)
server.AddCommands(rootCmd, simapp.DefaultNodeHome, newApp, createSimappAndExport)
server.AddCommands(rootCmd, simapp.DefaultNodeHome, newApp, createSimappAndExport, addModuleInitFlags)
// add keybase, auxiliary RPC, query, and tx child commands
rootCmd.AddCommand(
@ -108,6 +111,10 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) {
)
}
func addModuleInitFlags(startCmd *cobra.Command) {
crisis.AddModuleInitFlags(startCmd)
}
func queryCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "query",
@ -192,6 +199,7 @@ func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts serverty
cast.ToString(appOpts.Get(flags.FlagHome)),
cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)),
simapp.MakeTestEncodingConfig(), // Ideally, we would reuse the one created by NewRootCmd.
appOpts,
baseapp.SetPruning(pruningOpts),
baseapp.SetMinGasPrices(cast.ToString(appOpts.Get(server.FlagMinGasPrices))),
baseapp.SetHaltHeight(cast.ToUint64(appOpts.Get(server.FlagHaltHeight))),
@ -210,18 +218,19 @@ func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts serverty
// and exports state.
func createSimappAndExport(
logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailAllowedAddrs []string,
) (servertypes.ExportedApp, error) {
appOpts servertypes.AppOptions) (servertypes.ExportedApp, error) {
encCfg := simapp.MakeTestEncodingConfig() // Ideally, we would reuse the one created by NewRootCmd.
encCfg.Marshaler = codec.NewProtoCodec(encCfg.InterfaceRegistry)
var simApp *simapp.SimApp
if height != -1 {
simApp = simapp.NewSimApp(logger, db, traceStore, false, map[int64]bool{}, "", uint(1), encCfg)
simApp = simapp.NewSimApp(logger, db, traceStore, false, map[int64]bool{}, "", uint(1), encCfg, appOpts)
if err := simApp.LoadHeight(height); err != nil {
return servertypes.ExportedApp{}, err
}
} else {
simApp = simapp.NewSimApp(logger, db, traceStore, true, map[int64]bool{}, "", uint(1), encCfg)
simApp = simapp.NewSimApp(logger, db, traceStore, true, map[int64]bool{}, "", uint(1), encCfg, appOpts)
}
return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs)

View File

@ -51,7 +51,7 @@ var DefaultConsensusParams = &abci.ConsensusParams{
// Setup initializes a new SimApp. A Nop logger is set in SimApp.
func Setup(isCheckTx bool) *SimApp {
db := dbm.NewMemDB()
app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 5, MakeTestEncodingConfig())
app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 5, MakeTestEncodingConfig(), EmptyAppOptions{})
if !isCheckTx {
// init chain must be called to stop deliverState from being nil
genesisState := NewDefaultGenesisState()
@ -79,8 +79,7 @@ func Setup(isCheckTx bool) *SimApp {
// account. A Nop logger is set in SimApp.
func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *SimApp {
db := dbm.NewMemDB()
app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 5, MakeTestEncodingConfig())
app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 5, MakeTestEncodingConfig(), EmptyAppOptions{})
genesisState := NewDefaultGenesisState()
// set genesis accounts
@ -160,7 +159,7 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs
// accounts and possible balances.
func SetupWithGenesisAccounts(genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *SimApp {
db := dbm.NewMemDB()
app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, MakeTestEncodingConfig())
app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, MakeTestEncodingConfig(), EmptyAppOptions{})
// initialize the chain with the passed in genesis accounts
genesisState := NewDefaultGenesisState()
@ -435,3 +434,11 @@ func NewPubKeyFromHex(pk string) (res crypto.PubKey) {
}
return &ed25519.PubKey{Key: pkBytes}
}
// EmptyAppOptions is a stub implementing AppOptions
type EmptyAppOptions struct{}
// Get implements AppOptions
func (ao EmptyAppOptions) Get(o string) interface{} {
return nil
}

View File

@ -59,6 +59,7 @@ func NewAppConstructor(encodingCfg params.EncodingConfig) AppConstructor {
return simapp.NewSimApp(
val.Ctx.Logger, dbm.NewMemDB(), nil, true, make(map[int64]bool), val.Ctx.Config.RootDir, 0,
encodingCfg,
simapp.EmptyAppOptions{},
baseapp.SetPruning(storetypes.NewPruningOptionsFromString(val.AppConfig.Pruning)),
baseapp.SetMinGasPrices(val.AppConfig.MinGasPrices),
)

View File

@ -11,6 +11,7 @@ message PublicKey {
option (gogoproto.equal) = true;
oneof sum {
bytes ed25519 = 1;
bytes ed25519 = 1;
bytes secp256k1 = 2;
}
}

View File

@ -4,19 +4,9 @@ package tendermint.types;
option go_package = "github.com/tendermint/tendermint/proto/tendermint/types";
import "gogoproto/gogo.proto";
import "google/protobuf/timestamp.proto";
import "tendermint/types/types.proto";
// DuplicateVoteEvidence contains evidence a validator signed two conflicting
// votes.
message DuplicateVoteEvidence {
Vote vote_a = 1;
Vote vote_b = 2;
}
message LightClientAttackEvidence {
LightBlock conflicting_block = 1;
int64 common_height = 2;
}
import "tendermint/types/validator.proto";
message Evidence {
oneof sum {
@ -25,7 +15,24 @@ message Evidence {
}
}
// EvidenceData contains any evidence of malicious wrong-doing by validators
message EvidenceData {
// DuplicateVoteEvidence contains evidence of a validator signed two conflicting votes.
message DuplicateVoteEvidence {
tendermint.types.Vote vote_a = 1;
tendermint.types.Vote vote_b = 2;
int64 total_voting_power = 3;
int64 validator_power = 4;
google.protobuf.Timestamp timestamp = 5 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
}
// LightClientAttackEvidence contains evidence of a set of validators attempting to mislead a light client.
message LightClientAttackEvidence {
tendermint.types.LightBlock conflicting_block = 1;
int64 common_height = 2;
repeated tendermint.types.Validator byzantine_validators = 3;
int64 total_voting_power = 4;
google.protobuf.Timestamp timestamp = 5 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
}
message EvidenceList {
repeated Evidence evidence = 1 [(gogoproto.nullable) = false];
}

View File

@ -92,7 +92,7 @@ func (t *Tx) ValidateBasic() error {
if len(sigs) != len(t.GetSigners()) {
return sdkerrors.Wrapf(
sdkerrors.ErrUnauthorized,
"wrong number of signers; expected %d, got %d", t.GetSigners(), len(sigs),
"wrong number of signers; expected %d, got %d", len(t.GetSigners()), len(sigs),
)
}

View File

@ -1,26 +0,0 @@
package cli
import (
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/x/auth/types"
)
// GetTxCmd returns the transaction commands for this module
func GetTxCmd() *cobra.Command {
txCmd := &cobra.Command{
Use: types.ModuleName,
Short: "Auth transaction subcommands",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
txCmd.AddCommand(
GetMultiSignCommand(),
GetSignCommand(),
GetValidateSignaturesCommand(),
GetSignBatchCommand(),
)
return txCmd
}

View File

@ -72,7 +72,7 @@ func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *r
// GetTxCmd returns the root tx command for the auth module.
func (AppModuleBasic) GetTxCmd() *cobra.Command {
return cli.GetTxCmd()
return nil
}
// GetQueryCmd returns the root query command for the auth module.

View File

@ -20,10 +20,6 @@ func (k BaseKeeper) InitGenesis(ctx sdk.Context, genState types.GenesisState) {
panic(err)
}
if err := k.ValidateBalance(ctx, addr); err != nil {
panic(err)
}
if err := k.SetBalances(ctx, addr, balance.Coins); err != nil {
panic(fmt.Errorf("error on setting balances %w", err))
}

View File

@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"math/rand"
"time"
"github.com/gorilla/mux"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
@ -14,6 +15,7 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
@ -133,9 +135,11 @@ func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sd
// InitGenesis performs genesis initialization for the bank module. It returns
// no validator updates.
func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate {
start := time.Now()
var genesisState types.GenesisState
cdc.MustUnmarshalJSON(data, &genesisState)
telemetry.MeasureSince(start, "InitGenesis", "crisis", "unmarshal")
am.keeper.InitGenesis(ctx, genesisState)
return []abci.ValidatorUpdate{}
}

View File

@ -27,7 +27,7 @@ var (
func createTestApp() (*simapp.SimApp, sdk.Context, []sdk.AccAddress) {
db := dbm.NewMemDB()
app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 1, simapp.MakeTestEncodingConfig())
app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 1, simapp.MakeTestEncodingConfig(), simapp.EmptyAppOptions{})
ctx := app.NewContext(true, tmproto.Header{})
constantFee := sdk.NewInt64Coin(sdk.DefaultBondDenom, 10)

View File

@ -58,7 +58,7 @@ func (k Keeper) Routes() []types.InvarRoute {
return k.routes
}
// Invariants returns all the registered Crisis keeper invariants.
// Invariants returns a copy of all registered Crisis keeper invariants.
func (k Keeper) Invariants() []sdk.Invariant {
invars := make([]sdk.Invariant, len(k.routes))
for i, route := range k.routes {
@ -74,8 +74,9 @@ func (k Keeper) AssertInvariants(ctx sdk.Context) {
start := time.Now()
invarRoutes := k.Routes()
for _, ir := range invarRoutes {
n := len(invarRoutes)
for i, ir := range invarRoutes {
logger.Debug("Asserting cirisis invariants", "inv", fmt.Sprint(i, "/", n))
if res, stop := ir.Invar(ctx); stop {
// TODO: Include app name as part of context to allow for this to be
// variable.
@ -85,9 +86,7 @@ func (k Keeper) AssertInvariants(ctx sdk.Context) {
}
}
end := time.Now()
diff := end.Sub(start)
diff := time.Since(start)
logger.Info("asserted all invariants", "duration", diff, "height", ctx.BlockHeight())
}

View File

@ -3,6 +3,7 @@ package crisis
import (
"encoding/json"
"fmt"
"time"
"github.com/gorilla/mux"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
@ -12,6 +13,7 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/crisis/client/cli"
@ -24,6 +26,11 @@ var (
_ module.AppModuleBasic = AppModuleBasic{}
)
// Module init related flags
const (
FlagSkipGenesisInvariants = "x-crisis-skip-assert-invariants"
)
// AppModuleBasic defines the basic application module used by the crisis module.
type AppModuleBasic struct{}
@ -83,16 +90,28 @@ type AppModule struct {
// manager is created, the invariants can be properly registered and
// executed.
keeper *keeper.Keeper
skipGenesisInvariants bool
}
// NewAppModule creates a new AppModule object
func NewAppModule(keeper *keeper.Keeper) AppModule {
// NewAppModule creates a new AppModule object. If initChainAssertInvariants is set,
// we will call keeper.AssertInvariants during InitGenesis (it may take a significant time)
// - which doesn't impact the chain security unless 66+% of validators have a wrongly
// modified genesis file.
func NewAppModule(keeper *keeper.Keeper, skipGenesisInvariants bool) AppModule {
return AppModule{
AppModuleBasic: AppModuleBasic{},
keeper: keeper,
skipGenesisInvariants: skipGenesisInvariants,
}
}
// AddModuleInitFlags implements servertypes.ModuleInitFlags interface.
func AddModuleInitFlags(startCmd *cobra.Command) {
startCmd.Flags().Bool(FlagSkipGenesisInvariants, false, "Skip x/crisis invariants check on startup")
}
// Name returns the crisis module's name.
func (AppModule) Name() string {
return types.ModuleName
@ -120,10 +139,15 @@ func (am AppModule) RegisterServices(cfg module.Configurator) {
// InitGenesis performs genesis initialization for the crisis module. It returns
// no validator updates.
func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate {
start := time.Now()
var genesisState types.GenesisState
cdc.MustUnmarshalJSON(data, &genesisState)
telemetry.MeasureSince(start, "InitGenesis", "crisis", "unmarshal")
am.keeper.InitGenesis(ctx, &genesisState)
am.keeper.AssertInvariants(ctx)
if !am.skipGenesisInvariants {
am.keeper.AssertInvariants(ctx)
}
return []abci.ValidatorUpdate{}
}

View File

@ -68,7 +68,7 @@ func TestImportExportQueues(t *testing.T) {
}
db := dbm.NewMemDB()
app2 := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 0, simapp.MakeTestEncodingConfig())
app2 := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 0, simapp.MakeTestEncodingConfig(), simapp.EmptyAppOptions{})
app2.InitChain(
abci.RequestInitChain{

View File

@ -1,6 +1,8 @@
package types
import (
"strings"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types"
@ -42,6 +44,8 @@ func (MsgTransfer) Type() string {
// ValidateBasic performs a basic check of the MsgTransfer fields.
// NOTE: timeout height or timestamp values can be 0 to disable the timeout.
// NOTE: The recipient addresses format is not validated as the format defined by
// the chain is not known to IBC.
func (msg MsgTransfer) ValidateBasic() error {
if err := host.PortIdentifierValidator(msg.SourcePort); err != nil {
return sdkerrors.Wrap(err, "invalid source port ID")
@ -55,10 +59,12 @@ func (msg MsgTransfer) ValidateBasic() error {
if !msg.Token.IsPositive() {
return sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, msg.Token.String())
}
if msg.Sender == "" {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "missing sender address")
// NOTE: sender format must be validated as it is required by the GetSigners function.
_, err := sdk.AccAddressFromBech32(msg.Sender)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err)
}
if msg.Receiver == "" {
if strings.TrimSpace(msg.Receiver) == "" {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "missing recipient address")
}
return ValidateIBCDenom(msg.Token.Denom)

View File

@ -34,7 +34,9 @@ func NewFungibleTokenPacketData(
}
}
// ValidateBasic is used for validating the token transfer
// ValidateBasic is used for validating the token transfer.
// NOTE: The addresses formats are not validated as the sender and recipient can have different
// formats defined by their corresponding chains that are not known to IBC.
func (ftpd FungibleTokenPacketData) ValidateBasic() error {
if ftpd.Amount == 0 {
return sdkerrors.Wrap(ErrInvalidAmount, "amount cannot be 0")

View File

@ -156,22 +156,6 @@ func (k Keeper) GetLatestClientConsensusState(ctx sdk.Context, clientID string)
return k.GetClientConsensusState(ctx, clientID, clientState.GetLatestHeight())
}
// GetClientConsensusStateLTE will get the latest ConsensusState of a particular client at the latest height
// less than or equal to the given height
// It will only search for heights within the same version
func (k Keeper) GetClientConsensusStateLTE(ctx sdk.Context, clientID string, maxHeight exported.Height) (exported.ConsensusState, bool) {
h := maxHeight
ok := true
for ok {
found := k.HasClientConsensusState(ctx, clientID, h)
if found {
return k.GetClientConsensusState(ctx, clientID, h)
}
h, ok = h.Decrement()
}
return nil, false
}
// GetSelfConsensusState introspects the (self) past historical info at a given height
// and returns the expected consensus state at that height.
// For now, can only retrieve self consensus states for the current version

View File

@ -340,11 +340,6 @@ func (suite KeeperTestSuite) TestConsensusStateHelpers() {
latest, ok := suite.keeper.GetLatestClientConsensusState(suite.ctx, testClientID)
suite.Require().True(ok)
suite.Require().Equal(nextState, latest, "Latest client not returned correctly")
// Should return existing consensusState at latestClientHeight
lte, ok := suite.keeper.GetClientConsensusStateLTE(suite.ctx, testClientID, types.NewHeight(0, height+3))
suite.Require().True(ok)
suite.Require().Equal(suite.consensusState, lte, "LTE helper function did not return latest client state below height: %d", height+3)
}
// 2 clients in total are created on chainA. The first client is updated so it contains an initial consensus state

View File

@ -64,8 +64,9 @@ func (msg MsgCreateClient) Type() string {
// ValidateBasic implements sdk.Msg
func (msg MsgCreateClient) ValidateBasic() error {
if msg.Signer == "" {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "signer address cannot be empty")
_, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err)
}
clientState, err := UnpackClientState(msg.ClientState)
if err != nil {
@ -141,8 +142,9 @@ func (msg MsgUpdateClient) Type() string {
// ValidateBasic implements sdk.Msg
func (msg MsgUpdateClient) ValidateBasic() error {
if msg.Signer == "" {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "signer address cannot be empty")
_, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err)
}
header, err := UnpackHeader(msg.Header)
if err != nil {
@ -281,8 +283,9 @@ func (msg MsgSubmitMisbehaviour) Type() string {
// ValidateBasic performs basic (non-state-dependant) validation on a MsgSubmitMisbehaviour.
func (msg MsgSubmitMisbehaviour) ValidateBasic() error {
if msg.Signer == "" {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "signer address cannot be empty")
_, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err)
}
misbehaviour, err := UnpackMisbehaviour(msg.Misbehaviour)
if err != nil {

View File

@ -22,13 +22,8 @@ func (k Keeper) VerifyClientState(
return sdkerrors.Wrap(clienttypes.ErrClientNotFound, clientID)
}
targetConsState, found := k.clientKeeper.GetClientConsensusState(ctx, clientID, height)
if !found {
return sdkerrors.Wrapf(clienttypes.ErrConsensusStateNotFound, "clientID: %s with height: %s", clientID, height)
}
if err := targetClient.VerifyClientState(
k.clientKeeper.ClientStore(ctx, clientID), k.cdc, targetConsState.GetRoot(), height,
k.clientKeeper.ClientStore(ctx, clientID), k.cdc, height,
connection.GetCounterparty().GetPrefix(), connection.GetCounterparty().GetClientID(), proof, clientState); err != nil {
return sdkerrors.Wrapf(err, "failed client state verification for target client: %s", connection.GetClientID())
}
@ -52,13 +47,8 @@ func (k Keeper) VerifyClientConsensusState(
return sdkerrors.Wrap(clienttypes.ErrClientNotFound, clientID)
}
targetConsState, found := k.clientKeeper.GetClientConsensusState(ctx, clientID, height)
if !found {
return sdkerrors.Wrapf(clienttypes.ErrConsensusStateNotFound, "clientID: %s with height: %s", clientID, height)
}
if err := clientState.VerifyClientConsensusState(
k.clientKeeper.ClientStore(ctx, clientID), k.cdc, targetConsState.GetRoot(), height,
k.clientKeeper.ClientStore(ctx, clientID), k.cdc, height,
connection.GetCounterparty().GetClientID(), consensusHeight, connection.GetCounterparty().GetPrefix(), proof, consensusState,
); err != nil {
return sdkerrors.Wrapf(err, "failed consensus state verification for client (%s)", connection.GetClientID())

View File

@ -11,6 +11,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/ibc/core/exported"
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/07-tendermint/types"
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
ibcmock "github.com/cosmos/cosmos-sdk/x/ibc/testing/mock"
)
var defaultTimeoutHeight = clienttypes.NewHeight(0, 100000)
@ -336,16 +337,13 @@ func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgement() {
err := suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.Require().NoError(err)
err = suite.coordinator.WriteReceipt(suite.chainB, suite.chainA, packet, clientA)
suite.Require().NoError(err)
err = suite.coordinator.WriteAcknowledgement(suite.chainB, suite.chainA, packet, clientA)
err = suite.coordinator.RecvPacket(suite.chainA, suite.chainB, clientA, packet)
suite.Require().NoError(err)
packetAckKey := host.KeyPacketAcknowledgement(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
proof, proofHeight := suite.chainB.QueryProof(packetAckKey)
ack := ibctesting.TestHash
ack := ibcmock.MockAcknowledgement
if tc.changeAcknowledgement {
ack = []byte(ibctesting.InvalidID)
}
@ -399,7 +397,7 @@ func (suite *KeeperTestSuite) TestVerifyPacketReceiptAbsence() {
suite.Require().NoError(err)
if tc.recvAck {
err = suite.coordinator.WriteReceipt(suite.chainB, suite.chainA, packet, clientA)
err = suite.coordinator.RecvPacket(suite.chainA, suite.chainB, clientA, packet)
suite.Require().NoError(err)
} else {
// need to update height to prove absence
@ -458,7 +456,7 @@ func (suite *KeeperTestSuite) TestVerifyNextSequenceRecv() {
err := suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.Require().NoError(err)
err = suite.coordinator.WriteReceipt(suite.chainB, suite.chainA, packet, clientA)
err = suite.coordinator.RecvPacket(suite.chainA, suite.chainB, clientA, packet)
suite.Require().NoError(err)
nextSeqRecvKey := host.KeyNextSequenceRecv(packet.GetDestPort(), packet.GetDestChannel())

View File

@ -53,8 +53,9 @@ func (msg MsgConnectionOpenInit) ValidateBasic() error {
return sdkerrors.Wrap(err, "basic validation of the provided version failed")
}
}
if msg.Signer == "" {
return sdkerrors.ErrInvalidAddress
_, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err)
}
return msg.Counterparty.ValidateBasic()
}
@ -157,8 +158,9 @@ func (msg MsgConnectionOpenTry) ValidateBasic() error {
if msg.ConsensusHeight.IsZero() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidHeight, "consensus height must be non-zero")
}
if msg.Signer == "" {
return sdkerrors.ErrInvalidAddress
_, err = sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err)
}
return msg.Counterparty.ValidateBasic()
}
@ -266,8 +268,9 @@ func (msg MsgConnectionOpenAck) ValidateBasic() error {
if msg.ConsensusHeight.IsZero() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidHeight, "consensus height must be non-zero")
}
if msg.Signer == "" {
return sdkerrors.ErrInvalidAddress
_, err = sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err)
}
return nil
}
@ -324,8 +327,9 @@ func (msg MsgConnectionOpenConfirm) ValidateBasic() error {
if msg.ProofHeight.IsZero() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidHeight, "proof height must be non-zero")
}
if msg.Signer == "" {
return sdkerrors.ErrInvalidAddress
_, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err)
}
return nil
}

View File

@ -14,18 +14,22 @@ import (
// CounterpartyHops returns the connection hops of the counterparty channel.
// The counterparty hops are stored in the inverse order as the channel's.
// NOTE: Since connectionHops only supports single connection channels for now,
// this function requires that connection hops only contain a single connection id
func (k Keeper) CounterpartyHops(ctx sdk.Context, ch types.Channel) ([]string, bool) {
counterPartyHops := make([]string, len(ch.ConnectionHops))
for i, hop := range ch.ConnectionHops {
conn, found := k.connectionKeeper.GetConnection(ctx, hop)
if !found {
return []string{}, false
}
counterPartyHops[len(counterPartyHops)-1-i] = conn.GetCounterparty().GetConnectionID()
// Return empty array if connection hops is more than one
// ConnectionHops length should be verified earlier
if len(ch.ConnectionHops) != 1 {
return []string{}, false
}
counterPartyHops := make([]string, 1)
hop := ch.ConnectionHops[0]
conn, found := k.connectionKeeper.GetConnection(ctx, hop)
if !found {
return []string{}, false
}
counterPartyHops[0] = conn.GetCounterparty().GetConnectionID()
return counterPartyHops, true
}

View File

@ -137,6 +137,7 @@ func (k Keeper) SendPacket(
// sent on the corresponding channel end on the counterparty chain.
func (k Keeper) RecvPacket(
ctx sdk.Context,
chanCap *capabilitytypes.Capability,
packet exported.PacketI,
proof []byte,
proofHeight exported.Height,
@ -153,8 +154,14 @@ func (k Keeper) RecvPacket(
)
}
// NOTE: RecvPacket is called by the AnteHandler which acts upon the packet.Route(),
// so the capability authentication can be omitted here
// Authenticate capability to ensure caller has authority to receive packet on this channel
capName := host.ChannelCapabilityPath(packet.GetDestPort(), packet.GetDestChannel())
if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, capName) {
return sdkerrors.Wrapf(
types.ErrInvalidChannelCapability,
"channel capability failed authentication for capability name %s", capName,
)
}
// packet must come from the channel's counterparty
if packet.GetSourcePort() != channel.Counterparty.PortId {
@ -171,6 +178,9 @@ func (k Keeper) RecvPacket(
)
}
// Connection must be OPEN to receive a packet. It is possible for connection to not yet be open if packet was
// sent optimistically before connection and channel handshake completed. However, to receive a packet,
// connection and channel must both be open
connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0])
if !found {
return sdkerrors.Wrap(connectiontypes.ErrConnectionNotFound, channel.ConnectionHops[0])
@ -201,6 +211,15 @@ func (k Keeper) RecvPacket(
)
}
// verify that the counterparty did commit to sending this packet
if err := k.connectionKeeper.VerifyPacketCommitment(
ctx, connectionEnd, proofHeight, proof,
packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(),
types.CommitPacket(packet),
); err != nil {
return sdkerrors.Wrap(err, "couldn't verify counterparty packet commitment")
}
switch channel.Ordering {
case types.UNORDERED:
// check if the packet receipt has been received already for unordered channels
@ -212,6 +231,12 @@ func (k Keeper) RecvPacket(
)
}
// All verification complete, update state
// For unordered channels we must set the receipt so it can be verified on the other side.
// This receipt does not contain any data, since the packet has not yet been processed,
// it's just a single store key set to an empty string to indicate that the packet has been received
k.SetPacketReceipt(ctx, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
case types.ORDERED:
// check if the packet is being received in order
nextSequenceRecv, found := k.GetNextSequenceRecv(ctx, packet.GetDestPort(), packet.GetDestChannel())
@ -228,79 +253,15 @@ func (k Keeper) RecvPacket(
"packet sequence ≠ next receive sequence (%d ≠ %d)", packet.GetSequence(), nextSequenceRecv,
)
}
}
if err := k.connectionKeeper.VerifyPacketCommitment(
ctx, connectionEnd, proofHeight, proof,
packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(),
types.CommitPacket(packet),
); err != nil {
return sdkerrors.Wrap(err, "couldn't verify counterparty packet commitment")
}
// NOTE: the remaining code is located in the WriteReceipt function
return nil
}
// WriteReceipt updates the receive sequence in the case of an ordered channel or sets an empty receipt
// if the channel is unordered.
//
// CONTRACT: this function must be called in the IBC handler
func (k Keeper) WriteReceipt(
ctx sdk.Context,
chanCap *capabilitytypes.Capability,
packet exported.PacketI,
) error {
channel, found := k.GetChannel(ctx, packet.GetDestPort(), packet.GetDestChannel())
if !found {
return sdkerrors.Wrapf(types.ErrChannelNotFound, packet.GetDestChannel())
}
// sanity check
if channel.State != types.OPEN {
return sdkerrors.Wrapf(
types.ErrInvalidChannelState,
"channel state is not OPEN (got %s)", channel.State.String(),
)
}
capName := host.ChannelCapabilityPath(packet.GetDestPort(), packet.GetDestChannel())
if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, capName) {
return sdkerrors.Wrapf(
types.ErrInvalidChannelCapability,
"channel capability failed authentication for capability name %s", capName,
)
}
switch channel.Ordering {
case types.ORDERED:
nextSequenceRecv, found := k.GetNextSequenceRecv(ctx, packet.GetDestPort(), packet.GetDestChannel())
if !found {
return sdkerrors.Wrapf(
types.ErrSequenceReceiveNotFound,
"destination port: %s, destination channel: %s", packet.GetDestPort(), packet.GetDestChannel(),
)
}
// All verification complete, update state
// In ordered case, we must increment nextSequenceRecv
nextSequenceRecv++
// incrementing nextSequenceRecv and storing under this chain's channelEnd identifiers
// Since this is the receiving chain, our channelEnd is packet's destination port and channel
k.SetNextSequenceRecv(ctx, packet.GetDestPort(), packet.GetDestChannel(), nextSequenceRecv)
case types.UNORDERED:
// For unordered channels we must set the receipt so it can be verified on the other side.
// This receipt does not contain any data, since the packet has not yet been processed,
// it's just a single store key set to an empty string to indicate that the packet has been received
_, found := k.GetPacketReceipt(ctx, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
if found {
return sdkerrors.Wrapf(
types.ErrPacketReceived,
"destination port: %s, destination channel: %s, sequence: %d", packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(),
)
}
k.SetPacketReceipt(ctx, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
}
// log that a packet has been received & executed
@ -338,12 +299,35 @@ func (k Keeper) WriteReceipt(
// For async handling, it needs to be called directly by the module which originally
// processed the packet.
//
// 2) Assumes that packet receipt has been writted previously by WriteReceipt.
// 2) Assumes that packet receipt has been written (unordered), or nextSeqRecv was incremented (ordered)
// previously by RecvPacket.
func (k Keeper) WriteAcknowledgement(
ctx sdk.Context,
chanCap *capabilitytypes.Capability,
packet exported.PacketI,
acknowledgement []byte,
) error {
channel, found := k.GetChannel(ctx, packet.GetDestPort(), packet.GetDestChannel())
if !found {
return sdkerrors.Wrap(types.ErrChannelNotFound, packet.GetDestChannel())
}
if channel.State != types.OPEN {
return sdkerrors.Wrapf(
types.ErrInvalidChannelState,
"channel state is not OPEN (got %s)", channel.State.String(),
)
}
// Authenticate capability to ensure caller has authority to receive packet on this channel
capName := host.ChannelCapabilityPath(packet.GetDestPort(), packet.GetDestChannel())
if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, capName) {
return sdkerrors.Wrapf(
types.ErrInvalidChannelCapability,
"channel capability failed authentication for capability name %s", capName,
)
}
// NOTE: IBC app modules might have written the acknowledgement synchronously on
// the OnRecvPacket callback so we need to check if the acknowledgement is already
// set on the store and return an error if so.
@ -355,14 +339,14 @@ func (k Keeper) WriteAcknowledgement(
return sdkerrors.Wrap(types.ErrInvalidAcknowledgement, "acknowledgement cannot be empty")
}
// always set the acknowledgement so that it can be verified on the other side
// set the acknowledgement so that it can be verified on the other side
k.SetPacketAcknowledgement(
ctx, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(),
types.CommitAcknowledgement(acknowledgement),
)
// log that a packet has been acknowledged
k.Logger(ctx).Info("packet acknowledged", "packet", fmt.Sprintf("%v", packet))
// log that a packet acknowledgement has been written
k.Logger(ctx).Info("acknowledged written", "packet", fmt.Sprintf("%v", packet))
// emit an event that the relayer can query for
ctx.EventManager().EmitEvents(sdk.Events{
@ -390,11 +374,12 @@ func (k Keeper) WriteAcknowledgement(
// AcknowledgePacket is called by a module to process the acknowledgement of a
// packet previously sent by the calling module on a channel to a counterparty
// module on the counterparty chain. Its intended usage is within the ante
// handler. A subsequent call to AcknowledgementExecuted will clean up the
// packet commitment, which is no longer necessary since the packet has been
// received and acted upon.
// handler. AcknowledgePacket will clean up the packet commitment,
// which is no longer necessary since the packet has been received and acted upon.
// It will also increment NextSequenceAck in case of ORDERED channels.
func (k Keeper) AcknowledgePacket(
ctx sdk.Context,
chanCap *capabilitytypes.Capability,
packet exported.PacketI,
acknowledgement []byte,
proof []byte,
@ -415,8 +400,14 @@ func (k Keeper) AcknowledgePacket(
)
}
// NOTE: AcknowledgePacket is called by the AnteHandler which acts upon the packet.Route(),
// so the capability authentication can be omitted here
// Authenticate capability to ensure caller has authority to receive packet on this channel
capName := host.ChannelCapabilityPath(packet.GetSourcePort(), packet.GetSourceChannel())
if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, capName) {
return sdkerrors.Wrapf(
types.ErrInvalidChannelCapability,
"channel capability failed authentication for capability name %s", capName,
)
}
// packet must have been sent to the channel's counterparty
if packet.GetDestPort() != channel.Counterparty.PortId {
@ -475,56 +466,19 @@ func (k Keeper) AcknowledgePacket(
"packet sequence ≠ next ack sequence (%d ≠ %d)", packet.GetSequence(), nextSequenceAck,
)
}
}
// NOTE: the remaining code is located in the AcknowledgementExecuted function
return nil
}
// AcknowledgementExecuted deletes the packet commitment from this chain.
// It is assumed that the acknowledgement verification has already occurred.
//
// CONTRACT: this function must be called in the IBC handler
func (k Keeper) AcknowledgementExecuted(
ctx sdk.Context,
chanCap *capabilitytypes.Capability,
packet exported.PacketI,
) error {
channel, found := k.GetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel())
if !found {
return sdkerrors.Wrapf(
types.ErrChannelNotFound,
"port ID (%s) channel ID (%s)", packet.GetSourcePort(), packet.GetSourceChannel(),
)
}
capName := host.ChannelCapabilityPath(packet.GetSourcePort(), packet.GetSourceChannel())
if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, capName) {
return sdkerrors.Wrapf(
types.ErrInvalidChannelCapability,
"channel capability failed authentication for capability name %s", capName,
)
}
k.deletePacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())
// increment NextSequenceAck
if channel.Ordering == types.ORDERED {
nextSequenceAck, found := k.GetNextSequenceAck(ctx, packet.GetSourcePort(), packet.GetSourceChannel())
if !found {
return sdkerrors.Wrapf(
types.ErrSequenceAckNotFound,
"source port: %s, source channel: %s", packet.GetSourcePort(), packet.GetSourceChannel(),
)
}
// All verification complete, in the case of ORDERED channels we must increment nextSequenceAck
nextSequenceAck++
// incrementing NextSequenceAck and storing under this chain's channelEnd identifiers
// Since this is the original sending chain, our channelEnd is packet's source port and channel
k.SetNextSequenceAck(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), nextSequenceAck)
}
// Delete packet commitment, since the packet has been acknowledged, the commitement is no longer necessary
k.deletePacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())
// log that a packet has been acknowledged
k.Logger(ctx).Info("packet acknowledged", "packet", fmt.Sprintf("%v", packet))

View File

@ -9,6 +9,7 @@ import (
host "github.com/cosmos/cosmos-sdk/x/ibc/core/24-host"
"github.com/cosmos/cosmos-sdk/x/ibc/core/exported"
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
ibcmock "github.com/cosmos/cosmos-sdk/x/ibc/testing/mock"
)
var (
@ -179,7 +180,8 @@ func (suite *KeeperTestSuite) TestSendPacket() {
// verification tests need to simulate sending a packet from chainA to chainB.
func (suite *KeeperTestSuite) TestRecvPacket() {
var (
packet exported.PacketI
packet exported.PacketI
channelCap *capabilitytypes.Capability
)
testCases := []testCase{
@ -188,6 +190,7 @@ func (suite *KeeperTestSuite) TestRecvPacket() {
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
err := suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.Require().NoError(err)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, true},
{"success UNORDERED channel", func() {
// setup uses an UNORDERED channel
@ -195,6 +198,7 @@ func (suite *KeeperTestSuite) TestRecvPacket() {
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
err := suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.Require().NoError(err)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, true},
{"success with out of order packet: UNORDERED channel", func() {
// setup uses an UNORDERED channel
@ -209,6 +213,7 @@ func (suite *KeeperTestSuite) TestRecvPacket() {
err = suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.Require().NoError(err)
// attempts to receive packet 2 without receiving packet 1
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, true},
{"out of order packet failure with ORDERED channel", func() {
_, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.ORDERED)
@ -222,11 +227,13 @@ func (suite *KeeperTestSuite) TestRecvPacket() {
err = suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.Require().NoError(err)
// attempts to receive packet 2 without receiving packet 1
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
{"channel not found", func() {
// use wrong channel naming
_, _, _, _, channelA, _ := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, ibctesting.InvalidID, ibctesting.InvalidID, timeoutHeight, disabledTimeoutTimestamp)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
{"channel not open", func() {
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
@ -234,16 +241,26 @@ func (suite *KeeperTestSuite) TestRecvPacket() {
err := suite.coordinator.SetChannelClosed(suite.chainB, suite.chainA, channelB)
suite.Require().NoError(err)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
{"capability cannot authenticate", func() {
_, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.ORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
err := suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.Require().NoError(err)
channelCap = capabilitytypes.NewCapability(3)
}, false},
{"packet source port ≠ channel counterparty port", func() {
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
// use wrong port for dest
packet = types.NewPacket(validPacketData, 1, ibctesting.InvalidID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
{"packet source channel ID ≠ channel counterparty channel ID", func() {
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
// use wrong port for dest
packet = types.NewPacket(validPacketData, 1, channelA.PortID, ibctesting.InvalidID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
{"connection not found", func() {
channelA := ibctesting.TestChannel{PortID: portID, ID: channelIDA}
@ -255,6 +272,8 @@ func (suite *KeeperTestSuite) TestRecvPacket() {
types.NewChannel(types.OPEN, types.ORDERED, types.NewCounterparty(channelA.PortID, channelA.ID), []string{connIDB}, channelB.Version),
)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
suite.chainB.CreateChannelCapability(channelB.PortID, channelB.ID)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
{"connection not OPEN", func() {
clientA, clientB := suite.coordinator.SetupClients(suite.chainA, suite.chainB, ibctesting.Tendermint)
@ -271,14 +290,18 @@ func (suite *KeeperTestSuite) TestRecvPacket() {
types.NewChannel(types.OPEN, types.ORDERED, types.NewCounterparty(channelA.PortID, channelA.ID), []string{connB.ID}, channelB.Version),
)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
suite.chainB.CreateChannelCapability(channelB.PortID, channelB.ID)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
{"timeout height passed", func() {
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, clienttypes.GetSelfHeight(suite.chainB.GetContext()), disabledTimeoutTimestamp)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
{"timeout timestamp passed", func() {
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, disabledTimeoutHeight, uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
{"next receive sequence is not found", func() {
_, _, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, ibctesting.Tendermint)
@ -296,11 +319,22 @@ func (suite *KeeperTestSuite) TestRecvPacket() {
// manually set packet commitment
suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainA.GetContext(), channelA.PortID, channelA.ID, packet.GetSequence(), ibctesting.TestHash)
suite.chainB.CreateChannelCapability(channelB.PortID, channelB.ID)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
{"receipt already stored", func() {
_, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketReceipt(suite.chainB.GetContext(), channelB.PortID, channelB.ID, 1)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
{"validation failed", func() {
// packet commitment not set resulting in invalid proof
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
}
@ -314,10 +348,24 @@ func (suite *KeeperTestSuite) TestRecvPacket() {
packetKey := host.KeyPacketCommitment(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())
proof, proofHeight := suite.chainA.QueryProof(packetKey)
err := suite.chainB.App.IBCKeeper.ChannelKeeper.RecvPacket(suite.chainB.GetContext(), packet, proof, proofHeight)
err := suite.chainB.App.IBCKeeper.ChannelKeeper.RecvPacket(suite.chainB.GetContext(), channelCap, packet, proof, proofHeight)
if tc.expPass {
suite.Require().NoError(err)
channelB, _ := suite.chainB.App.IBCKeeper.ChannelKeeper.GetChannel(suite.chainB.GetContext(), packet.GetDestPort(), packet.GetDestChannel())
nextSeqRecv, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetNextSequenceRecv(suite.chainB.GetContext(), packet.GetDestPort(), packet.GetDestChannel())
suite.Require().True(found)
receipt, receiptStored := suite.chainB.App.IBCKeeper.ChannelKeeper.GetPacketReceipt(suite.chainB.GetContext(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
if channelB.Ordering == types.ORDERED {
suite.Require().Equal(packet.GetSequence()+1, nextSeqRecv, "sequence not incremented in ordered channel")
suite.Require().False(receiptStored, "packet receipt stored on ORDERED channel")
} else {
suite.Require().Equal(uint64(1), nextSeqRecv, "sequence incremented for UNORDERED channel")
suite.Require().True(receiptStored, "packet receipt not stored after RecvPacket in UNORDERED channel")
suite.Require().Equal("", receipt, "packet receipt is not empty string")
}
} else {
suite.Require().Error(err)
}
@ -326,92 +374,11 @@ func (suite *KeeperTestSuite) TestRecvPacket() {
}
// TestWriteReceipt tests the WriteReceipt call on chainB.
func (suite *KeeperTestSuite) TestWriteReceipt() {
var (
packet types.Packet
channelCap *capabilitytypes.Capability
)
testCases := []testCase{
{"success: UNORDERED", func() {
// setup uses an UNORDERED channel
_, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, true},
{"success: ORDERED", func() {
_, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.ORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, true},
{"channel not found", func() {
// use wrong channel naming
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, ibctesting.InvalidID, ibctesting.InvalidID, timeoutHeight, disabledTimeoutTimestamp)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
{"channel not OPEN", func() {
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
err := suite.coordinator.SetChannelClosed(suite.chainB, suite.chainA, channelB)
suite.Require().NoError(err)
}, false},
{"next sequence receive not found", func() {
_, _, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, ibctesting.Tendermint)
channelA := connA.NextTestChannel(ibctesting.TransferPort)
channelB := connB.NextTestChannel(ibctesting.TransferPort)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
// manually creating channel prevents next sequence receive from being set
suite.chainB.App.IBCKeeper.ChannelKeeper.SetChannel(
suite.chainB.GetContext(),
channelB.PortID, channelB.ID,
types.NewChannel(types.OPEN, types.ORDERED, types.NewCounterparty(channelA.PortID, channelA.ID), []string{connB.ID}, channelB.Version),
)
suite.chainB.CreateChannelCapability(channelB.PortID, channelB.ID)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
{"capability not found", func() {
_, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.ORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
channelCap = capabilitytypes.NewCapability(3)
}, false},
{"receipt already stored", func() {
_, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketReceipt(suite.chainB.GetContext(), channelB.PortID, channelB.ID, 1)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
}
for i, tc := range testCases {
tc := tc
suite.Run(fmt.Sprintf("Case %s, %d/%d tests", tc.msg, i, len(testCases)), func() {
suite.SetupTest() // reset
tc.malleate()
err := suite.chainB.App.IBCKeeper.ChannelKeeper.WriteReceipt(suite.chainB.GetContext(), channelCap, packet)
if tc.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *KeeperTestSuite) TestWriteAcknowledgement() {
var (
ack []byte
packet exported.PacketI
ack []byte
packet exported.PacketI
channelCap *capabilitytypes.Capability
)
testCases := []testCase{
@ -421,9 +388,36 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() {
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
ack = ibctesting.TestHash
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
},
true,
},
{"channel not found", func() {
// use wrong channel naming
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, ibctesting.InvalidID, ibctesting.InvalidID, timeoutHeight, disabledTimeoutTimestamp)
ack = ibctesting.TestHash
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
{"channel not open", func() {
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
ack = ibctesting.TestHash
err := suite.coordinator.SetChannelClosed(suite.chainB, suite.chainA, channelB)
suite.Require().NoError(err)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
{
"capability authentication failed",
func() {
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
ack = ibctesting.TestHash
channelCap = capabilitytypes.NewCapability(3)
},
false,
},
{
"no-op, already acked",
func() {
@ -431,6 +425,7 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() {
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
ack = ibctesting.TestHash
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(suite.chainB.GetContext(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), ack)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
},
false,
},
@ -440,6 +435,7 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() {
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
ack = nil
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
},
false,
},
@ -451,7 +447,7 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() {
tc.malleate()
err := suite.chainB.App.IBCKeeper.ChannelKeeper.WriteAcknowledgement(suite.chainB.GetContext(), packet, ack)
err := suite.chainB.App.IBCKeeper.ChannelKeeper.WriteAcknowledgement(suite.chainB.GetContext(), channelCap, packet, ack)
if tc.expPass {
suite.Require().NoError(err)
@ -466,7 +462,9 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() {
func (suite *KeeperTestSuite) TestAcknowledgePacket() {
var (
packet types.Packet
ack = ibctesting.TestHash
ack = ibcmock.MockAcknowledgement
channelCap *capabilitytypes.Capability
)
testCases := []testCase{
@ -478,11 +476,10 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() {
suite.Require().NoError(err)
// create packet receipt and acknowledgement
err = suite.coordinator.WriteReceipt(suite.chainB, suite.chainA, packet, clientA)
err = suite.coordinator.RecvPacket(suite.chainA, suite.chainB, clientA, packet)
suite.Require().NoError(err)
err = suite.coordinator.WriteAcknowledgement(suite.chainB, suite.chainA, packet, clientA)
suite.Require().NoError(err)
channelCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, true},
{"success on unordered channel", func() {
// setup uses an UNORDERED channel
@ -494,11 +491,10 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() {
suite.Require().NoError(err)
// create packet receipt and acknowledgement
err = suite.coordinator.WriteReceipt(suite.chainB, suite.chainA, packet, clientA)
err = suite.coordinator.RecvPacket(suite.chainA, suite.chainB, clientA, packet)
suite.Require().NoError(err)
err = suite.coordinator.WriteAcknowledgement(suite.chainB, suite.chainA, packet, clientA)
suite.Require().NoError(err)
channelCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, true},
{"channel not found", func() {
// use wrong channel naming
@ -511,16 +507,32 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() {
err := suite.coordinator.SetChannelClosed(suite.chainA, suite.chainB, channelA)
suite.Require().NoError(err)
channelCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, false},
{"capability authentication failed", func() {
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.ORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
// create packet commitment
err := suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.Require().NoError(err)
// create packet receipt and acknowledgement
err = suite.coordinator.RecvPacket(suite.chainA, suite.chainB, clientA, packet)
suite.Require().NoError(err)
channelCap = capabilitytypes.NewCapability(3)
}, false},
{"packet destination port ≠ channel counterparty port", func() {
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
// use wrong port for dest
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, ibctesting.InvalidID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
channelCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, false},
{"packet destination channel ID ≠ channel counterparty channel ID", func() {
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
// use wrong channel for dest
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, ibctesting.InvalidID, timeoutHeight, disabledTimeoutTimestamp)
channelCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, false},
{"connection not found", func() {
channelA := ibctesting.TestChannel{PortID: portID, ID: channelIDA}
@ -532,6 +544,8 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() {
types.NewChannel(types.OPEN, types.ORDERED, types.NewCounterparty(channelA.PortID, channelA.ID), []string{connIDB}, channelB.Version),
)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
suite.chainA.CreateChannelCapability(channelA.PortID, channelA.ID)
channelCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, false},
{"connection not OPEN", func() {
clientA, clientB := suite.coordinator.SetupClients(suite.chainA, suite.chainB, ibctesting.Tendermint)
@ -548,11 +562,14 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() {
types.NewChannel(types.OPEN, types.ORDERED, types.NewCounterparty(channelB.PortID, channelB.ID), []string{connA.ID}, channelA.Version),
)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
suite.chainA.CreateChannelCapability(channelA.PortID, channelA.ID)
channelCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, false},
{"packet hasn't been sent", func() {
// packet commitment never written
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
channelCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, false},
{"packet ack verification failed", func() {
// ack never written
@ -561,6 +578,7 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() {
// create packet commitment
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
channelCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, false},
{"next ack sequence not found", func() {
_, _, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, ibctesting.Tendermint)
@ -576,8 +594,10 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() {
// manually set packet commitment
suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainA.GetContext(), channelA.PortID, channelA.ID, packet.GetSequence(), ibctesting.TestHash)
// manually set packet acknowledgement
// manually set packet acknowledgement and capability
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(suite.chainB.GetContext(), channelB.PortID, channelB.ID, packet.GetSequence(), ibctesting.TestHash)
suite.chainA.CreateChannelCapability(channelA.PortID, channelA.ID)
channelCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, false},
{"next ack sequence mismatch", func() {
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.ORDERED)
@ -587,14 +607,12 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() {
suite.Require().NoError(err)
// create packet acknowledgement
err = suite.coordinator.WriteReceipt(suite.chainB, suite.chainA, packet, clientA)
suite.Require().NoError(err)
err = suite.coordinator.WriteAcknowledgement(suite.chainB, suite.chainA, packet, clientA)
err = suite.coordinator.RecvPacket(suite.chainA, suite.chainB, clientA, packet)
suite.Require().NoError(err)
// set next sequence ack wrong
suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceAck(suite.chainA.GetContext(), channelA.PortID, channelA.ID, 10)
channelCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, false},
}
@ -607,84 +625,7 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() {
packetKey := host.KeyPacketAcknowledgement(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
proof, proofHeight := suite.chainB.QueryProof(packetKey)
err := suite.chainA.App.IBCKeeper.ChannelKeeper.AcknowledgePacket(suite.chainA.GetContext(), packet, ack, proof, proofHeight)
if tc.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
}
// TestAcknowledgementExectued verifies that packet commitments are deleted on chainA
// after capabilities are verified.
func (suite *KeeperTestSuite) TestAcknowledgementExecuted() {
var (
packet types.Packet
chanCap *capabilitytypes.Capability
)
testCases := []testCase{
{"success ORDERED", func() {
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.ORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
// create packet commitment
err := suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.Require().NoError(err)
// create packet receipt and acknowledgement
err = suite.coordinator.WriteReceipt(suite.chainB, suite.chainA, packet, clientA)
suite.Require().NoError(err)
err = suite.coordinator.WriteAcknowledgement(suite.chainB, suite.chainA, packet, clientA)
suite.Require().NoError(err)
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, true},
{"success UNORDERED", func() {
// setup uses an UNORDERED channel
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
// create packet commitment
err := suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.Require().NoError(err)
// create packet receipt and acknowledgement
err = suite.coordinator.WriteReceipt(suite.chainB, suite.chainA, packet, clientA)
suite.Require().NoError(err)
err = suite.coordinator.WriteAcknowledgement(suite.chainB, suite.chainA, packet, clientA)
suite.Require().NoError(err)
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, true},
{"channel not found", func() {
// use wrong channel naming
_, _, _, _, _, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
packet = types.NewPacket(validPacketData, 1, ibctesting.InvalidID, ibctesting.InvalidID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
}, false},
{"incorrect capability", func() {
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
chanCap = capabilitytypes.NewCapability(100)
}, false},
}
for i, tc := range testCases {
tc := tc
suite.Run(fmt.Sprintf("Case %s, %d/%d tests", tc.msg, i, len(testCases)), func() {
suite.SetupTest() // reset
tc.malleate()
err := suite.chainA.App.IBCKeeper.ChannelKeeper.AcknowledgementExecuted(suite.chainA.GetContext(), chanCap, packet)
err := suite.chainA.App.IBCKeeper.ChannelKeeper.AcknowledgePacket(suite.chainA.GetContext(), channelCap, packet, ack, proof, proofHeight)
pc := suite.chainA.App.IBCKeeper.ChannelKeeper.GetPacketCommitment(suite.chainA.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())
channelA, _ := suite.chainA.App.IBCKeeper.ChannelKeeper.GetChannel(suite.chainA.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel())

View File

@ -13,7 +13,7 @@ import (
var _ sdk.Msg = &MsgChannelOpenInit{}
// NewMsgChannelOpenInit creates a new MsgChannelOpenInit
//nolint:interfacer
// nolint:interfacer
func NewMsgChannelOpenInit(
portID, channelID string, version string, channelOrder Order, connectionHops []string,
counterpartyPortID, counterpartyChannelID string, signer sdk.AccAddress,
@ -46,7 +46,16 @@ func (msg MsgChannelOpenInit) ValidateBasic() error {
if err := host.ChannelIdentifierValidator(msg.ChannelId); err != nil {
return sdkerrors.Wrap(err, "invalid channel ID")
}
// Signer can be empty
if msg.Channel.State != INIT {
return sdkerrors.Wrapf(ErrInvalidChannelState,
"channel state must be INIT in MsgChannelOpenInit. expected: %s, got: %s",
INIT, msg.Channel.State,
)
}
_, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err)
}
return msg.Channel.ValidateBasic()
}
@ -68,14 +77,14 @@ func (msg MsgChannelOpenInit) GetSigners() []sdk.AccAddress {
var _ sdk.Msg = &MsgChannelOpenTry{}
// NewMsgChannelOpenTry creates a new MsgChannelOpenTry instance
//nolint:interfacer
// nolint:interfacer
func NewMsgChannelOpenTry(
portID, desiredChannelID, counterpartyChosenChannelID, version string, channelOrder Order, connectionHops []string,
counterpartyPortID, counterpartyChannelID, counterpartyVersion string,
proofInit []byte, proofHeight clienttypes.Height, signer sdk.AccAddress,
) *MsgChannelOpenTry {
counterparty := NewCounterparty(counterpartyPortID, counterpartyChannelID)
channel := NewChannel(INIT, channelOrder, counterparty, connectionHops, version)
channel := NewChannel(TRYOPEN, channelOrder, counterparty, connectionHops, version)
return &MsgChannelOpenTry{
PortId: portID,
DesiredChannelId: desiredChannelID,
@ -115,7 +124,16 @@ func (msg MsgChannelOpenTry) ValidateBasic() error {
if msg.ProofHeight.IsZero() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidHeight, "proof height must be non-zero")
}
// Signer can be empty
if msg.Channel.State != TRYOPEN {
return sdkerrors.Wrapf(ErrInvalidChannelState,
"channel state must be TRYOPEN in MsgChannelOpenTry. expected: %s, got: %s",
TRYOPEN, msg.Channel.State,
)
}
_, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err)
}
return msg.Channel.ValidateBasic()
}
@ -137,7 +155,7 @@ func (msg MsgChannelOpenTry) GetSigners() []sdk.AccAddress {
var _ sdk.Msg = &MsgChannelOpenAck{}
// NewMsgChannelOpenAck creates a new MsgChannelOpenAck instance
//nolint:interfacer
// nolint:interfacer
func NewMsgChannelOpenAck(
portID, channelID, counterpartyChannelID string, cpv string, proofTry []byte, proofHeight clienttypes.Height,
signer sdk.AccAddress,
@ -180,7 +198,10 @@ func (msg MsgChannelOpenAck) ValidateBasic() error {
if msg.ProofHeight.IsZero() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidHeight, "proof height must be non-zero")
}
// Signer can be empty
_, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err)
}
return nil
}
@ -202,7 +223,7 @@ func (msg MsgChannelOpenAck) GetSigners() []sdk.AccAddress {
var _ sdk.Msg = &MsgChannelOpenConfirm{}
// NewMsgChannelOpenConfirm creates a new MsgChannelOpenConfirm instance
//nolint:interfacer
// nolint:interfacer
func NewMsgChannelOpenConfirm(
portID, channelID string, proofAck []byte, proofHeight clienttypes.Height,
signer sdk.AccAddress,
@ -240,7 +261,10 @@ func (msg MsgChannelOpenConfirm) ValidateBasic() error {
if msg.ProofHeight.IsZero() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidHeight, "proof height must be non-zero")
}
// Signer can be empty
_, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err)
}
return nil
}
@ -262,7 +286,7 @@ func (msg MsgChannelOpenConfirm) GetSigners() []sdk.AccAddress {
var _ sdk.Msg = &MsgChannelCloseInit{}
// NewMsgChannelCloseInit creates a new MsgChannelCloseInit instance
//nolint:interfacer
// nolint:interfacer
func NewMsgChannelCloseInit(
portID string, channelID string, signer sdk.AccAddress,
) *MsgChannelCloseInit {
@ -291,7 +315,10 @@ func (msg MsgChannelCloseInit) ValidateBasic() error {
if err := host.ChannelIdentifierValidator(msg.ChannelId); err != nil {
return sdkerrors.Wrap(err, "invalid channel ID")
}
// Signer can be empty
_, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err)
}
return nil
}
@ -313,7 +340,7 @@ func (msg MsgChannelCloseInit) GetSigners() []sdk.AccAddress {
var _ sdk.Msg = &MsgChannelCloseConfirm{}
// NewMsgChannelCloseConfirm creates a new MsgChannelCloseConfirm instance
//nolint:interfacer
// nolint:interfacer
func NewMsgChannelCloseConfirm(
portID, channelID string, proofInit []byte, proofHeight clienttypes.Height,
signer sdk.AccAddress,
@ -351,7 +378,10 @@ func (msg MsgChannelCloseConfirm) ValidateBasic() error {
if msg.ProofHeight.IsZero() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidHeight, "proof height must be non-zero")
}
// Signer can be empty
_, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err)
}
return nil
}
@ -373,7 +403,7 @@ func (msg MsgChannelCloseConfirm) GetSigners() []sdk.AccAddress {
var _ sdk.Msg = &MsgRecvPacket{}
// NewMsgRecvPacket constructs new MsgRecvPacket
//nolint:interfacer
// nolint:interfacer
func NewMsgRecvPacket(
packet Packet, proof []byte, proofHeight clienttypes.Height,
signer sdk.AccAddress,
@ -399,10 +429,10 @@ func (msg MsgRecvPacket) ValidateBasic() error {
if msg.ProofHeight.IsZero() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidHeight, "proof height must be non-zero")
}
if msg.Signer == "" {
return sdkerrors.ErrInvalidAddress
_, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err)
}
return msg.Packet.ValidateBasic()
}
@ -436,7 +466,7 @@ func (msg MsgRecvPacket) Type() string {
var _ sdk.Msg = &MsgTimeout{}
// NewMsgTimeout constructs new MsgTimeout
//nolint:interfacer
// nolint:interfacer
func NewMsgTimeout(
packet Packet, nextSequenceRecv uint64, proof []byte,
proofHeight clienttypes.Height, signer sdk.AccAddress,
@ -463,10 +493,10 @@ func (msg MsgTimeout) ValidateBasic() error {
if msg.ProofHeight.IsZero() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidHeight, "proof height must be non-zero")
}
if msg.Signer == "" {
return sdkerrors.ErrInvalidAddress
_, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err)
}
return msg.Packet.ValidateBasic()
}
@ -491,7 +521,7 @@ func (msg MsgTimeout) Type() string {
}
// NewMsgTimeoutOnClose constructs new MsgTimeoutOnClose
//nolint:interfacer
// nolint:interfacer
func NewMsgTimeoutOnClose(
packet Packet, nextSequenceRecv uint64,
proof, proofClose []byte,
@ -523,10 +553,10 @@ func (msg MsgTimeoutOnClose) ValidateBasic() error {
if msg.ProofHeight.IsZero() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidHeight, "proof height must be non-zero")
}
if msg.Signer == "" {
return sdkerrors.ErrInvalidAddress
_, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err)
}
return msg.Packet.ValidateBasic()
}
@ -553,7 +583,7 @@ func (msg MsgTimeoutOnClose) Type() string {
var _ sdk.Msg = &MsgAcknowledgement{}
// NewMsgAcknowledgement constructs a new MsgAcknowledgement
//nolint:interfacer
// nolint:interfacer
func NewMsgAcknowledgement(
packet Packet, ack []byte, proof []byte, proofHeight clienttypes.Height, signer sdk.AccAddress) *MsgAcknowledgement {
return &MsgAcknowledgement{
@ -578,10 +608,10 @@ func (msg MsgAcknowledgement) ValidateBasic() error {
if msg.ProofHeight.IsZero() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidHeight, "proof height must be non-zero")
}
if msg.Signer == "" {
return sdkerrors.ErrInvalidAddress
_, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err)
}
return msg.Packet.ValidateBasic()
}

View File

@ -105,6 +105,9 @@ func TestTypesTestSuite(t *testing.T) {
}
func (suite *TypesTestSuite) TestMsgChannelOpenInitValidateBasic() {
counterparty := types.NewCounterparty(cpportid, cpchanid)
tryOpenChannel := types.NewChannel(types.TRYOPEN, types.ORDERED, counterparty, connHops, version)
testCases := []struct {
name string
msg *types.MsgChannelOpenInit
@ -125,6 +128,7 @@ func (suite *TypesTestSuite) TestMsgChannelOpenInitValidateBasic() {
{"", types.NewMsgChannelOpenInit(portid, chanid, "", types.UNORDERED, connHops, cpportid, cpchanid, addr), true},
{"invalid counterparty port id", types.NewMsgChannelOpenInit(portid, chanid, version, types.UNORDERED, connHops, invalidPort, cpchanid, addr), false},
{"invalid counterparty channel id", types.NewMsgChannelOpenInit(portid, chanid, version, types.UNORDERED, connHops, cpportid, invalidChannel, addr), false},
{"channel not in INIT state", &types.MsgChannelOpenInit{portid, chanid, tryOpenChannel, addr.String()}, false},
}
for _, tc := range testCases {
@ -142,6 +146,9 @@ func (suite *TypesTestSuite) TestMsgChannelOpenInitValidateBasic() {
}
func (suite *TypesTestSuite) TestMsgChannelOpenTryValidateBasic() {
counterparty := types.NewCounterparty(cpportid, cpchanid)
initChannel := types.NewChannel(types.INIT, types.ORDERED, counterparty, connHops, version)
testCases := []struct {
name string
msg *types.MsgChannelOpenTry
@ -167,6 +174,7 @@ func (suite *TypesTestSuite) TestMsgChannelOpenTryValidateBasic() {
{"empty proof", types.NewMsgChannelOpenTry(portid, chanid, chanid, version, types.UNORDERED, connHops, cpportid, cpchanid, version, emptyProof, height, addr), false},
{"valid empty proved channel id", types.NewMsgChannelOpenTry(portid, chanid, "", version, types.ORDERED, connHops, cpportid, cpchanid, version, suite.proof, height, addr), true},
{"invalid proved channel id, doesn't match channel id", types.NewMsgChannelOpenTry(portid, chanid, "differentchannel", version, types.ORDERED, connHops, cpportid, cpchanid, version, suite.proof, height, addr), false},
{"channel not in TRYOPEN state", &types.MsgChannelOpenTry{portid, chanid, chanid, initChannel, version, suite.proof, height, addr.String()}, false},
}
for _, tc := range testCases {

View File

@ -192,105 +192,15 @@ func (proof MerkleProof) VerifyNonMembership(specs []*ics23.ProofSpec, root expo
}
// BatchVerifyMembership verifies a group of key value pairs against the given root
// NOTE: All items must be part of a batch proof in the first chained proof, i.e. items must all be part of smallest subtree in the chained proof
// NOTE: The path passed in must be the path from the root to the smallest subtree in the chained proof
// NOTE: Untested
// NOTE: Currently left unimplemented as it is unused
func (proof MerkleProof) BatchVerifyMembership(specs []*ics23.ProofSpec, root exported.Root, path exported.Path, items map[string][]byte) error {
if err := proof.validateVerificationArgs(specs, root); err != nil {
return err
}
// Convert Proof to []CommitmentProof
proofs, err := convertProofs(proof)
if err != nil {
return err
}
// VerifyNonMembership will verify the absence of key in lowest subtree, and then chain inclusion proofs
// of all subroots up to final root
subroot, err := proofs[0].Calculate()
if err != nil {
return sdkerrors.Wrapf(ErrInvalidProof, "could not calculate root for proof index 0: %v", err)
}
if ok := ics23.BatchVerifyMembership(specs[0], subroot, proofs[0], items); !ok {
return sdkerrors.Wrapf(ErrInvalidProof, "could not verify batch items")
}
// BatchVerifyMembership specific argument validation
// Path must only be defined if this is a chained proof
if len(specs) > 1 {
mpath, ok := path.(MerklePath)
if !ok {
return sdkerrors.Wrapf(ErrInvalidProof, "path %v is not of type MerkleProof", path)
}
// path length should be one less than specs, since lowest proof keys are in items
if len(mpath.KeyPath.Keys) != len(specs)-1 {
return sdkerrors.Wrapf(ErrInvalidProof, "path length %d not same as proof %d",
len(mpath.KeyPath.Keys), len(specs))
}
// Since BatchedProof path does not include lowest subtree, exclude first proof from specs and proofs and start
// chaining at index 0
if err := verifyChainedMembershipProof(root.GetHash(), specs[1:], proofs[1:], mpath.KeyPath, subroot, 0); err != nil {
return err
}
} else if !bytes.Equal(root.GetHash(), subroot) {
// Since we are not chaining proofs, we must check first subroot equals given root
return sdkerrors.Wrapf(ErrInvalidProof, "batched proof did not commit to expected root: %X, got: %X", root.GetHash(), subroot)
}
return nil
return sdkerrors.Wrap(ErrInvalidProof, "batch proofs are currently unsupported")
}
// BatchVerifyNonMembership verifies absence of a group of keys against the given root
// NOTE: All items must be part of a batch proof in the first chained proof, i.e. items must all be part of smallest subtree in the chained proof
// NOTE: The path passed in must be the path from the root to the smallest subtree in the chained proof
// NOTE: Untested
// NOTE: Currently left unimplemented as it is unused
func (proof MerkleProof) BatchVerifyNonMembership(specs []*ics23.ProofSpec, root exported.Root, path exported.Path, items [][]byte) error {
if err := proof.validateVerificationArgs(specs, root); err != nil {
return err
}
// Convert Proof to []CommitmentProof
proofs, err := convertProofs(proof)
if err != nil {
return err
}
// VerifyNonMembership will verify the absence of key in lowest subtree, and then chain inclusion proofs
// of all subroots up to final root
subroot, err := proofs[0].Calculate()
if err != nil {
return sdkerrors.Wrapf(ErrInvalidProof, "could not calculate root for proof index 0: %v", err)
}
if ok := ics23.BatchVerifyNonMembership(specs[0], subroot, proofs[0], items); !ok {
return sdkerrors.Wrapf(ErrInvalidProof, "could not verify batch items")
}
// BatchVerifyNonMembership specific argument validation
// Path must only be defined if this is a chained proof
if len(specs) > 1 {
mpath, ok := path.(MerklePath)
if !ok {
return sdkerrors.Wrapf(ErrInvalidProof, "path %v is not of type MerkleProof", path)
}
// path length should be one less than specs, since lowest proof keys are in items
if len(mpath.KeyPath.Keys) != len(specs)-1 {
return sdkerrors.Wrapf(ErrInvalidProof, "path length %d not same as proof %d",
len(mpath.KeyPath.Keys), len(specs))
}
// Since BatchedProof path does not include lowest subtree, exclude first proof from specs and proofs and start
// chaining at index 0
if err := verifyChainedMembershipProof(root.GetHash(), specs[1:], proofs[1:], mpath.KeyPath, subroot, 0); err != nil {
return err
}
} else if !bytes.Equal(root.GetHash(), subroot) {
// Since we are not chaining proofs, we must check first subroot equals given root
return sdkerrors.Wrapf(ErrInvalidProof, "batched proof did not commit to expected root: %X, got: %X", root.GetHash(), subroot)
}
return nil
return sdkerrors.Wrap(ErrInvalidProof, "batch proofs are currently unsupported")
}
// verifyChainedMembershipProof takes a list of proofs and specs and verifies each proof sequentially ensuring that the value is committed to

View File

@ -31,9 +31,9 @@ var (
const (
KeyChannelPrefix = "channelEnds"
KeyChannelCapabilityPrefix = "capabilities"
KeyNextSeqSendPrefix = "seqSends"
KeyNextSeqRecvPrefix = "seqRecvs"
KeyNextSeqAckPrefix = "seqAcks"
KeyNextSeqSendPrefix = "nextSequenceSend"
KeyNextSeqRecvPrefix = "nextSequenceRecv"
KeyNextSeqAckPrefix = "nextSequenceAck"
KeyPacketCommitmentPrefix = "commitments"
KeyPacketAckPrefix = "acks"
KeyPacketReceiptPrefix = "receipts"
@ -116,17 +116,17 @@ func ChannelCapabilityPath(portID, channelID string) string {
// NextSequenceSendPath defines the next send sequence counter store path
func NextSequenceSendPath(portID, channelID string) string {
return fmt.Sprintf("%s/", KeyNextSeqSendPrefix) + channelPath(portID, channelID) + "/nextSequenceSend"
return fmt.Sprintf("%s/", KeyNextSeqSendPrefix) + channelPath(portID, channelID)
}
// NextSequenceRecvPath defines the next receive sequence counter store path
func NextSequenceRecvPath(portID, channelID string) string {
return fmt.Sprintf("%s/", KeyNextSeqRecvPrefix) + channelPath(portID, channelID) + "/nextSequenceRecv"
return fmt.Sprintf("%s/", KeyNextSeqRecvPrefix) + channelPath(portID, channelID)
}
// NextSequenceAckPath defines the next acknowledgement sequence counter store path
func NextSequenceAckPath(portID, channelID string) string {
return fmt.Sprintf("%s/", KeyNextSeqAckPrefix) + channelPath(portID, channelID) + "/nextSequenceAck"
return fmt.Sprintf("%s/", KeyNextSeqAckPrefix) + channelPath(portID, channelID)
}
// PacketCommitmentPath defines the commitments to packet data fields store path

View File

@ -51,7 +51,6 @@ type ClientState interface {
VerifyClientState(
store sdk.KVStore,
cdc codec.BinaryMarshaler,
root Root,
height Height,
prefix Prefix,
counterpartyClientIdentifier string,
@ -61,7 +60,6 @@ type ClientState interface {
VerifyClientConsensusState(
store sdk.KVStore,
cdc codec.BinaryMarshaler,
root Root,
height Height,
counterpartyClientIdentifier string,
consensusHeight Height,

View File

@ -431,7 +431,7 @@ func (k Keeper) RecvPacket(goCtx context.Context, msg *channeltypes.MsgRecvPacke
}
// Perform TAO verification
if err := k.ChannelKeeper.RecvPacket(ctx, msg.Packet, msg.Proof, msg.ProofHeight); err != nil {
if err := k.ChannelKeeper.RecvPacket(ctx, cap, msg.Packet, msg.Proof, msg.ProofHeight); err != nil {
return nil, sdkerrors.Wrap(err, "receive packet verification failed")
}
@ -441,15 +441,11 @@ func (k Keeper) RecvPacket(goCtx context.Context, msg *channeltypes.MsgRecvPacke
return nil, sdkerrors.Wrap(err, "receive packet callback failed")
}
if err := k.ChannelKeeper.WriteReceipt(ctx, cap, msg.Packet); err != nil {
return nil, err
}
// Set packet acknowledgement only if the acknowledgement is not nil.
// NOTE: IBC applications modules may call the WriteAcknowledgement asynchronously if the
// acknowledgement is nil.
if ack != nil {
if err := k.ChannelKeeper.WriteAcknowledgement(ctx, msg.Packet, ack); err != nil {
if err := k.ChannelKeeper.WriteAcknowledgement(ctx, cap, msg.Packet, ack); err != nil {
return nil, err
}
}
@ -586,7 +582,7 @@ func (k Keeper) Acknowledgement(goCtx context.Context, msg *channeltypes.MsgAckn
}
// Perform TAO verification
if err := k.ChannelKeeper.AcknowledgePacket(ctx, msg.Packet, msg.Acknowledgement, msg.Proof, msg.ProofHeight); err != nil {
if err := k.ChannelKeeper.AcknowledgePacket(ctx, cap, msg.Packet, msg.Acknowledgement, msg.Proof, msg.ProofHeight); err != nil {
return nil, sdkerrors.Wrap(err, "acknowledge packet verification failed")
}
@ -596,11 +592,6 @@ func (k Keeper) Acknowledgement(goCtx context.Context, msg *channeltypes.MsgAckn
return nil, sdkerrors.Wrap(err, "acknowledge packet callback failed")
}
// Delete packet commitment
if err = k.ChannelKeeper.AcknowledgementExecuted(ctx, cap, msg.Packet); err != nil {
return nil, err
}
defer func() {
telemetry.IncrCounterWithLabels(
[]string{"tx", "msg", "ibc", msg.Type()},

View File

@ -15,6 +15,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/ibc/core/keeper"
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/07-tendermint/types"
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
ibcmock "github.com/cosmos/cosmos-sdk/x/ibc/testing/mock"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
)
@ -49,7 +50,7 @@ func TestIBCTestSuite(t *testing.T) {
// tests the IBC handler receiving a packet on ordered and unordered channels.
// It verifies that the storing of an acknowledgement on success occurs. It
// tests high level properties like ordering and basic sanity checks. More
// rigorous testing of 'RecvPacket' and 'WriteReceipt' can be found in the
// rigorous testing of 'RecvPacket' can be found in the
// 04-channel/keeper/packet_test.go.
func (suite *KeeperTestSuite) TestHandleRecvPacket() {
var (
@ -113,7 +114,7 @@ func (suite *KeeperTestSuite) TestHandleRecvPacket() {
err := suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.Require().NoError(err)
err = suite.coordinator.WriteReceipt(suite.chainB, suite.chainA, packet, clientA)
err = suite.coordinator.RecvPacket(suite.chainA, suite.chainB, clientA, packet)
suite.Require().NoError(err)
}, false},
{"UNORDERED: packet already received (replay)", func() {
@ -124,7 +125,7 @@ func (suite *KeeperTestSuite) TestHandleRecvPacket() {
err := suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.Require().NoError(err)
err = suite.coordinator.WriteReceipt(suite.chainB, suite.chainA, packet, clientA)
err = suite.coordinator.RecvPacket(suite.chainA, suite.chainB, clientA, packet)
suite.Require().NoError(err)
}, false},
}
@ -167,7 +168,7 @@ func (suite *KeeperTestSuite) TestHandleRecvPacket() {
// tests the IBC handler acknowledgement of a packet on ordered and unordered
// channels. It verifies that the deletion of packet commitments from state
// occurs. It test high level properties like ordering and basic sanity
// checks. More rigorous testing of 'AcknowledgePacket' and 'AcknowledgementExecuted'
// checks. More rigorous testing of 'AcknowledgePacket'
// can be found in the 04-channel/keeper/packet_test.go.
func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() {
var (
@ -186,10 +187,7 @@ func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() {
err := suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.Require().NoError(err)
err = suite.coordinator.WriteReceipt(suite.chainB, suite.chainA, packet, clientA)
suite.Require().NoError(err)
err = suite.coordinator.WriteAcknowledgement(suite.chainB, suite.chainA, packet, clientA)
err = suite.coordinator.RecvPacket(suite.chainA, suite.chainB, clientA, packet)
suite.Require().NoError(err)
}, true},
{"success: UNORDERED", func() {
@ -199,10 +197,7 @@ func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() {
err := suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.Require().NoError(err)
err = suite.coordinator.WriteReceipt(suite.chainB, suite.chainA, packet, clientA)
suite.Require().NoError(err)
err = suite.coordinator.WriteAcknowledgement(suite.chainB, suite.chainA, packet, clientA)
err = suite.coordinator.RecvPacket(suite.chainA, suite.chainB, clientA, packet)
suite.Require().NoError(err)
}, true},
{"success: UNORDERED acknowledge out of order packet", func() {
@ -216,10 +211,7 @@ func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() {
err := suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.Require().NoError(err)
err = suite.coordinator.WriteReceipt(suite.chainB, suite.chainA, packet, clientA)
suite.Require().NoError(err)
err = suite.coordinator.WriteAcknowledgement(suite.chainB, suite.chainA, packet, clientA)
err = suite.coordinator.RecvPacket(suite.chainA, suite.chainB, clientA, packet)
suite.Require().NoError(err)
}
}, true},
@ -233,10 +225,7 @@ func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() {
err := suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.Require().NoError(err)
err = suite.coordinator.WriteReceipt(suite.chainB, suite.chainA, packet, clientA)
suite.Require().NoError(err)
err = suite.coordinator.WriteAcknowledgement(suite.chainB, suite.chainA, packet, clientA)
err = suite.coordinator.RecvPacket(suite.chainA, suite.chainB, clientA, packet)
suite.Require().NoError(err)
}
}, false},
@ -258,16 +247,13 @@ func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() {
err := suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.Require().NoError(err)
err = suite.coordinator.WriteReceipt(suite.chainB, suite.chainA, packet, clientA)
err = suite.coordinator.RecvPacket(suite.chainA, suite.chainB, clientA, packet)
suite.Require().NoError(err)
err = suite.coordinator.WriteAcknowledgement(suite.chainB, suite.chainA, packet, clientA)
suite.Require().NoError(err)
err = suite.coordinator.AcknowledgementExecuted(suite.chainA, suite.chainB, packet, clientB)
err = suite.coordinator.AcknowledgePacket(suite.chainA, suite.chainB, clientB, packet, ibctesting.TestHash)
suite.Require().NoError(err)
}, false},
{"UNORDERED: packet already received (replay)", func() {
{"UNORDERED: packet already acknowledged (replay)", func() {
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, channeltypes.UNORDERED)
packet = channeltypes.NewPacket(ibctesting.MockCommitment, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, 0)
@ -275,13 +261,10 @@ func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() {
err := suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.Require().NoError(err)
err = suite.coordinator.WriteReceipt(suite.chainB, suite.chainA, packet, clientA)
err = suite.coordinator.RecvPacket(suite.chainA, suite.chainB, clientA, packet)
suite.Require().NoError(err)
err = suite.coordinator.WriteAcknowledgement(suite.chainB, suite.chainA, packet, clientA)
suite.Require().NoError(err)
err = suite.coordinator.AcknowledgementExecuted(suite.chainA, suite.chainB, packet, clientB)
err = suite.coordinator.AcknowledgePacket(suite.chainA, suite.chainB, clientB, packet, ibctesting.TestHash)
suite.Require().NoError(err)
}, false},
}
@ -298,7 +281,7 @@ func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() {
packetKey := host.KeyPacketAcknowledgement(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
proof, proofHeight := suite.chainB.QueryProof(packetKey)
msg := channeltypes.NewMsgAcknowledgement(packet, ibctesting.MockAcknowledgement, proof, proofHeight, suite.chainA.SenderAccount.GetAddress())
msg := channeltypes.NewMsgAcknowledgement(packet, ibcmock.MockAcknowledgement, proof, proofHeight, suite.chainA.SenderAccount.GetAddress())
_, err := keeper.Keeper.Acknowledgement(*suite.chainA.App.IBCKeeper, sdk.WrapSDKContext(suite.chainA.GetContext()), msg)

View File

@ -89,7 +89,6 @@ func (cs ClientState) VerifyUpgrade(
func (cs ClientState) VerifyClientState(
store sdk.KVStore,
cdc codec.BinaryMarshaler,
_ exported.Root,
height exported.Height,
prefix exported.Prefix,
counterpartyClientIdentifier string,
@ -127,7 +126,6 @@ func (cs ClientState) VerifyClientState(
func (cs ClientState) VerifyClientConsensusState(
store sdk.KVStore,
cdc codec.BinaryMarshaler,
_ exported.Root,
height exported.Height,
counterpartyClientIdentifier string,
consensusHeight exported.Height,

View File

@ -192,7 +192,7 @@ func (suite *SoloMachineTestSuite) TestVerifyClientState() {
}
err := tc.clientState.VerifyClientState(
suite.store, suite.chainA.Codec, nil, solomachine.GetHeight(), tc.prefix, counterpartyClientIdentifier, tc.proof, clientState,
suite.store, suite.chainA.Codec, solomachine.GetHeight(), tc.prefix, counterpartyClientIdentifier, tc.proof, clientState,
)
if tc.expPass {
@ -320,7 +320,7 @@ func (suite *SoloMachineTestSuite) TestVerifyClientConsensusState() {
}
err := tc.clientState.VerifyClientConsensusState(
suite.store, suite.chainA.Codec, nil, solomachine.GetHeight(), counterpartyClientIdentifier, consensusHeight, tc.prefix, tc.proof, consensusState,
suite.store, suite.chainA.Codec, solomachine.GetHeight(), counterpartyClientIdentifier, consensusHeight, tc.prefix, tc.proof, consensusState,
)
if tc.expPass {

View File

@ -169,14 +169,13 @@ func (cs ClientState) ZeroCustomFields() exported.ClientState {
func (cs ClientState) VerifyClientState(
store sdk.KVStore,
cdc codec.BinaryMarshaler,
provingRoot exported.Root,
height exported.Height,
prefix exported.Prefix,
counterpartyClientIdentifier string,
proof []byte,
clientState exported.ClientState,
) error {
merkleProof, _, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof)
merkleProof, provingConsensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof)
if err != nil {
return err
}
@ -201,7 +200,7 @@ func (cs ClientState) VerifyClientState(
return err
}
return merkleProof.VerifyMembership(cs.ProofSpecs, provingRoot, path, bz)
return merkleProof.VerifyMembership(cs.ProofSpecs, provingConsensusState.GetRoot(), path, bz)
}
// VerifyClientConsensusState verifies a proof of the consensus state of the
@ -209,7 +208,6 @@ func (cs ClientState) VerifyClientState(
func (cs ClientState) VerifyClientConsensusState(
store sdk.KVStore,
cdc codec.BinaryMarshaler,
provingRoot exported.Root,
height exported.Height,
counterpartyClientIdentifier string,
consensusHeight exported.Height,
@ -217,7 +215,7 @@ func (cs ClientState) VerifyClientConsensusState(
proof []byte,
consensusState exported.ConsensusState,
) error {
merkleProof, _, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof)
merkleProof, provingConsensusState, err := produceVerificationArgs(store, cdc, cs, height, prefix, proof)
if err != nil {
return err
}
@ -242,7 +240,7 @@ func (cs ClientState) VerifyClientConsensusState(
return err
}
if err := merkleProof.VerifyMembership(cs.ProofSpecs, provingRoot, path, bz); err != nil {
if err := merkleProof.VerifyMembership(cs.ProofSpecs, provingConsensusState.GetRoot(), path, bz); err != nil {
return err
}

View File

@ -10,6 +10,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/ibc/core/exported"
"github.com/cosmos/cosmos-sdk/x/ibc/light-clients/07-tendermint/types"
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
ibcmock "github.com/cosmos/cosmos-sdk/x/ibc/testing/mock"
)
const (
@ -160,7 +161,7 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() {
tc := tc
err := tc.clientState.VerifyClientConsensusState(
nil, suite.cdc, tc.consensusState.Root, height, "chainA", tc.clientState.LatestHeight, tc.prefix, tc.proof, tc.consensusState,
nil, suite.cdc, height, "chainA", tc.clientState.LatestHeight, tc.prefix, tc.proof, tc.consensusState,
)
if tc.expPass {
@ -465,10 +466,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() {
suite.Require().NoError(err)
// write receipt and ack
err = suite.coordinator.WriteReceipt(suite.chainB, suite.chainA, packet, clientA)
suite.Require().NoError(err)
err = suite.coordinator.WriteAcknowledgement(suite.chainB, suite.chainA, packet, clientA)
err = suite.coordinator.RecvPacket(suite.chainA, suite.chainB, clientA, packet)
suite.Require().NoError(err)
var ok bool
@ -488,7 +486,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() {
err = clientState.VerifyPacketAcknowledgement(
store, suite.chainA.Codec, proofHeight, &prefix, proof,
packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), ibctesting.TestHash,
packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), ibcmock.MockAcknowledgement,
)
if tc.expPass {
@ -635,15 +633,15 @@ func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() {
suite.SetupTest() // reset
// setup testing conditions
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, channeltypes.UNORDERED)
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, channeltypes.ORDERED)
packet := channeltypes.NewPacket(ibctesting.TestHash, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, clienttypes.NewHeight(0, 100), 0)
// send packet
err := suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
suite.Require().NoError(err)
// write receipt, next seq recv incremented
err = suite.coordinator.WriteReceipt(suite.chainB, suite.chainA, packet, clientA)
// next seq recv incremented
err = suite.coordinator.RecvPacket(suite.chainA, suite.chainB, clientA, packet)
suite.Require().NoError(err)
// need to update chainA's client representing chainB
@ -666,7 +664,7 @@ func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() {
err = clientState.VerifyNextSequenceRecv(
store, suite.chainA.Codec, proofHeight, &prefix, proof,
packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(),
packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()+1,
)
if tc.expPass {

View File

@ -16,12 +16,12 @@ func GetConsensusState(store sdk.KVStore, cdc codec.BinaryMarshaler, height expo
if bz == nil {
return nil, sdkerrors.Wrapf(
clienttypes.ErrConsensusStateNotFound,
"consensus state does not exist for height %d", height,
"consensus state does not exist for height %s", height,
)
}
var consensusStateI exported.ConsensusState
if err := codec.UnmarshalAny(cdc, &consensusStateI, bz); err != nil {
consensusStateI, err := clienttypes.UnmarshalConsensusState(cdc, bz)
if err != nil {
return nil, sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "unmarshal error: %v", err)
}

View File

@ -5,6 +5,7 @@ import (
channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/core/24-host"
"github.com/cosmos/cosmos-sdk/x/ibc/core/exported"
solomachinetypes "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/06-solomachine/types"
"github.com/cosmos/cosmos-sdk/x/ibc/light-clients/07-tendermint/types"
)
@ -36,15 +37,14 @@ func (suite *TendermintTestSuite) TestGetConsensusState() {
store.Set(host.KeyConsensusState(height), clientStateBz)
}, false,
},
// TODO: uncomment upon merge of solomachine
// {
// "invalid consensus state (solomachine)", func() {
// // marshal and set solomachine consensus state
// store := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA)
// consensusStateBz := suite.chainA.App.IBCKeeper.ClientKeeper.MustMarshalConsensusState(&solomachinetypes.ConsensusState{})
// store.Set(host.KeyConsensusState(height), consensusStateBz)
// }, false,
// },
{
"invalid consensus state (solomachine)", func() {
// marshal and set solomachine consensus state
store := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA)
consensusStateBz := suite.chainA.App.IBCKeeper.ClientKeeper.MustMarshalConsensusState(&solomachinetypes.ConsensusState{})
store.Set(host.KeyConsensusState(height), consensusStateBz)
}, false,
},
}
for _, tc := range testCases {

View File

@ -112,7 +112,7 @@ func (cs ClientState) VerifyUpgrade(
// VerifyClientState verifies that the localhost client state is stored locally
func (cs ClientState) VerifyClientState(
store sdk.KVStore, cdc codec.BinaryMarshaler, _ exported.Root,
store sdk.KVStore, cdc codec.BinaryMarshaler,
_ exported.Height, _ exported.Prefix, _ string, _ []byte, clientState exported.ClientState,
) error {
path := host.KeyClientState()
@ -136,7 +136,7 @@ func (cs ClientState) VerifyClientState(
// VerifyClientConsensusState returns nil since a local host client does not store consensus
// states.
func (cs ClientState) VerifyClientConsensusState(
sdk.KVStore, codec.BinaryMarshaler, exported.Root,
sdk.KVStore, codec.BinaryMarshaler,
exported.Height, string, exported.Height, exported.Prefix,
[]byte, exported.ConsensusState,
) error {

View File

@ -98,7 +98,7 @@ func (suite *LocalhostTestSuite) TestVerifyClientState() {
tc.malleate()
err := tc.clientState.VerifyClientState(
suite.store, suite.cdc, nil, clienttypes.NewHeight(0, 10), nil, "", []byte{}, tc.counterparty,
suite.store, suite.cdc, clienttypes.NewHeight(0, 10), nil, "", []byte{}, tc.counterparty,
)
if tc.expPass {
@ -114,7 +114,7 @@ func (suite *LocalhostTestSuite) TestVerifyClientState() {
func (suite *LocalhostTestSuite) TestVerifyClientConsensusState() {
clientState := types.NewClientState("chainID", clientHeight)
err := clientState.VerifyClientConsensusState(
nil, nil, nil, nil, "", nil, nil, nil, nil,
nil, nil, nil, "", nil, nil, nil, nil,
)
suite.Require().NoError(err)
}

View File

@ -881,51 +881,14 @@ func (chain *TestChain) SendPacket(
return nil
}
// WriteReceipt simulates receiving and writing a receipt to the chain.
func (chain *TestChain) WriteReceipt(
// WriteAcknowledgement simulates writing an acknowledgement to the chain.
func (chain *TestChain) WriteAcknowledgement(
packet exported.PacketI,
) error {
channelCap := chain.GetChannelCapability(packet.GetDestPort(), packet.GetDestChannel())
// no need to send message, acting as a handler
err := chain.App.IBCKeeper.ChannelKeeper.WriteReceipt(chain.GetContext(), channelCap, packet)
if err != nil {
return err
}
// commit changes
chain.App.Commit()
chain.NextBlock()
return nil
}
// WriteAcknowledgement simulates writing an acknowledgement to the chain.
func (chain *TestChain) WriteAcknowledgement(
packet exported.PacketI,
) error {
// no need to send message, acting as a handler
err := chain.App.IBCKeeper.ChannelKeeper.WriteAcknowledgement(chain.GetContext(), packet, TestHash)
if err != nil {
return err
}
// commit changes
chain.App.Commit()
chain.NextBlock()
return nil
}
// AcknowledgementExecuted simulates deleting a packet commitment with the
// given packet sequence.
func (chain *TestChain) AcknowledgementExecuted(
packet exported.PacketI,
) error {
channelCap := chain.GetChannelCapability(packet.GetSourcePort(), packet.GetSourceChannel())
// no need to send message, acting as a handler
err := chain.App.IBCKeeper.ChannelKeeper.AcknowledgementExecuted(chain.GetContext(), channelCap, packet)
err := chain.App.IBCKeeper.ChannelKeeper.WriteAcknowledgement(chain.GetContext(), channelCap, packet, TestHash)
if err != nil {
return err
}

View File

@ -247,25 +247,6 @@ func (coord *Coordinator) RecvPacket(
return coord.SendMsgs(counterparty, source, sourceClient, []sdk.Msg{recvMsg})
}
// WriteReceipt receives a packet through the channel keeper on the source chain, writes a receipt, and updates the
// counterparty client for the source chain.
func (coord *Coordinator) WriteReceipt(
source, counterparty *TestChain,
packet exported.PacketI,
counterpartyClientID string,
) error {
if err := source.WriteReceipt(packet); err != nil {
return err
}
coord.IncrementTime()
// update source client on counterparty connection
return coord.UpdateClient(
counterparty, source,
counterpartyClientID, Tendermint,
)
}
// WriteAcknowledgement writes an acknowledgement to the channel keeper on the source chain and updates the
// counterparty client for the source chain.
func (coord *Coordinator) WriteAcknowledgement(
@ -303,25 +284,6 @@ func (coord *Coordinator) AcknowledgePacket(
return coord.SendMsgs(source, counterparty, counterpartyClient, []sdk.Msg{ackMsg})
}
// AcknowledgementExecuted deletes the packet commitment with the given
// packet sequence since the acknowledgement has been verified.
func (coord *Coordinator) AcknowledgementExecuted(
source, counterparty *TestChain,
packet exported.PacketI,
counterpartyClientID string,
) error {
if err := source.AcknowledgementExecuted(packet); err != nil {
return err
}
coord.IncrementTime()
// update source client on counterparty connection
return coord.UpdateClient(
counterparty, source,
counterpartyClientID, Tendermint,
)
}
// RelayPacket receives a channel packet on counterparty, queries the ack
// and acknowledges the packet on source. The clients are updated as needed.
func (coord *Coordinator) RelayPacket(

File diff suppressed because it is too large Load Diff

View File

@ -40,7 +40,7 @@ var s TestSuite
func setupTest(height int64, skip map[int64]bool) TestSuite {
db := dbm.NewMemDB()
app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, skip, simapp.DefaultNodeHome, 0, simapp.MakeTestEncodingConfig())
app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, skip, simapp.DefaultNodeHome, 0, simapp.MakeTestEncodingConfig(), simapp.EmptyAppOptions{})
genesisState := simapp.NewDefaultGenesisState()
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
if err != nil {