Skip to content

Commit

Permalink
Merge pull request #190 from NebraLtd/light-hotspot
Browse files Browse the repository at this point in the history
Light hotspot is finally merging to master! Yay!
  • Loading branch information
MuratUrsavas authored Apr 6, 2023
2 parents 2a6067a + fe6ff94 commit eac698c
Show file tree
Hide file tree
Showing 24 changed files with 739 additions and 57 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/linting.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ jobs:
- name: Lint with flake8
run: |
pip install flake8
flake8 . --count --max-complexity=10 --statistics
flake8 . --count --max-complexity=10 --statistics --exclude protos
34 changes: 17 additions & 17 deletions .github/workflows/publish-to-pypi-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,30 @@ jobs:

- name: Fetch gateway-mfr-rs
env:
GATEWAY_MFR_RS_RELEASE: v0.3.2
GATEWAY_MFR_RS_RELEASE: "0.4.1"
run: |
wget "https://github.com/helium/gateway-mfr-rs/releases/download/${GATEWAY_MFR_RS_RELEASE}/gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-arm-unknown-linux-gnueabihf-ecc608.tar.gz"
wget "https://github.com/helium/gateway-mfr-rs/releases/download/${GATEWAY_MFR_RS_RELEASE}/gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-arm-unknown-linux-gnueabihf-ecc608.checksum"
wget "https://github.com/helium/gateway-mfr-rs/releases/download/${GATEWAY_MFR_RS_RELEASE}/gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-aarch64-unknown-linux-gnu-ecc608.tar.gz"
wget "https://github.com/helium/gateway-mfr-rs/releases/download/${GATEWAY_MFR_RS_RELEASE}/gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-aarch64-unknown-linux-gnu-ecc608.checksum"
wget "https://github.com/helium/gateway-mfr-rs/releases/download/${GATEWAY_MFR_RS_RELEASE}/gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-x86_64-unknown-linux-gnu-ecc608.tar.gz"
wget "https://github.com/helium/gateway-mfr-rs/releases/download/${GATEWAY_MFR_RS_RELEASE}/gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-x86_64-unknown-linux-gnu-ecc608.checksum"
SHA256_ARM=$( shasum -a 256 "gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-arm-unknown-linux-gnueabihf-ecc608.tar.gz" | awk '{print $1}')
SHA256_AARCH64=$( shasum -a 256 "gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-aarch64-unknown-linux-gnu-ecc608.tar.gz" | awk '{print $1}')
SHA256_X86_64=$( shasum -a 256 "gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-x86_64-unknown-linux-gnu-ecc608.tar.gz" | awk '{print $1}')
wget "https://github.com/helium/gateway-mfr-rs/releases/download/v${GATEWAY_MFR_RS_RELEASE}/gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-arm-unknown-linux-gnueabihf.tar.gz"
wget "https://github.com/helium/gateway-mfr-rs/releases/download/v${GATEWAY_MFR_RS_RELEASE}/gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-arm-unknown-linux-gnueabihf.checksum"
wget "https://github.com/helium/gateway-mfr-rs/releases/download/v${GATEWAY_MFR_RS_RELEASE}/gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-aarch64-unknown-linux-gnu.tar.gz"
wget "https://github.com/helium/gateway-mfr-rs/releases/download/v${GATEWAY_MFR_RS_RELEASE}/gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-aarch64-unknown-linux-gnu.checksum"
wget "https://github.com/helium/gateway-mfr-rs/releases/download/v${GATEWAY_MFR_RS_RELEASE}/gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-x86_64-tpm-debian-gnu.tar.gz"
wget "https://github.com/helium/gateway-mfr-rs/releases/download/v${GATEWAY_MFR_RS_RELEASE}/gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-x86_64-tpm-debian-gnu.checksum"
SHA256_ARM=$( shasum -a 256 "gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-arm-unknown-linux-gnueabihf.tar.gz" | awk '{print $1}')
SHA256_AARCH64=$( shasum -a 256 "gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-aarch64-unknown-linux-gnu.tar.gz" | awk '{print $1}')
SHA256_X86_64=$( shasum -a 256 "gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-x86_64-tpm-debian-gnu.tar.gz" | awk '{print $1}')
echo "Generated checksum ARM: ${SHA256_ARM}"
echo "Generated checksum AARCH64: ${SHA256_AARCH64}"
echo "Generated checksum X86_64: ${SHA256_X86_64}"
# Verify the checksums
if grep -q "${SHA256_ARM}" "gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-arm-unknown-linux-gnueabihf-ecc608.checksum" && grep -q "${SHA256_AARCH64}" "gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-aarch64-unknown-linux-gnu-ecc608.checksum" && grep -q "${SHA256_X86_64}" "gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-x86_64-unknown-linux-gnu-ecc608.checksum"; then
if grep -q "${SHA256_ARM}" "gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-arm-unknown-linux-gnueabihf.checksum" && grep -q "${SHA256_AARCH64}" "gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-aarch64-unknown-linux-gnu.checksum" && grep -q "${SHA256_X86_64}" "gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-x86_64-tpm-debian-gnu.checksum"; then
echo "Checksum verified for gateway_mfr. Unpacking tarball..."
# Unpack the tarballs
tar -xvf "gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-arm-unknown-linux-gnueabihf-ecc608.tar.gz"
tar -xvf "gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-arm-unknown-linux-gnueabihf.tar.gz"
mv gateway_mfr gateway_mfr_arm
tar -xvf "gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-aarch64-unknown-linux-gnu-ecc608.tar.gz"
tar -xvf "gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-aarch64-unknown-linux-gnu.tar.gz"
mv gateway_mfr gateway_mfr_aarch64
tar -xvf "gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-x86_64-unknown-linux-gnu-ecc608.tar.gz"
tar -xvf "gateway-mfr-${GATEWAY_MFR_RS_RELEASE}-x86_64-tpm-debian-gnu.tar.gz"
mv gateway_mfr gateway_mfr_x86_64
exit 0
else
Expand All @@ -53,13 +53,13 @@ jobs:
chmod +x gateway_mfr_arm
chmod +x gateway_mfr_aarch64
chmod +x gateway_mfr_x86_64
- name: Move gateway_mfr in place
run: |
mv gateway_mfr_arm hm_pyhelper/gateway_mfr
mv gateway_mfr_aarch64 hm_pyhelper/gateway_mfr_aarch64
mv gateway_mfr_x86_64 hm_pyhelper/gateway_mfr_x86_64
- name: Install pypa/build
run: |
python -m pip install build --user
Expand All @@ -78,4 +78,4 @@ jobs:
with:
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
repository_url: https://test.pypi.org/legacy/
if: github.ref == 'refs/heads/master'
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/light-hotspot'
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,10 @@ and formatted the same way as the [smartphone app expects](https://docs.helium.c

Usage:
```
While using miner container, use json rpc client
client = MinerClient()
While using gateway-rs container, use grpc client
client = GatewayClient()
result = client.create_add_gateway_txn('owner_address', 'payer_address', 'gateway_address')
```

Expand Down
1 change: 1 addition & 0 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
grpcio-tools==1.44.0
11 changes: 11 additions & 0 deletions hm_pyhelper/constants/diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,18 @@
LTE_KEY = 'lte'
ONBOARDING_KEY = 'onboarding_key'
PF_KEY = 'legacy_pass_fail'
LORA_KEY = 'lora'
PUBLIC_KEY = 'public_key'
SERIAL_NUMBER_KEY = 'serial_number'
VARIANT_KEY = 'VARIANT'
WIFI_MAC_ADDRESS_KEY = 'wifi_mac_address'

# gatewayrs diagnostic keys
VALIDATOR_ADDRESS_KEY = 'validator_address'
VALIDATOR_URI_KEY = 'validator_uri'
VALIDATOR_BLOCK_HEIGHT_KEY = 'validator_height'
VALIDATOR_BLOCK_HEIGHT_SHORT_KEY = 'MH'
VALIDATOR_BLOCK_AGE = 'validator_block_age'
GATEWAY_PUBKEY_KEY = 'gateway_pubkey'
GATEWAY_REGION_KEY = 'gateway_region'
GATEWAY_REGION_SHORT_KEY = 'RE'
4 changes: 4 additions & 0 deletions hm_pyhelper/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ class MinerFailedToFetchMacAddress(Exception):
pass


class MinerFailedToFetchEthernetAddress(Exception):
pass


class UnknownVariantException(Exception):
pass

Expand Down
Empty file.
193 changes: 193 additions & 0 deletions hm_pyhelper/gateway_grpc/client.py
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
2 changes: 2 additions & 0 deletions hm_pyhelper/gateway_grpc/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class MinerMalformedAddGatewayTxn(Exception):
pass
Loading

0 comments on commit eac698c

Please sign in to comment.