Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test,feat!: (1) New events and tx resp abstractions. (2) Cater tests to devnet #180

Merged
merged 21 commits into from
Dec 9, 2022
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
3d7309f
feat: add tests for dex
matthiasmatt Dec 5, 2022
dea1bdb
Merge branch 'master' into mat/add-dex-tests
Unique-Divine Dec 6, 2022
1b65d2e
test(common): test parse attributes
Unique-Divine Dec 6, 2022
8ac112a
feat(pytypes)!: TxResp for easily handling transaction responses
Unique-Divine Dec 7, 2022
632bc91
test: use ueth instead of unibi for pricefeed_test. (2) Bump package …
Unique-Divine Dec 7, 2022
439ef27
docs,refactor(network.py): Dynamically load insecure status using the…
Unique-Divine Dec 7, 2022
6ed915e
fix: handle case when the dex pools query returns an empty list
Unique-Divine Dec 8, 2022
3e1a5ba
refactor(common.py): Use dataclass for the TxConfig since it's simpler
Unique-Divine Dec 8, 2022
8346dfe
test: use more semantic names + increase pass rate
Unique-Divine Dec 8, 2022
8b364fb
(1) dependencies: Use pytest-order to order tests.
Unique-Divine Dec 8, 2022
0471ccc
test: passing pricefeed tests
Unique-Divine Dec 8, 2022
b342355
test: passing dex and perp tests
Unique-Divine Dec 9, 2022
11f1cdc
checkpoint #wip
Unique-Divine Dec 9, 2022
b21bd78
Merge branch 'master' into realu/tx-resp-abstraction
Unique-Divine Dec 9, 2022
cd559e4
test: improve test ordering and separate large websocket test
Unique-Divine Dec 9, 2022
cc25279
test: dex and pricefeed green
Unique-Divine Dec 9, 2022
1067938
test: fix utils_test.py
Unique-Divine Dec 9, 2022
b8ead46
test: add an env var, "USE_LOCALNET" that lets you test against custom
Unique-Divine Dec 9, 2022
d068155
fix(conftest.py)
Unique-Divine Dec 9, 2022
3063307
test,docs: (1) Add additional cases for event_test.py (2) More
Unique-Divine Dec 9, 2022
c75fb06
refactor: address PR comments
Unique-Divine Dec 9, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pytests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,4 @@ jobs:
# run tests
#----------------------------------------------
- name: Run Python SDK tests
run: poetry run pytest -s
run: poetry run pytest -s tests
6 changes: 3 additions & 3 deletions nibiru/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@

ProtobufMessage = google.protobuf.message.Message

import nibiru.common # noqa
import nibiru.msg # noqa
from nibiru.client import GrpcClient # noqa
from nibiru.common import Coin, Direction, PoolAsset, Side, TxConfig, TxType # noqa
import nibiru.pytypes # noqa
from nibiru.grpc_client import GrpcClient # noqa
from nibiru.network import Network # noqa
from nibiru.pytypes import Coin, Direction, PoolAsset, Side, TxConfig, TxType # noqa
from nibiru.sdk import Sdk # noqa
from nibiru.transaction import Transaction # noqa
from nibiru.wallet import Address, PrivateKey, PublicKey # noqa
File renamed without changes.
2 changes: 1 addition & 1 deletion nibiru/msg/bank.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from nibiru_proto.proto.cosmos.distribution.v1beta1 import tx_pb2 as tx_pb
from nibiru_proto.proto.cosmos.staking.v1beta1 import tx_pb2 as staking_pb

from nibiru.common import Coin, PythonMsg
from nibiru.pytypes import Coin, PythonMsg


@dataclasses.dataclass
Expand Down
2 changes: 1 addition & 1 deletion nibiru/msg/dex.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from nibiru_proto.proto.dex.v1 import pool_pb2 as pool_tx_pb
from nibiru_proto.proto.dex.v1 import tx_pb2 as pb

from nibiru.common import Coin, PoolAsset, PoolType, PythonMsg
from nibiru.pytypes import Coin, PoolAsset, PoolType, PythonMsg


@dataclasses.dataclass
Expand Down
2 changes: 1 addition & 1 deletion nibiru/msg/perp.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from nibiru_proto.proto.perp.v1 import state_pb2 as state_pb
from nibiru_proto.proto.perp.v1 import tx_pb2 as pb

from nibiru.common import Coin, PythonMsg, Side
from nibiru.pytypes import Coin, PythonMsg, Side
from nibiru.utils import to_sdk_dec, to_sdk_int


Expand Down
2 changes: 1 addition & 1 deletion nibiru/msg/pricefeed.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from nibiru_proto.proto.pricefeed import tx_pb2 as pb

from nibiru.common import PythonMsg
from nibiru.pytypes import PythonMsg
from nibiru.utils import to_sdk_dec, toPbTimestamp


Expand Down
46 changes: 37 additions & 9 deletions nibiru/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,48 @@

@dataclasses.dataclass
class Network:
"""A representation of a Nibiru network based on its Tendermint RPC, gRPC,
and LCD (REST) endpoints. A 'Network' instance enables interactions with a
running blockchain.

Attributes:
lcd_endpoint (str): .
grpc_endpoint (str): .
tendermint_rpc_endpoint (str): .
chain_id (str): .
websocket_endpoint (str): .
env (Optional[str]): TODO docs
fee_denom (Optional[str]): Denom for the coin used to pay gas fees. Defaults to "unibi".

Methods:
customnet: A custom Nibiru network based on environment variables.
Defaults to localnet.
devnet: A development testnet environment that runs the latest release or
pre-release from the nibiru repo. Defaults to 'nibiru-devnet-1'.
localnet: The default local network created by running 'make localnet' in
the nibiru repo.
testnet: A stable testnet environment with public community members.
Think of this as out practice mainnet. Defaults to 'nibiru-testnet-1'.
mainnet: NotImplemented.

Examples:
>>> from nibiru import Network
>>> network = Network.devnet(2)
>>> network.is_insecure
True
"""

lcd_endpoint: str
grpc_endpoint: str
tendermint_rpc_endpoint: str
chain_id: str
env: str
websocket_endpoint: str
env: str = "custom"
fee_denom: str = "unibi"

def __post_init__(self):
"""
Update the env value if the dataclass was created without one.
"""
if self.env == "":
self.env = "custom"
@property
def is_insecure(self) -> bool:
return not ("https" in self.tendermint_rpc_endpoint)

@classmethod
def customnet(cls) -> "Network":
Expand Down Expand Up @@ -74,8 +102,8 @@ def customnet(cls) -> "Network":
@classmethod
def testnet(cls, chain_num: int = 1) -> "Network":
"""
Testnet is a network open to invited validators. It is more stable than devnet and provides a faucet to get some
funds
Testnet is a network open to invited validators. It is more stable than
devnet and provides a faucet to get some funds

Args:
chain_num (int): Testnet number
Expand Down
16 changes: 16 additions & 0 deletions nibiru/pytypes/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# These import statements export the types to 'nibiru.pytypes'.

from nibiru.pytypes.common import ( # noqa # TODO move constants to a constants.py file.; noqa
GAS_PRICE,
MAX_MEMO_CHARACTERS,
Coin,
Direction,
PoolAsset,
PoolType,
PythonMsg,
Side,
TxConfig,
TxType,
)
from nibiru.pytypes.event import Event, RawEvent, TxLogEvents # noqa
from nibiru.pytypes.tx_resp import RawTxResp, TxResp # noqa
45 changes: 21 additions & 24 deletions nibiru/common.py → nibiru/pytypes/common.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import abc
from dataclasses import dataclass
import dataclasses
from enum import Enum

from nibiru_proto.proto.cosmos.base.v1beta1 import coin_pb2 as cosmos_base_coin_pb
Expand Down Expand Up @@ -52,7 +52,7 @@ class Direction(Enum):
REMOVE = 2


@dataclass
@dataclasses.dataclass
class Coin:
amount: float
denom: str
Expand All @@ -61,35 +61,32 @@ def _generate_proto_object(self):
return cosmos_base_coin_pb.Coin(amount=str(self.amount), denom=self.denom)


@dataclass
@dataclasses.dataclass
class PoolAsset:
token: Coin
weight: float


@dataclasses.dataclass
class TxConfig:
def __init__(
self,
gas_wanted: int = 0,
gas_multiplier: float = 1.25,
gas_price: float = 0,
tx_type: TxType = TxType.ASYNC,
):
"""
The TxConfig object allows to customize the behavior of the Sdk interface when a transaction is sent.

Args:
gas_wanted (int, optional): Set the absolute gas_wanted to be used. Defaults to 0.
gas_multiplier (float, optional): Set the gas multiplier that's being applied to the estimated gas.
Defaults to 0. If gas_wanted is set this property is ignored.
gas_price (float, optional): Set the gas price used to calculate the fee. Defaults to 0.
tx_type (TxType, optional): Configure how to execute the tx. Defaults to TxType.ASYNC.
"""
"""
The TxConfig object allows to customize the behavior of the Sdk interface when a transaction is sent.

Args:
gas_wanted (int, optional): Set the absolute gas_wanted to be used.
Defaults to 0.
gas_multiplier (float, optional): Set the gas multiplier that's being
applied to the estimated gas. If gas_wanted is set, this property
is ignored. Defaults to 0.
gas_price (float, optional): Set the gas price used to calculate the fee.
Defaults to 0.25.
tx_type (TxType, optional): Configure how to execute the tx. Defaults to TxType.ASYNC.
"""

self.gas_multiplier = gas_multiplier
self.gas_wanted = gas_wanted
self.gas_price = gas_price
self.tx_type = tx_type
gas_wanted: int = 0
gas_multiplier: float = 1.25
gas_price: float = 0.25
tx_type: TxType = TxType.ASYNC


class PythonMsg(abc.ABC):
Expand Down
118 changes: 118 additions & 0 deletions nibiru/pytypes/event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import collections
import pprint
from typing import Dict, List


class RawEvent(collections.abc.MutableMapping):
"""Dictionary representing a Tendermint event. In the raw TxOutput of a
successful transaciton, it's the value at

```python
tx_output['rawLog'][0]['events']
```

### Keys (KeyType):
- attributes (List[Dict[str,str]])
- type (str)

### Example:
```python
{'attributes': [
{'key': 'recipient', 'value': 'nibi1uvu52rxwqj5ndmm59y6atvx33mru9xrz6sqekr'},
{'key': 'sender', 'value': 'nibi1zaavvzxez0elundtn32qnk9lkm8kmcsz44g7xl'},
{'key': 'amount', 'value': '7unibi,70unusd'}],
'type': 'transfer'}
```
"""


class Event:
"""A Tendermint event. An event contains a type and set of attributes.
Events allow application developers to attach additional information to the
'ResponseBeginBlock', 'ResponseEndBlock', 'ResponseCheckTx', and 'ResponseDeliverTx'
functions in the ABCI (application blockchain interface).

In the Tendermint protobuf, the hard definition is:

```proto
message Event {
string type = 1;
repeated EventAttribute attributes = 2;
}
message EventAttribute {
bytes key = 1;
bytes value = 2;
bool index = 3;
}
```

- Ref: [cosmos-sdk/types/events.go](https://github.com/cosmos/cosmos-sdk/blob/93abfdd21d9892550da315b10308519b43fb1775/types/events.go#L221)
- Ref: [tendermint/tendermint/proto/tendermint/abci/types.proto](https://github.com/tendermint/tendermint/blob/a6dd0d270abc3c01f223eedee44d8b285ae273f6/proto/tendermint/abci/types.proto)
"""

type: str
attrs: Dict[str, str]

def __init__(self, raw_event: RawEvent):
self.type = raw_event["type"]
self.attrs = self.parse_attributes(raw_event["attributes"])

@staticmethod
def parse_attributes(raw_attributes: List[Dict[str, str]]) -> Dict[str, str]:
try:
attributes: dict[str, str] = {
kv_dict['key']: kv_dict['value'] for kv_dict in raw_attributes
}
return attributes
except:
raise Exception(
f"failed to parse raw attributes:\n{pprint.pformat(raw_attributes)}"
)

def __repr__(self) -> str:
return f"Event(type={self.type}, attrs={self.attrs})"

def to_dict(self) -> Dict[str, Dict[str, str]]:
return {self.type: self.attrs}


class TxLogEvents:
"""An element of 'TxResp.rawLog'. This object contains events and messages.

Keys (KeyType):
type (str)
attributes (List[EventAttribute])

Args:
events_raw (List[RawEvent])

Attributes:
events (List[Event])
msgs (List[str])
events_raw (List[RawEvent])
event_types (List[str])
"""

events: List[Event]
msgs: List[str]
events_raw: List[RawEvent]
event_types: List[str]

def __init__(self, events_raw: List[RawEvent] = []):
self.events_raw = events_raw
self.events = [Event(raw_event) for raw_event in events_raw]
self.msgs = self.get_msg_types()

def get_msg_types(self) -> List[str]:

msgs = []
self.event_types = []
for event in self.events:
self.event_types.append(event.type)
if event.type == "message":
msgs.append(event.attrs["action"])
return msgs

def __repr__(self) -> str:
self_as_dict = dict(msgs=self.msgs, events=[e.to_dict() for e in self.events])
return pprint.pformat(self_as_dict, indent=2)
Loading