-
-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #190 from NebraLtd/light-hotspot
Light hotspot is finally merging to master! Yay!
- Loading branch information
Showing
24 changed files
with
739 additions
and
57 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
grpcio-tools==1.44.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
import base58 | ||
import grpc | ||
import subprocess | ||
import json | ||
from typing import Union | ||
|
||
from hm_pyhelper.protos import blockchain_txn_add_gateway_v1_pb2, \ | ||
local_pb2_grpc, local_pb2, region_pb2, gateway_staking_mode_pb2 | ||
from hm_pyhelper.gateway_grpc.exceptions import MinerMalformedAddGatewayTxn | ||
|
||
from hm_pyhelper.logger import get_logger | ||
|
||
LOGGER = get_logger(__name__) | ||
|
||
|
||
def decode_pub_key(encoded_key: bytes) -> str: | ||
# Addresses returned by the RPC response are missing a leading | ||
# byte for the version. The version is currently always 0. | ||
# https://github.com/helium/helium-js/blob/8d5cb76e156fb80de6fc80f239b43e3872c7b7d7/packages/crypto/src/Address.ts#L64 | ||
version_byte = b'\x00' | ||
|
||
# Convert binary address to base58 | ||
complete_key = version_byte + encoded_key | ||
decoded_key = base58.b58encode_check(complete_key).decode() | ||
return decoded_key | ||
|
||
|
||
class GatewayClient(object): | ||
''' | ||
GatewayClient wraps grpc api provided by helium gateway-rs | ||
It provides some convenience methods to support the old api | ||
to limit breaking changes. | ||
Direct interaction with the grpc api can be achieved by | ||
using GatewayClient.stub.<api> | ||
All methods might return grpc pass through exceptions. | ||
''' | ||
|
||
def __init__(self, url='helium-miner:4467'): | ||
self._url = url | ||
self._channel = grpc.insecure_channel(url) | ||
self._channel.subscribe(self._connect_state_handler) | ||
self.stub = local_pb2_grpc.apiStub(self._channel) | ||
|
||
def _connect_state_handler(self, state): | ||
if state == grpc.ChannelConnectivity.SHUTDOWN: | ||
LOGGER.error('GRPC Channel shutdown : irrecoverable error') | ||
|
||
def __enter__(self): | ||
return self | ||
|
||
def __exit__(self, _, _2, _3): | ||
self._channel.close() | ||
|
||
def get_region_enum(self) -> int: | ||
''' | ||
Returns the current configured region of the gateway. | ||
If not asserted or set in settings, defaults to 0 (US915) | ||
ref: https://github.com/helium/proto/blob/master/src/region.proto | ||
''' | ||
return self.stub.region(local_pb2.region_req()).region | ||
|
||
def get_region(self) -> str: | ||
''' | ||
Returns the current configured region of the gateway. | ||
If not asserted or set in settings, defaults to 0 (US915) | ||
''' | ||
region_id = self.get_region_enum() | ||
return region_pb2.region.Name(region_id) | ||
|
||
def sign(self, data: bytes) -> bytes: | ||
''' | ||
Sign a message with the gateway private key | ||
''' | ||
return self.stub.sign(local_pb2.sign_req(data=data)).signature | ||
|
||
def ecdh(self, address: bytes) -> bytes: | ||
''' | ||
Return shared secret using ECDH | ||
''' | ||
return self.stub.ecdh(local_pb2.ecdh_req(address=address)).secret | ||
|
||
def get_pubkey(self) -> str: | ||
''' | ||
Returns decoded public key of the gateway | ||
''' | ||
encoded_key = self.stub.pubkey(local_pb2.pubkey_req()).address | ||
return decode_pub_key(encoded_key) | ||
|
||
def get_summary(self) -> dict: | ||
''' | ||
Returns a dict with following information | ||
{ | ||
"region": str | ||
configured region eg. "US915", | ||
"key": str | ||
gateway/device public key | ||
} | ||
''' | ||
return { | ||
'region': self.get_region(), | ||
'key': self.get_pubkey(), | ||
'gateway_version': self.get_gateway_version(), | ||
} | ||
|
||
def get_gateway_version(self) -> Union[str, None]: | ||
''' | ||
Returns the current version of the gateway package installed | ||
''' | ||
# NOTE:: there is a command line argument to helium-gateway | ||
# but it is not exposed in the rpc, falling back to dpkg | ||
try: | ||
output = subprocess.check_output(['dpkg', '-s', 'helium_gateway']) | ||
for line in output.decode().splitlines(): | ||
if line.strip().startswith('Version'): | ||
# dpkg has version without v but github tags begin with v | ||
return "v" + line.split(':')[1].strip() | ||
return None | ||
except subprocess.CalledProcessError: | ||
return None | ||
|
||
def create_add_gateway_txn(self, owner_address: str, payer_address: str, | ||
staking_mode: gateway_staking_mode_pb2.gateway_staking_mode | ||
= gateway_staking_mode_pb2.gateway_staking_mode.light, | ||
gateway_address: str = "") -> dict: | ||
""" | ||
Invokes the txn_add_gateway RPC endpoint on the gateway and returns | ||
the same payload that the smartphone app traditionally expects. | ||
https://docs.helium.com/mine-hnt/full-hotspots/become-a-maker/hotspot-integration-testing/#generate-an-add-hotspot-transaction | ||
Parameters: | ||
- owner_address: The address of the account that owns the gateway. | ||
- payer_address: The address of the account that will pay for the | ||
transaction. This will typically be the | ||
maker/Nebra's account. | ||
- staking_mode: The staking mode of the gateway. | ||
ref: | ||
https://github.com/helium/proto/blob/master/src/service/local.proto#L38 | ||
- gateway_address: The address of the miner itself. This is | ||
an optional parameter because the miner | ||
will always return it in the payload during | ||
transaction generation. If the param is | ||
provided, it will only be used as extra | ||
validation. | ||
""" | ||
# NOTE:: this is unimplemented as of alpha23 release of the gateway | ||
response = self.stub.add_gateway(local_pb2.add_gateway_req( | ||
owner=owner_address.encode('utf-8'), | ||
payer=payer_address.encode('utf-8'), | ||
staking_mode=staking_mode | ||
)) | ||
result = json.loads(response.decode()) | ||
if result["address"] != gateway_address: | ||
raise MinerMalformedAddGatewayTxn | ||
return result | ||
|
||
|
||
def get_address_from_add_gateway_txn(add_gateway_txn: | ||
blockchain_txn_add_gateway_v1_pb2, | ||
address_type: str, | ||
expected_address: str = None): | ||
""" | ||
Deserializes specified field in the blockchain_txn_add_gateway_v1_pb2 | ||
protobuf to a base58 Helium address. | ||
Pararms: | ||
- add_gateway_txn: The blockchain_txn_add_gateway_v1_pb2 to | ||
inspect. | ||
- address_type: 'owner', 'gateway', or 'payer'. | ||
- expected_address (optional): Value we expect to be returned. | ||
Raises: | ||
MinerMalformedAddGatewayTxn if expected_address supplied and | ||
does not match the return value. | ||
""" | ||
|
||
# Addresses returned by the RPC response are missing a leading | ||
# byte for the version. The version is currently always 0. | ||
# https://github.com/helium/helium-js/blob/8d5cb76e156fb80de6fc80f239b43e3872c7b7d7/packages/crypto/src/Address.ts#L64 | ||
version_byte = b'\x00' | ||
|
||
# Convert binary address to base58 | ||
address_bytes = version_byte + getattr(add_gateway_txn, address_type) | ||
address = str(base58.b58encode_check(address_bytes), 'utf-8') | ||
|
||
# Ensure resulting address matches expectation | ||
is_expected_address_defined = expected_address is not None | ||
if is_expected_address_defined and address != expected_address: | ||
msg = f"Expected {address_type} address to be {expected_address}," + \ | ||
f"but is {address}" | ||
raise MinerMalformedAddGatewayTxn(msg) | ||
|
||
return address |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
class MinerMalformedAddGatewayTxn(Exception): | ||
pass |
Oops, something went wrong.