Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions .wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -334,3 +334,6 @@ iterable
denoms
impl
bcrypt
QueryParamsResponse
ConsensusRestClient
CosmosSDK
53 changes: 42 additions & 11 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
COSMOS_SDK_URL := https://github.com/fetchai/cosmos-sdk
COSMOS_SDK_VERSION := v0.18.0
COSMOS_SDK_VERSION := merge/v0.53.4_to_v0.19.4__jiri
COSMOS_SDK_DIR := build/cosmos-sdk-proto-schema

WASMD_URL := https://github.com/CosmWasm/wasmd
WASMD_VERSION := v0.27.0
WASMD_VERSION := v0.61.2
WASMD_DIR := build/wasm-proto-shema

IBCGO_URL := https://github.com/cosmos/ibc-go
IBCGO_VERSION := v2.2.0
IBCGO_VERSION := v10.2.0
IBCGO_DIR := build/ibcgo-proto-schema

ICS23_URL := https://github.com/cosmos/ics23
ICS23_VERSION := go/v0.11.0
ICS23_DIR := build/ics23-protoIBC

GOGOPROTO_URL := https://github.com/cosmos/gogoproto
GOGOPROTO_VERSION := v1.7.0
GOGOPROTO_DIR := build/gogo-proto

COSMOSPROTO_URL := https://github.com/cosmos/cosmos-proto
COSMOSPROTO_VERSION := v1.0.0-beta.5
COSMOSPROTO_DIR := build/cosmos-proto

PY_GOOGLEAPIS_ROOT := $(shell python -c "import importlib.util, pathlib, sys; s=importlib.util.find_spec('google.api'); print(pathlib.Path(next(iter(s.submodule_search_locations))).parents[1]) if s and s.submodule_search_locations else sys.stdout.write('')")

COSMPY_PROTOS_DIR := cosmpy/protos
COSMPY_SRC_DIR := cosmpy
COSMPY_TESTS_DIR := tests
Expand All @@ -22,7 +36,7 @@ PYTHON_CODE_DIRS := $(COSMPY_SRC_DIR) $(COSMPY_TESTS_DIR) $(COSMPY_EXAMPLES_DIR)
### Initialise dev environment
########################################

# Create a new poetry virtual environment with all the necessary dependencies installed.
# Create a new poetry virtual environment with all the necessary dependencies installed.
# Once finished, `poetry shell` to enter the virtual environment
v := $(shell pip -V | grep virtualenvs)

Expand Down Expand Up @@ -258,14 +272,18 @@ unique = $(if $1,$(firstword $1) $(call unique,$(filter-out $(firstword $1),$1))

proto: fetch_proto_schema_source generate_proto_types generate_init_py_files

generate_proto_types: $(COSMOS_SDK_DIR) $(WASMD_DIR) $(IBCGO_DIR)
generate_proto_types: $(COSMOS_SDK_DIR) $(WASMD_DIR) $(IBCGO_DIR) $(GOGOPROTO_DIR) $(COSMOSPROTO_DIR) $(PY_GOOGLEAPIS_ROOT)
rm -frv $(COSMPY_PROTOS_DIR)/*
python -m grpc_tools.protoc --proto_path=$(WASMD_DIR)/proto --proto_path=$(WASMD_DIR)/third_party/proto --python_out=$(COSMPY_PROTOS_DIR) --grpc_python_out=$(COSMPY_PROTOS_DIR) $(shell find $(WASMD_DIR) \( -path */proto/* -or -path */third_party/proto/* \) -type f -name *.proto)
python -m grpc_tools.protoc --proto_path=$(IBCGO_DIR)/proto --proto_path=$(IBCGO_DIR)/third_party/proto --python_out=$(COSMPY_PROTOS_DIR) --grpc_python_out=$(COSMPY_PROTOS_DIR) $(shell find $(IBCGO_DIR) \( -path */proto/* -or -path */third_party/proto/* \) -type f -name *.proto)
python -m grpc_tools.protoc --proto_path=$(WASMD_DIR)/proto --proto_path=$(GOGOPROTO_DIR) --proto_path=$(COSMOSPROTO_DIR)/proto --proto_path=$(PY_GOOGLEAPIS_ROOT) --proto_path=$(COSMOS_SDK_DIR)/proto --python_out=$(COSMPY_PROTOS_DIR) --grpc_python_out=$(COSMPY_PROTOS_DIR) $(shell find $(WASMD_DIR) \( -path */proto/* -or -path */third_party/proto/* \) -type f -name *.proto)
python -m grpc_tools.protoc --proto_path=$(IBCGO_DIR)/proto --proto_path=$(GOGOPROTO_DIR) --proto_path=$(COSMOSPROTO_DIR)/proto --proto_path=$(PY_GOOGLEAPIS_ROOT) --proto_path=$(COSMOS_SDK_DIR)/proto --python_out=$(COSMPY_PROTOS_DIR) --grpc_python_out=$(COSMPY_PROTOS_DIR) $(shell find $(IBCGO_DIR) \( -path */proto/* -or -path *///third_party/proto/* \) -type f -name *.proto) --proto_path=$(COSMOS_SDK_DIR)/third_party/proto --proto_path=$(ICS23_DIR)/proto
python -m grpc_tools.protoc --proto_path=$(ICS23_DIR)/proto --proto_path=$(GOGOPROTO_DIR) --proto_path=$(COSMOSPROTO_DIR)/proto --proto_path=$(PY_GOOGLEAPIS_ROOT) --proto_path=$(COSMOS_SDK_DIR)/proto --python_out=$(COSMPY_PROTOS_DIR) --grpc_python_out=$(COSMPY_PROTOS_DIR) $(shell find $(ICS23_DIR) \( -path */proto/* -or -path *///third_party/proto/* \) -type f -name *.proto)
# ensure cosmos-sdk is last as previous modules may have duplicated proto models which are now outdated
python -m grpc_tools.protoc --proto_path=$(COSMOS_SDK_DIR)/proto --proto_path=$(COSMOS_SDK_DIR)/third_party/proto --python_out=$(COSMPY_PROTOS_DIR) --grpc_python_out=$(COSMPY_PROTOS_DIR) $(shell find $(COSMOS_SDK_DIR) \( -path */proto/* -or -path */third_party/proto/* \) -type f -name *.proto)
python -m grpc_tools.protoc --proto_path=$(COSMOS_SDK_DIR)/proto --python_out=$(COSMPY_PROTOS_DIR) --proto_path=$(GOGOPROTO_DIR) --proto_path=$(COSMOSPROTO_DIR)/proto --proto_path=$(PY_GOOGLEAPIS_ROOT) --proto_path=$(COSMOS_SDK_DIR)/proto --grpc_python_out=$(COSMPY_PROTOS_DIR) $(shell find $(COSMOS_SDK_DIR) \( -path */proto/* -or -path */third_party/proto/* \) -type f -name *.proto)
python -m grpc_tools.protoc --proto_path=$(COSMOS_SDK_DIR)/proto --python_out=$(COSMPY_PROTOS_DIR) --proto_path=$(GOGOPROTO_DIR) --proto_path=$(COSMOSPROTO_DIR)/proto --proto_path=$(PY_GOOGLEAPIS_ROOT) --proto_path=$(COSMOS_SDK_DIR)/proto --grpc_python_out=$(COSMPY_PROTOS_DIR) $(shell find $(GOGOPROTO_DIR) \( -path */gogoproto/* \) -type f -name *.proto)
python -m grpc_tools.protoc --proto_path=$(COSMOS_SDK_DIR)/proto --python_out=$(COSMPY_PROTOS_DIR) --proto_path=$(GOGOPROTO_DIR) --proto_path=$(COSMOSPROTO_DIR)/proto --proto_path=$(PY_GOOGLEAPIS_ROOT) --proto_path=$(COSMOS_SDK_DIR)/proto --grpc_python_out=$(COSMPY_PROTOS_DIR) $(shell find $(COSMOSPROTO_DIR) \( -path */proto/* \) -type f -name *.proto)

fetch_proto_schema_source: $(COSMOS_SDK_DIR) $(WASMD_DIR) $(IBCGO_DIR)

fetch_proto_schema_source: $(COSMOS_SDK_DIR) $(WASMD_DIR) $(ICS23_DIR) $(IBCGO_DIR) $(GOGOPROTO_DIR) $(COSMOSPROTO_DIR)

.PHONY: generate_init_py_files
generate_init_py_files: generate_proto_types
Expand All @@ -281,7 +299,7 @@ $(GENERATED): $(SOURCE)
$(INIT_PY_FILES_TO_CREATE): $(GENERATED_DIRS)
touch $(INIT_PY_FILES_TO_CREATE)

$(GENERATED_DIRS): $(COSMOS_SDK_DIR) $(WASMD_DIR) $(IBCGO_DIR)
$(GENERATED_DIRS): $(COSMOS_SDK_DIR) $(WASMD_DIR) $(IBCGO_DIR) $(GOGOPROTO_DIR) $(COSMOSPROTO_DIR)

$(COSMOS_SDK_DIR): Makefile
rm -rfv $(COSMOS_SDK_DIR)
Expand All @@ -298,6 +316,19 @@ $(IBCGO_DIR): Makefile
git clone --branch $(IBCGO_VERSION) --depth 1 --quiet --no-checkout --filter=blob:none $(IBCGO_URL) $(IBCGO_DIR)
cd $(IBCGO_DIR) && git checkout $(IBCGO_VERSION) -- $(IBCGO_PROTO_RELATIVE_DIRS)

$(ICS23_DIR): Makefile
rm -rfv $(ICS23_DIR)
git clone --branch $(ICS23_VERSION) --depth 1 --quiet --no-checkout --filter=blob:none $(ICS23_URL) $(ICS23_DIR)
cd $(ICS23_DIR) && git checkout $(ICS23_VERSION) -- $(ICS23_PROTO_RELATIVE_DIRS)

$(GOGOPROTO_DIR): Makefile
rm -rfv $(GOGOPROTO_DIR)
git clone --branch $(GOGOPROTO_VERSION) --depth 1 --quiet $(GOGOPROTO_URL) $(GOGOPROTO_DIR)

$(COSMOSPROTO_DIR): Makefile
rm -rfv $(COSMOSPROTO_DIR)
git clone --branch $(COSMOSPROTO_VERSION) --depth 1 --quiet $(COSMOSPROTO_URL) $(COSMOSPROTO_DIR)

debug:
$(info SOURCES_REGEX_TO_EXCLUDE: $(SOURCES_REGEX_TO_EXCLUDE))
$(info )
Expand Down Expand Up @@ -341,4 +372,4 @@ check-manifest-ci:
# Check API documentation is up-to-date
.PHONY: check-api-docs-ci
check-api-docs-ci:
python scripts/generate_api_docs.py --check-clean
python scripts/generate_api_docs.py --check-clean
41 changes: 38 additions & 3 deletions cosmpy/aerial/client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
# ------------------------------------------------------------------------------

"""Client functionality."""

import json
import math
import time
Expand All @@ -29,6 +28,7 @@
import certifi
import grpc
from dateutil.parser import isoparse
from packaging.version import Version

from cosmpy.aerial import cast_to_int
from cosmpy.aerial.client.bank import create_bank_send_msg
Expand All @@ -54,13 +54,14 @@
from cosmpy.aerial.exceptions import NotFoundError, QueryTimeoutError
from cosmpy.aerial.gas import GasStrategy, SimulationGasStrategy
from cosmpy.aerial.tx import Transaction, TxState
from cosmpy.aerial.tx_helpers import MessageLog, SubmittedTx, TxResponse
from cosmpy.aerial.tx_helpers import MessageLog, SubmittedTx, TxResponse, safe_decode
from cosmpy.aerial.types import Account, Block
from cosmpy.aerial.urls import Protocol, parse_url
from cosmpy.aerial.wallet import Wallet
from cosmpy.auth.rest_client import AuthRestClient
from cosmpy.bank.rest_client import BankRestClient
from cosmpy.common.rest_client import RestClient
from cosmpy.consensus.rest_client import ConsensusRestClient
from cosmpy.cosmwasm.rest_client import CosmWasmRestClient
from cosmpy.crypto.address import Address
from cosmpy.distribution.rest_client import DistributionRestClient
Expand All @@ -76,10 +77,14 @@
from cosmpy.protos.cosmos.base.tendermint.v1beta1.query_pb2 import (
GetBlockByHeightRequest,
GetLatestBlockRequest,
GetNodeInfoRequest,
)
from cosmpy.protos.cosmos.base.tendermint.v1beta1.query_pb2_grpc import (
ServiceStub as TendermintQueryGrpcClient,
)
from cosmpy.protos.cosmos.consensus.v1.query_pb2_grpc import (
QueryStub as QueryConsensusGrpcClient,
)
from cosmpy.protos.cosmos.crypto.ed25519.keys_pb2 import ( # noqa # pylint: disable=unused-import
PubKey,
)
Expand Down Expand Up @@ -164,6 +169,7 @@ def __init__(
self.staking = StakingGrpcClient(grpc_client)
self.distribution = DistributionGrpcClient(grpc_client)
self.params = QueryParamsGrpcClient(grpc_client)
self.consensus = QueryConsensusGrpcClient(grpc_client)
self.tendermint = TendermintQueryGrpcClient(grpc_client)
else:
rest_client = RestClient(parsed_url.rest_url)
Expand All @@ -175,6 +181,7 @@ def __init__(
self.staking = StakingRestClient(rest_client) # type: ignore
self.distribution = DistributionRestClient(rest_client) # type: ignore
self.params = ParamsRestClient(rest_client) # type: ignore
self.consensus = ConsensusRestClient(rest_client) # type: ignore
self.tendermint = TendermintRestClient(rest_client) # type: ignore

@property
Expand Down Expand Up @@ -236,6 +243,34 @@ def query_params(self, subspace: str, key: str) -> Any:
resp = self.params.Params(req)
return json.loads(resp.param.value)

def query_node_info(self) -> Any:
"""
Query basic Tendermint / node information (moniker, chain-id, version, etc.).

:return: `GetNodeInfoResponse` protobuf message.
"""
request = GetNodeInfoRequest()
return self.tendermint.GetNodeInfo(request)

def query_cosmos_sdk_version(self) -> Version:
"""
Query version of cosmos sdk.

:return: Version
"""
res = self.query_node_info()
cosmos_sdk_version = res.application_version.cosmos_sdk_version
return Version(cosmos_sdk_version.lstrip("v"))

def query_consensus(self) -> Any:
"""Query Params.

:return: Query params
"""
req = QueryParamsRequest()
resp = self.consensus.Params(req)
return resp

def query_bank_balance(self, address: Address, denom: Optional[str] = None) -> int:
"""Query bank balance.

Expand Down Expand Up @@ -652,7 +687,7 @@ def _parse_tx_response(tx_response: Any) -> TxResponse:
for event in tx_response.events:
event_data = events.get(event.type, {})
for attribute in event.attributes:
event_data[attribute.key.decode()] = attribute.value.decode()
event_data[safe_decode(attribute.key)] = safe_decode(attribute.value)
events[event.type] = event_data

timestamp = None
Expand Down
11 changes: 9 additions & 2 deletions cosmpy/aerial/gas.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
from abc import ABC, abstractmethod
from typing import Dict, Optional

from packaging.version import Version

from cosmpy.aerial.tx import Transaction


Expand Down Expand Up @@ -84,8 +86,13 @@ def block_gas_limit(self) -> int:
:return: block gas limit
"""
if self._max_gas is None:
block_params = self._client.query_params("baseapp", "BlockParams")
self._max_gas = int(block_params["max_gas"])
cosmos_sdk_version = self._client.query_cosmos_sdk_version()
if cosmos_sdk_version >= Version("0.50"):
params = self._client.query_consensus()
self._max_gas = int(params.params.block.max_gas)
else:
block_params = self._client.query_params("baseapp", "BlockParams")
self._max_gas = int(block_params["max_gas"])

return self._max_gas or -1

Expand Down
14 changes: 14 additions & 0 deletions cosmpy/aerial/tx_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,17 @@ def wait_to_complete(
self._response.ensure_successful()

return self


def safe_decode(v):
"""
Decode a value from bytes to UTF-8 string if necessary.

:param v: The value to decode. If ``bytes`` it will be decoded using UTF-8,
otherwise returned unchanged.

:return: The decoded string or the original value if it was not ``bytes``.
"""
if isinstance(v, bytes):
return v.decode("utf-8")
return v
11 changes: 2 additions & 9 deletions cosmpy/protos/__init__.py → cosmpy/consensus/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
"""This package includes autogenerated implementation of protocol buffer schema files."""
# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
#
# Copyright 2018-2022 Fetch.AI Limited
# Copyright 2018-2021 Fetch.AI Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -18,10 +17,4 @@
#
# ------------------------------------------------------------------------------

"""This package includes autogenerated implementation of protocol buffer schema files."""

import sys
from os.path import dirname


sys.path.append(dirname(__file__))
"""This package contains the Consensus module."""
40 changes: 40 additions & 0 deletions cosmpy/consensus/interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
#
# Copyright 2018-2021 Fetch.AI Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ------------------------------------------------------------------------------

"""Interface for the Consensus functionality of CosmosSDK."""

from abc import ABC, abstractmethod

from cosmpy.protos.cosmos.consensus.v1.query_pb2 import (
QueryParamsRequest,
QueryParamsResponse,
)


class Params(ABC):
"""Params abstract class."""

@abstractmethod
def Params(self, request: QueryParamsRequest) -> QueryParamsResponse:
"""
Params queries a specific Cosmos SDK parameter.

:param request: QueryParamsRequest
:return: QueryParamsResponse
"""
53 changes: 53 additions & 0 deletions cosmpy/consensus/rest_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
#
# Copyright 2018-2021 Fetch.AI Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ------------------------------------------------------------------------------

"""Implementation of Params interface using REST."""

from google.protobuf.json_format import Parse

from cosmpy.common.rest_client import RestClient
from cosmpy.consensus.interface import Params
from cosmpy.protos.cosmos.consensus.v1.query_pb2 import (
QueryParamsRequest,
QueryParamsResponse,
)


class ConsensusRestClient(Params):
"""Consensus REST client."""

API_URL = "/cosmos/consensus/v1"

def __init__(self, rest_api: RestClient) -> None:
"""
Initialize.

:param rest_api: REST client api
"""
self._rest_api = rest_api

def Params(self, request: QueryParamsRequest) -> QueryParamsResponse:
"""
Params queries a specific Cosmos SDK parameter.

:param request: QueryParamsRequest
:return: QueryParamsResponse
"""
json_response = self._rest_api.get(f"{self.API_URL}/params", request)
return Parse(json_response, QueryParamsResponse())
2 changes: 1 addition & 1 deletion cosmpy/cosmwasm/rest_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ def Codes(self, request: QueryCodesRequest) -> QueryCodesResponse:
def _fix_permission(self, permission_name):
permission_map = {
"Nobody": AccessType.Value("ACCESS_TYPE_NOBODY"),
"OnlyAddress": AccessType.Value("ACCESS_TYPE_ONLY_ADDRESS"),
"AnyOfAddresses": AccessType.Value("ACCESS_TYPE_ANY_OF_ADDRESSES"),
"Everybody": AccessType.Value("ACCESS_TYPE_EVERYBODY"),
"Unspecified": AccessType.Value("ACCESS_TYPE_UNSPECIFIED"),
}
Expand Down
Loading
Loading