├── .github └── workflows │ ├── cpp.yml │ ├── erlang.yml │ ├── lint.yml │ ├── node.yml │ └── rust.yml ├── .gitignore ├── .prettierrc ├── CONTRIBUTING.md ├── Cargo.toml ├── LICENSE ├── Makefile.nanopb ├── README.md ├── beacon ├── Cargo.toml └── src │ ├── entropy.rs │ ├── error.rs │ ├── lib.rs │ └── region.rs ├── build-cpp.sh ├── build.rs ├── include └── .keep ├── package.json ├── rebar.config ├── rebar.lock ├── rebar3 ├── release.toml ├── src ├── blockchain_block.proto ├── blockchain_block_v1.proto ├── blockchain_gossip_handler.proto ├── blockchain_ledger_entry_v2.proto ├── blockchain_ledger_subnetwork_v1.proto ├── blockchain_poc_core_v1.proto ├── blockchain_region_param_v1.proto ├── blockchain_routing_address.proto ├── blockchain_snapshot_handler.proto ├── blockchain_state_channel_v1.proto ├── blockchain_sync_handler.proto ├── blockchain_token_type_v1.proto ├── blockchain_txn.proto ├── blockchain_txn_add_gateway_v1.proto ├── blockchain_txn_add_subnetwork_v1.proto ├── blockchain_txn_assert_location_v1.proto ├── blockchain_txn_assert_location_v2.proto ├── blockchain_txn_coinbase_v1.proto ├── blockchain_txn_consensus_group_failure_v1.proto ├── blockchain_txn_consensus_group_v1.proto ├── blockchain_txn_create_htlc_v1.proto ├── blockchain_txn_dc_coinbase_v1.proto ├── blockchain_txn_gen_gateway_v1.proto ├── blockchain_txn_gen_price_oracle_v1.proto ├── blockchain_txn_gen_validator_v1.proto ├── blockchain_txn_handler.proto ├── blockchain_txn_oui_v1.proto ├── blockchain_txn_payment_v1.proto ├── blockchain_txn_payment_v2.proto ├── blockchain_txn_poc_receipts_v1.proto ├── blockchain_txn_poc_receipts_v2.proto ├── blockchain_txn_poc_request_v1.proto ├── blockchain_txn_price_oracle_v1.proto ├── blockchain_txn_redeem_htlc_v1.proto ├── blockchain_txn_rewards_v1.proto ├── blockchain_txn_rewards_v2.proto ├── blockchain_txn_routing_v1.proto ├── blockchain_txn_security_coinbase_v1.proto ├── blockchain_txn_security_exchange_v1.proto ├── blockchain_txn_stake_validator_v1.proto ├── blockchain_txn_state_channel_close_v1.proto ├── blockchain_txn_state_channel_open_v1.proto ├── blockchain_txn_subnetwork_fund_v1.proto ├── blockchain_txn_subnetwork_rewards_v1.proto ├── blockchain_txn_token_burn_exchange_rate_v1.proto ├── blockchain_txn_token_burn_v1.proto ├── blockchain_txn_token_redeem_v1.proto ├── blockchain_txn_transfer_hotspot_v1.proto ├── blockchain_txn_transfer_hotspot_v2.proto ├── blockchain_txn_transfer_validator_stake_v1.proto ├── blockchain_txn_unstake_validator_v1.proto ├── blockchain_txn_update_gateway_oui_v1.proto ├── blockchain_txn_update_subnetwork_v1.proto ├── blockchain_txn_validator_heartbeat_v1.proto ├── blockchain_txn_vars_v1.proto ├── data_rate.proto ├── decimal.proto ├── discovery.proto ├── entropy.proto ├── gateway_staking_mode.proto ├── helium_proto.app.src ├── hex_boosting.proto ├── lib.rs ├── longfi.proto ├── mapper.proto ├── packet.proto ├── price_report.proto ├── radio.proto ├── region.proto ├── reward_manifest.proto ├── scaling_factors.proto ├── service │ ├── chain_rewardable_entities.proto │ ├── downlink.proto │ ├── follower.proto │ ├── iot_config.proto │ ├── local.proto │ ├── mobile_config.proto │ ├── multi_buy.proto │ ├── packet_router.proto │ ├── packet_verifier.proto │ ├── poc_entropy.proto │ ├── poc_lora.proto │ ├── poc_mobile.proto │ ├── router.proto │ ├── state_channel.proto │ ├── sub_dao.proto │ └── transaction.proto └── service_provider.proto ├── test ├── assert_location_v2.spec.js ├── payment_v1.spec.js ├── payment_v2.spec.js ├── service │ ├── downlink.spec.js │ └── poc_mobile.spec.js ├── token_redeem_v1.spec.js └── transfer_hotspot_v2.spec.js └── yarn.lock /.github/workflows/cpp.yml: -------------------------------------------------------------------------------- 1 | name: Cpp CI 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | tags: ['v*'] 7 | pull_request: 8 | branches: [master] 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - name: Install protoc 16 | run: sudo apt-get install -y protobuf-compiler 17 | 18 | - name: Cancel previous runs 19 | uses: styfle/cancel-workflow-action@0.11.0 20 | with: 21 | access_token: ${{ github.token }} 22 | 23 | - uses: actions/checkout@v3 24 | 25 | - name: Build pr files 26 | run: bash build-cpp.sh 27 | -------------------------------------------------------------------------------- /.github/workflows/erlang.yml: -------------------------------------------------------------------------------- 1 | name: Erlang CI 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | tags: ['v*'] 7 | pull_request: 8 | branches: [master] 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | node-version: [22.3, 23.3, 24.1] 17 | 18 | container: 19 | image: erlang:${{ matrix.node-version }} 20 | 21 | steps: 22 | - uses: actions/checkout@v3 23 | 24 | - name: Cancel previous runs 25 | uses: styfle/cancel-workflow-action@0.11.0 26 | with: 27 | access_token: ${{ github.token }} 28 | 29 | - name: Compile with OTP ${{ matrix.node-version }} 30 | run: rebar3 compile 31 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint CI 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | tags: ['v*'] 7 | pull_request: 8 | branches: [master] 9 | 10 | jobs: 11 | formatting-check: 12 | name: Formatting Check 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: Cancel previous runs 17 | uses: styfle/cancel-workflow-action@0.11.0 18 | with: 19 | access_token: ${{ github.token }} 20 | - name: Run clang-format for protobuf files 21 | uses: jidicula/clang-format-action@v4.13.0 22 | with: 23 | clang-format-version: '15' 24 | check-path: 'src' 25 | -------------------------------------------------------------------------------- /.github/workflows/node.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | tags: ['v*'] 7 | pull_request: 8 | branches: [master] 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | 17 | - name: Cancel previous runs 18 | uses: styfle/cancel-workflow-action@0.11.0 19 | with: 20 | access_token: ${{ github.token }} 21 | 22 | - name: Use Node.js 13 23 | uses: actions/setup-node@v4 24 | with: 25 | node-version: 13 26 | cache: 'npm' 27 | - run: yarn install 28 | - run: yarn build 29 | - run: yarn test 30 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust CI 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | tags: ['v*'] 7 | pull_request: 8 | branches: [master] 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | - uses: dtolnay/rust-toolchain@stable 17 | with: 18 | components: clippy, rustfmt 19 | 20 | - name: Install protoc 21 | run: sudo apt-get install -y protobuf-compiler 22 | 23 | - name: Cancel previous runs 24 | uses: styfle/cancel-workflow-action@0.11.0 25 | with: 26 | access_token: ${{ github.token }} 27 | 28 | - name: Check formatting 29 | run: cargo fmt -- --check 30 | 31 | - name: Clippy 32 | run: cargo clippy -- -Dclippy::all -A clippy::large_enum_variant 33 | 34 | - name: Build Library 35 | run: cargo build --workspace --all-features 36 | 37 | - name: Run tests 38 | run: cargo test --workspace --all-features 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .rebar3 2 | _* 3 | .eunit 4 | *.o 5 | *.beam 6 | *.plt 7 | *.swp 8 | *.swo 9 | .erlang.cookie 10 | ebin 11 | log 12 | erl_crash.dump 13 | .rebar 14 | logs 15 | _build 16 | .idea 17 | *.iml 18 | rebar3.crashdump 19 | log/ 20 | data/ 21 | src/pb/ 22 | include/ 23 | /target 24 | Cargo.lock 25 | **/*.rs.bk 26 | build 27 | node_modules 28 | include/ 29 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "trailingComma": "all", 4 | "singleQuote": true 5 | } 6 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute to this repository # 2 | 3 | We value contributions from the community and will do everything we 4 | can go get them reviewed in a timely fashion. If you have code to send 5 | our way or a bug to report: 6 | 7 | * **Contributing Code**: If you have new code or a bug fix, fork this 8 | repo, create a logically-named branch, and [submit a PR against this 9 | repo](https://github.com/helium/proto/issues). Include a 10 | write up of the PR with details on what it does. 11 | 12 | * **Reporting Bugs**: Open an issue [against this 13 | repo](https://github.com/helium/proto/issues) with as much 14 | detail as you can. At the very least you'll include steps to 15 | reproduce the problem. 16 | 17 | This project is intended to be a safe, welcoming space for 18 | collaboration, and contributors are expected to adhere to the 19 | [Contributor Covenant Code of 20 | Conduct](http://contributor-covenant.org/). 21 | 22 | Above all, thank you for taking the time to be a part of the Helium community. 23 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "helium-proto" 3 | version = "0.1.0" 4 | authors = ["Helium "] 5 | edition = "2021" 6 | license = "Apache-2.0" 7 | 8 | [lib] 9 | name = "helium_proto" 10 | path = "src/lib.rs" 11 | 12 | [workspace] 13 | members = ["beacon"] 14 | 15 | [workspace.dependencies] 16 | tonic = "0.14" 17 | bytes = "1" 18 | prost = "0.14" 19 | serde = { version = "1", features = ["derive"] } 20 | serde_json = "1" 21 | tonic-prost = "0.14" 22 | 23 | [features] 24 | default = [] 25 | services = ["tonic", "tonic-prost"] 26 | 27 | [dependencies] 28 | tonic = { workspace = true, optional = true } 29 | tonic-prost = { workspace = true, optional = true } 30 | bytes = { workspace = true } 31 | prost = { workspace = true } 32 | serde = { workspace = true } 33 | serde_json = { workspace = true } 34 | strum = { version = "0.27", features = ["derive"] } 35 | strum_macros = "0.27" 36 | 37 | [build-dependencies] 38 | tonic-prost-build = "0.14" 39 | prost-build = "0.14" 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | Copyright 2018, Helium Systems Inc. 179 | 180 | Licensed under the Apache License, Version 2.0 (the "License"); 181 | you may not use this file except in compliance with the License. 182 | You may obtain a copy of the License at 183 | 184 | http://www.apache.org/licenses/LICENSE-2.0 185 | 186 | Unless required by applicable law or agreed to in writing, software 187 | distributed under the License is distributed on an "AS IS" BASIS, 188 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 189 | See the License for the specific language governing permissions and 190 | limitations under the License. 191 | 192 | -------------------------------------------------------------------------------- /Makefile.nanopb: -------------------------------------------------------------------------------- 1 | # To use install protoc and place nanopb in your $(HOME) 2 | 3 | rwildcard = $(strip $(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d))) 4 | 5 | # recursively find all the .proto 6 | PROTOS := $(strip $(call rwildcard,src,*.proto)) 7 | filter := src/blockchain_block.proto src/blockchain_block_v1.proto 8 | filter := $(filter) $(strip $(call rwildcard,src/service,*.proto)) 9 | PROTOS := $(filter-out $(filter),$(PROTOS)) 10 | 11 | # create C_SRCS which will be our build targets 12 | C_SRCS := $(patsubst src/%.proto,build/%.c, $(PROTOS)) 13 | 14 | # create list of all directories needed for build output 15 | DIRS := build $(patsubst src%,build%,$(dir $(C_SRCS))) 16 | 17 | .PHONY: build clean dirs 18 | 19 | PROTOC := protoc -I$(HOME)/nanopb/generator/proto --plugin=protoc-gen-nanopb=$(HOME)/nanopb/generator/protoc-gen-nanopb 20 | OUT := --nanopb_out 21 | 22 | build: $(C_SRCS) 23 | 24 | dirs: 25 | mkdir -p $(DIRS) 26 | 27 | clean: 28 | rm -rf build 29 | 30 | build/%.c: src/%.proto dirs 31 | $(PROTOC) $(OUT)=$(@D) $("] 5 | edition = "2021" 6 | license = "Apache-2.0" 7 | 8 | [dependencies] 9 | base64 = ">=0.21" 10 | byteorder = "1" 11 | helium-proto = { path = "../", features = ["services"] } 12 | prost = { workspace = true } 13 | rand = "< 0.9" 14 | rand_chacha = "<=0.3.1" 15 | serde = { workspace = true } 16 | sha2 = "0" 17 | rust_decimal = { version = "1", features = ["serde-with-float"] } 18 | thiserror = "1" 19 | 20 | [dev-dependencies] 21 | serde_json = { workspace = true } 22 | 23 | 24 | -------------------------------------------------------------------------------- /beacon/src/entropy.rs: -------------------------------------------------------------------------------- 1 | use super::{Error, Result}; 2 | use base64::{engine::general_purpose::STANDARD, Engine}; 3 | use helium_proto::EntropyReportV1; 4 | use rand::{rngs::OsRng, RngCore}; 5 | use serde::{Deserialize, Serialize}; 6 | use sha2::Digest; 7 | use std::time::{SystemTime, UNIX_EPOCH}; 8 | 9 | pub const LOCAL_ENTROPY_SIZE: usize = 4; 10 | 11 | #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] 12 | pub struct Entropy { 13 | #[serde(default = "default_version")] 14 | pub version: u32, 15 | pub timestamp: i64, 16 | #[serde(with = "serde_base64")] 17 | pub data: Vec, 18 | } 19 | 20 | impl Entropy { 21 | /// Construct entropy from a local system source. The timestamp and version 22 | /// of local entropy is always 0. 23 | pub fn local() -> Result { 24 | let mut local_entropy = vec![0u8; LOCAL_ENTROPY_SIZE]; 25 | OsRng.fill_bytes(&mut local_entropy); 26 | Ok(Self { 27 | version: 0, 28 | timestamp: 0, 29 | data: local_entropy, 30 | }) 31 | } 32 | 33 | pub fn from_data(data: Vec) -> Result { 34 | let timestamp = SystemTime::now() 35 | .duration_since(UNIX_EPOCH) 36 | .map_err(Error::from)? 37 | .as_secs() as i64; 38 | Ok(Self { 39 | version: 1, // marked as local 40 | timestamp, 41 | data, 42 | }) 43 | } 44 | 45 | pub(crate) fn digest(&self, state: &mut D) { 46 | state.update(&self.data); 47 | state.update(self.timestamp.to_le_bytes()); 48 | } 49 | } 50 | 51 | fn default_version() -> u32 { 52 | 0 53 | } 54 | 55 | mod serde_base64 { 56 | use base64::{engine::general_purpose::STANDARD, Engine}; 57 | 58 | pub fn serialize(key: &T, serializer: S) -> std::result::Result 59 | where 60 | T: AsRef<[u8]>, 61 | S: serde::ser::Serializer, 62 | { 63 | serializer.serialize_str(&STANDARD.encode(key.as_ref())) 64 | } 65 | 66 | pub fn deserialize<'de, D>(deserializer: D) -> std::result::Result, D::Error> 67 | where 68 | D: serde::de::Deserializer<'de>, 69 | { 70 | struct _Visitor; 71 | 72 | impl<'de> serde::de::Visitor<'de> for _Visitor { 73 | type Value = Vec; 74 | fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { 75 | formatter.write_str("base64 entropy") 76 | } 77 | fn visit_str(self, value: &str) -> std::result::Result 78 | where 79 | E: serde::de::Error, 80 | { 81 | STANDARD 82 | .decode(value) 83 | .map_err(|err| serde::de::Error::custom(err.to_string())) 84 | } 85 | } 86 | 87 | deserializer.deserialize_str(_Visitor) 88 | } 89 | } 90 | 91 | impl std::fmt::Display for Entropy { 92 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 93 | f.write_str(&STANDARD.encode(&self.data)) 94 | } 95 | } 96 | 97 | impl From for Entropy { 98 | fn from(value: EntropyReportV1) -> Self { 99 | Self { 100 | version: value.version, 101 | timestamp: value.timestamp as i64, 102 | data: value.data, 103 | } 104 | } 105 | } 106 | 107 | #[cfg(test)] 108 | mod test { 109 | use super::*; 110 | 111 | #[test] 112 | fn test_serde() { 113 | const TIMESTAMP: u64 = 1663702455; 114 | const DATA: &str = "CE98+3O9JaKJYQqNO7vCF94iOVasA/TaWfdcpvLmcWs="; 115 | const VERSION: u32 = 0; 116 | const JSON_STR: &str = r#"{ 117 | "version": 0, 118 | "timestamp": 1663702455, 119 | "data": "CE98+3O9JaKJYQqNO7vCF94iOVasA/TaWfdcpvLmcWs=" 120 | }"#; 121 | 122 | let entropy: Entropy = serde_json::from_str(JSON_STR).expect("deserialized entropy"); 123 | let ser_entropy = serde_json::to_value(&entropy).expect("serialized entropy"); 124 | assert_eq!(VERSION, *ser_entropy.get("version").unwrap()); 125 | assert_eq!(TIMESTAMP, *ser_entropy.get("timestamp").unwrap()); 126 | assert_eq!(DATA, *ser_entropy.get("data").unwrap()); 127 | assert_eq!(DATA, entropy.to_string()); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /beacon/src/error.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | 3 | pub type Result = std::result::Result; 4 | 5 | #[derive(Error, Debug)] 6 | pub enum Error { 7 | #[error("system time")] 8 | SystemTime(#[from] std::time::SystemTimeError), 9 | #[error("protobuf decode")] 10 | Prost(#[from] prost::DecodeError), 11 | #[error("unsupported region {0}")] 12 | UnsupportedRegion(i32), 13 | #[error("no applicable region plan")] 14 | NoRegionParams, 15 | #[error("no region spreading in region plan")] 16 | NoRegionSpreading, 17 | #[error("unsupported region spreading {0}")] 18 | UnsupportedRegionSpreading(i32), 19 | #[error("no valid region spreading for packet size {0}")] 20 | NoRegionSpreadingAvailable(usize), 21 | #[error("no plausible conducted power")] 22 | InvalidConductedPower, 23 | #[error("invalid beacon version")] 24 | InvalidVersion, 25 | #[error("no valid datarate found")] 26 | NoDataRate, 27 | } 28 | 29 | impl Error { 30 | pub fn no_region_params() -> Self { 31 | Self::NoRegionParams 32 | } 33 | 34 | pub fn invalid_conducted_power() -> Self { 35 | Self::InvalidConductedPower 36 | } 37 | 38 | pub fn no_region_spreading() -> Self { 39 | Self::NoRegionSpreading 40 | } 41 | 42 | pub fn no_region_spreading_for_size(packet_size: usize) -> Self { 43 | Self::NoRegionSpreadingAvailable(packet_size) 44 | } 45 | pub fn unsupported_region_spreading(v: i32) -> Self { 46 | Self::UnsupportedRegionSpreading(v) 47 | } 48 | 49 | pub fn unsupported_region(v: i32) -> Self { 50 | Self::UnsupportedRegion(v) 51 | } 52 | 53 | pub fn invalid_version() -> Self { 54 | Self::InvalidVersion 55 | } 56 | 57 | pub fn no_data_rate() -> Self { 58 | Self::NoDataRate 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /beacon/src/lib.rs: -------------------------------------------------------------------------------- 1 | use byteorder::{ByteOrder, LittleEndian}; 2 | use helium_proto::{services::poc_lora, DataRate}; 3 | use rand::{Rng, SeedableRng}; 4 | use sha2::{Digest, Sha256}; 5 | use std::time::{SystemTime, UNIX_EPOCH}; 6 | 7 | mod entropy; 8 | mod error; 9 | mod region; 10 | 11 | pub use error::{Error, Result}; 12 | pub use { 13 | entropy::Entropy, 14 | region::{Region, RegionParams}, 15 | }; 16 | 17 | pub const BEACON_PAYLOAD_SIZE: usize = 51; 18 | 19 | #[derive(Debug, Clone, Eq)] 20 | pub struct Beacon { 21 | pub data: Vec, 22 | pub frequency: u64, 23 | pub datarate: DataRate, 24 | pub remote_entropy: Entropy, 25 | pub local_entropy: Entropy, 26 | pub conducted_power: u32, 27 | } 28 | 29 | /// A beacon is equal to another beacon when all fields except for conducted 30 | /// power are equal. Conducted power can be adjusted by the packet forwarder 31 | /// from the value inferred by the region parameters. So conducted_power is 32 | /// excluded from equality, but _should_ be compared in beacon verification to 33 | /// ensure that the generated beacon's conducted power >= the received beacon's 34 | /// conducted_power. The Beacon::verfy function performs this check 35 | impl PartialEq for Beacon { 36 | fn eq(&self, other: &Self) -> bool { 37 | self.data.eq(&other.data) 38 | && self.frequency.eq(&other.frequency) 39 | && self.datarate.eq(&other.datarate) 40 | && self.remote_entropy.eq(&other.remote_entropy) 41 | && self.local_entropy.eq(&other.local_entropy) 42 | } 43 | } 44 | 45 | impl Beacon { 46 | /// Construct a new beacon with a given remote and local entropy. The remote 47 | /// and local entropy are checked for version equality. 48 | /// 49 | /// Version 0/1 beacons use a Sha256 of the remote and local entropy (data 50 | /// and timestamp), which is then used (truncated) as the beacon payload. 51 | /// The frequency is derived from the first two bytes of the beacon payload, 52 | /// while the data_rate is derived from the packet size (spreading factor) 53 | /// and bandwidth as set in the region parameters 54 | pub fn new( 55 | remote_entropy: Entropy, 56 | local_entropy: Entropy, 57 | region_params: &RegionParams, 58 | ) -> Result { 59 | match remote_entropy.version { 60 | 0 | 1 => { 61 | region_params.check_valid()?; 62 | 63 | let seed_data = { 64 | let mut hasher = Sha256::new(); 65 | remote_entropy.digest(&mut hasher); 66 | local_entropy.digest(&mut hasher); 67 | hasher.finalize().to_vec() 68 | }; 69 | 70 | // Construct a 32 byte seed from the hash of the local and 71 | // remote entropy 72 | let mut seed = [0u8; 32]; 73 | seed.copy_from_slice(&seed_data); 74 | // Make a random generator 75 | let mut rng = rand_chacha::ChaCha12Rng::from_seed(seed); 76 | 77 | let data = rand_payload(&mut rng, BEACON_PAYLOAD_SIZE); 78 | 79 | // Selet frequency based on the the first two bytes of the 80 | // beacon data 81 | let freq_seed = LittleEndian::read_u16(&data) as usize; 82 | let frequency = 83 | region_params.params[freq_seed % region_params.params.len()].channel_frequency; 84 | let datarate = region_params.select_datarate(data.len())?; 85 | let conducted_power = region_params.max_conducted_power()?; 86 | 87 | Ok(Self { 88 | data, 89 | frequency, 90 | datarate: datarate.to_owned(), 91 | local_entropy, 92 | remote_entropy, 93 | conducted_power, 94 | }) 95 | } 96 | _ => Err(Error::invalid_version()), 97 | } 98 | } 99 | 100 | pub fn beacon_id(&self) -> String { 101 | use base64::Engine; 102 | base64::engine::general_purpose::STANDARD.encode(&self.data) 103 | } 104 | 105 | /// Verifies a generated beacon with a `reported` beacon. This checks that 106 | /// all fields are equal but that the conducted_power of this beacon is 107 | /// greater than the reported conducted_power. 108 | /// 109 | /// The conducted power verification check is disabled while makers upgrade 110 | /// their packet forwarders. 111 | pub fn verify(&self, reported: &Beacon) -> bool { 112 | self.eq(reported) // && self.conducted_power >= reported.conducted_power 113 | } 114 | } 115 | 116 | fn rand_payload(rng: &mut R, size: usize) -> Vec 117 | where 118 | R: Rng + ?Sized, 119 | { 120 | rng.sample_iter(rand::distributions::Standard) 121 | .take(size) 122 | .collect::>() 123 | } 124 | 125 | impl TryFrom for poc_lora::LoraBeaconReportReqV1 { 126 | type Error = Error; 127 | fn try_from(v: Beacon) -> Result { 128 | Ok(Self { 129 | pub_key: vec![], 130 | local_entropy: v.local_entropy.data, 131 | remote_entropy: v.remote_entropy.data, 132 | data: v.data, 133 | frequency: v.frequency, 134 | channel: 0, 135 | datarate: v.datarate as i32, 136 | tmst: 0, 137 | // This is the initial value. The beacon sender updates this value 138 | // with the actual conducted power reported by the packet forwarder. 139 | // This is adjusted for in the PartialEq implementation 140 | tx_power: v.conducted_power as i32, 141 | // The timestamp of the beacon is the timestamp of creation of the 142 | // report (in nanos) 143 | timestamp: SystemTime::now() 144 | .duration_since(UNIX_EPOCH) 145 | .map_err(Error::from)? 146 | .as_nanos() as u64, 147 | signature: vec![], 148 | }) 149 | } 150 | } 151 | 152 | #[cfg(test)] 153 | mod test { 154 | use super::*; 155 | 156 | #[test] 157 | fn test_beacon_payload() { 158 | let mut rng = rand_chacha::ChaCha12Rng::seed_from_u64(0); 159 | let data = rand_payload(&mut rng, BEACON_PAYLOAD_SIZE); 160 | 161 | assert_eq!(BEACON_PAYLOAD_SIZE, data.len()); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /beacon/src/region.rs: -------------------------------------------------------------------------------- 1 | use super::{Error, Result}; 2 | use helium_proto::{ 3 | services::iot_config::GatewayRegionParamsResV1, BlockchainRegionParamV1, 4 | BlockchainRegionParamsV1, DataRate, Message, Region as ProtoRegion, RegionSpreading, 5 | }; 6 | use rust_decimal::prelude::{Decimal, ToPrimitive}; 7 | use serde::{de, Deserialize, Deserializer}; 8 | use std::{fmt, str::FromStr}; 9 | 10 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 11 | pub struct Region(ProtoRegion); 12 | 13 | impl From for ProtoRegion { 14 | fn from(v: Region) -> Self { 15 | v.0 16 | } 17 | } 18 | 19 | impl From for Region { 20 | fn from(value: ProtoRegion) -> Self { 21 | Self(value) 22 | } 23 | } 24 | 25 | impl<'de> Deserialize<'de> for Region { 26 | fn deserialize(deserializer: D) -> std::result::Result 27 | where 28 | D: Deserializer<'de>, 29 | { 30 | struct RegionVisitor; 31 | 32 | impl<'de> de::Visitor<'de> for RegionVisitor { 33 | type Value = Region; 34 | 35 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 36 | formatter.write_str("region string") 37 | } 38 | 39 | fn visit_str(self, value: &str) -> std::result::Result 40 | where 41 | E: de::Error, 42 | { 43 | let proto_region = ProtoRegion::from_str(value) 44 | .map_err(|_| de::Error::custom(format!("unsupported region: {value}")))?; 45 | Ok(Region(proto_region)) 46 | } 47 | } 48 | 49 | deserializer.deserialize_str(RegionVisitor) 50 | } 51 | } 52 | 53 | impl fmt::Display for Region { 54 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 55 | self.0.fmt(f) 56 | } 57 | } 58 | 59 | impl From for i32 { 60 | fn from(region: Region) -> Self { 61 | region.0.into() 62 | } 63 | } 64 | 65 | impl From<&Region> for i32 { 66 | fn from(region: &Region) -> Self { 67 | region.0.into() 68 | } 69 | } 70 | 71 | impl Default for Region { 72 | fn default() -> Self { 73 | Region(ProtoRegion::Unknown) 74 | } 75 | } 76 | 77 | impl Region { 78 | pub fn from_i32(v: i32) -> Result { 79 | ProtoRegion::try_from(v) 80 | .map(Self) 81 | .map_err(|_| Error::unsupported_region(v)) 82 | } 83 | 84 | pub fn is_unknown(&self) -> bool { 85 | self.0 == ProtoRegion::Unknown 86 | } 87 | } 88 | 89 | #[derive(Debug, Clone, Default)] 90 | pub struct RegionParams { 91 | pub gain: Decimal, 92 | pub region: Region, 93 | pub params: Vec, 94 | // Timestamp the region params were attested by the config service, in 95 | // seconds since unix epoch 96 | pub timestamp: u64, 97 | } 98 | 99 | impl AsRef<[BlockchainRegionParamV1]> for RegionParams { 100 | fn as_ref(&self) -> &[BlockchainRegionParamV1] { 101 | self.params.as_ref() 102 | } 103 | } 104 | 105 | impl PartialEq for RegionParams { 106 | fn eq(&self, other: &Self) -> bool { 107 | self.gain.eq(&other.gain) && self.region.eq(&other.region) && self.params.eq(&other.params) 108 | } 109 | } 110 | 111 | impl TryFrom for RegionParams { 112 | type Error = Error; 113 | fn try_from(value: GatewayRegionParamsResV1) -> Result { 114 | let region = Region::from_i32(value.region)?; 115 | let params = value 116 | .params 117 | .ok_or_else(Error::no_region_params)? 118 | .region_params; 119 | let timestamp = value.timestamp; 120 | Ok(Self { 121 | gain: Decimal::new(value.gain as i64, 1), 122 | params, 123 | region, 124 | timestamp, 125 | }) 126 | } 127 | } 128 | 129 | impl From for RegionParams { 130 | fn from(region: Region) -> Self { 131 | Self { 132 | region, 133 | gain: 0.into(), 134 | params: vec![], 135 | timestamp: 0, 136 | } 137 | } 138 | } 139 | 140 | impl RegionParams { 141 | pub fn from_bytes(region: Region, gain: u64, data: &[u8], timestamp: u64) -> Result { 142 | let params = BlockchainRegionParamsV1::decode(data)?.region_params; 143 | let gain = Decimal::new(gain as i64, 1); 144 | Ok(Self { 145 | region, 146 | gain, 147 | params, 148 | timestamp, 149 | }) 150 | } 151 | 152 | pub fn is_unknown(&self) -> bool { 153 | self.region.is_unknown() 154 | } 155 | } 156 | 157 | impl RegionParams { 158 | pub fn check_valid(&self) -> Result { 159 | if self.is_unknown() || self.params.is_empty() { 160 | return Err(Error::no_region_params()); 161 | } 162 | Ok(()) 163 | } 164 | 165 | pub fn max_eirp(&self) -> Result { 166 | self.check_valid()?; 167 | self.params 168 | .iter() 169 | .max_by_key(|p| p.max_eirp) 170 | .ok_or_else(Error::no_region_params) 171 | .map(|v| Decimal::new(v.max_eirp as i64, 1)) 172 | } 173 | 174 | pub fn max_conducted_power(&self) -> Result { 175 | self.max_eirp().and_then(|max_eirp| { 176 | (max_eirp - self.gain) 177 | .trunc() 178 | .to_u32() 179 | .ok_or_else(Error::invalid_conducted_power) 180 | }) 181 | } 182 | 183 | /// Selects the best spreading factor for the given packet size. 184 | /// 185 | /// NOTE: This implementation matches the legacy Helium miner behavior in 186 | /// how it selects the tagged spreading from the region parameters. This 187 | /// legacy tagged spreading behavior assumes the unsorted ordering as stored 188 | /// in the region params. 189 | pub fn select_spreading(&self, packet_size: usize) -> Result { 190 | // The spreading does not change per channel frequency So just get one 191 | // and do selection depending on max_packet_size 192 | self.params 193 | .first() 194 | // ensure region params themselves are available 195 | .ok_or_else(Error::no_region_params) 196 | // Ensure spreading parameters are available 197 | .and_then(|params| { 198 | params 199 | .spreading 200 | .as_ref() 201 | .ok_or_else(Error::no_region_spreading) 202 | }) 203 | // Find the first tagged spreading that can manage the given 204 | // packet size and extract the region spreading 205 | .and_then(|spreading| { 206 | spreading 207 | .tagged_spreading 208 | .iter() 209 | .find(|tagged_spreading| { 210 | tagged_spreading.max_packet_size as usize >= packet_size 211 | }) 212 | .map(|tagged_spreading| tagged_spreading.region_spreading) 213 | .ok_or_else(|| Error::no_region_spreading_for_size(packet_size)) 214 | }) 215 | // Convert to RegionSpreading 216 | .and_then(|region_spreading| { 217 | RegionSpreading::try_from(region_spreading) 218 | .map_err(|_| Error::unsupported_region_spreading(region_spreading)) 219 | }) 220 | } 221 | 222 | /// Gets the bandwidth for teh region parameters if present. 223 | // The bandwidth does not change per channel frequency, so this gets the 224 | // first one 225 | pub fn bandwidth(&self) -> Result { 226 | self.params 227 | .first() 228 | // ensure region params themselves are available 229 | .ok_or_else(Error::no_region_params) 230 | .map(|params| params.bandwidth) 231 | } 232 | 233 | /// Convenience function to select a spreading and bandwidth for a given 234 | /// packet size and convert to a DataRate 235 | pub fn select_datarate(&self, packet_size: usize) -> Result { 236 | let spreading = self.select_spreading(packet_size)?.as_str_name(); 237 | let bandwidth = self.bandwidth()? / 1000; // in khz 238 | 239 | DataRate::from_str(&format!("{spreading}BW{bandwidth}")).map_err(|_| Error::no_data_rate()) 240 | } 241 | } 242 | 243 | impl std::fmt::Display for RegionParams { 244 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 245 | self.region.fmt(f) 246 | } 247 | } 248 | 249 | #[cfg(test)] 250 | mod test { 251 | use super::*; 252 | 253 | const EU868_PARAMS: &[u8] = &[ 254 | 10, 35, 8, 224, 202, 187, 157, 3, 16, 200, 208, 7, 24, 161, 1, 34, 20, 10, 4, 8, 6, 16, 65, 255 | 10, 5, 8, 3, 16, 129, 1, 10, 5, 8, 2, 16, 238, 1, 10, 35, 8, 160, 229, 199, 157, 3, 16, 256 | 200, 208, 7, 24, 161, 1, 34, 20, 10, 4, 8, 6, 16, 65, 10, 5, 8, 3, 16, 129, 1, 10, 5, 8, 2, 257 | 16, 238, 1, 10, 35, 8, 224, 255, 211, 157, 3, 16, 200, 208, 7, 24, 161, 1, 34, 20, 10, 4, 258 | 8, 6, 16, 65, 10, 5, 8, 3, 16, 129, 1, 10, 5, 8, 2, 16, 238, 1, 10, 35, 8, 160, 154, 224, 259 | 157, 3, 16, 200, 208, 7, 24, 161, 1, 34, 20, 10, 4, 8, 6, 16, 65, 10, 5, 8, 3, 16, 129, 1, 260 | 10, 5, 8, 2, 16, 238, 1, 10, 35, 8, 224, 180, 236, 157, 3, 16, 200, 208, 7, 24, 161, 1, 34, 261 | 20, 10, 4, 8, 6, 16, 65, 10, 5, 8, 3, 16, 129, 1, 10, 5, 8, 2, 16, 238, 1, 10, 35, 8, 160, 262 | 207, 248, 157, 3, 16, 200, 208, 7, 24, 161, 1, 34, 20, 10, 4, 8, 6, 16, 65, 10, 5, 8, 3, 263 | 16, 129, 1, 10, 5, 8, 2, 16, 238, 1, 10, 35, 8, 224, 233, 132, 158, 3, 16, 200, 208, 7, 24, 264 | 161, 1, 34, 20, 10, 4, 8, 6, 16, 65, 10, 5, 8, 3, 16, 129, 1, 10, 5, 8, 2, 16, 238, 1, 10, 265 | 35, 8, 160, 132, 145, 158, 3, 16, 200, 208, 7, 24, 161, 1, 34, 20, 10, 4, 8, 6, 16, 65, 10, 266 | 5, 8, 3, 16, 129, 1, 10, 5, 8, 2, 16, 238, 1, 267 | ]; 268 | 269 | #[test] 270 | fn test_select_datarate() { 271 | let region = ProtoRegion::Eu868.into(); 272 | let params = RegionParams::from_bytes(region, 12, EU868_PARAMS, 0).expect("region params"); 273 | assert_eq!( 274 | DataRate::Sf12bw125, 275 | params.select_datarate(30).expect("datarate") 276 | ); 277 | assert_eq!( 278 | DataRate::Sf9bw125, 279 | params.select_datarate(90).expect("datarate") 280 | ); 281 | assert_eq!( 282 | DataRate::Sf8bw125, 283 | params.select_datarate(130).expect("datarate") 284 | ); 285 | assert!(params.select_datarate(300).is_err()); 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /build-cpp.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SERVICES=$(echo src/service/{iot_config,mobile_config,downlink,multi_buy,follower,local,packet_router,poc_lora,poc_mobile,router,state_channel,transaction}.proto) 4 | MESSAGES=$(echo src/{blockchain_txn,entropy,data_rate,region,mapper,price_report}.proto) 5 | SRC_FILES="$SERVICES $MESSAGES" 6 | 7 | protoc -I=src --cpp_out=. $SRC_FILES 8 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | use std::io::Result; 2 | 3 | #[cfg(feature = "services")] 4 | const SERVICES: &[&str] = &[ 5 | "src/service/router.proto", 6 | "src/service/state_channel.proto", 7 | "src/service/local.proto", 8 | "src/service/transaction.proto", 9 | "src/service/follower.proto", 10 | "src/service/poc_mobile.proto", 11 | "src/service/poc_lora.proto", 12 | "src/service/poc_entropy.proto", 13 | "src/service/packet_router.proto", 14 | "src/service/iot_config.proto", 15 | "src/service/mobile_config.proto", 16 | "src/service/downlink.proto", 17 | "src/service/multi_buy.proto", 18 | "src/service/packet_verifier.proto", 19 | "src/service/sub_dao.proto", 20 | "src/service/chain_rewardable_entities.proto", 21 | ]; 22 | 23 | const MESSAGES: &[&str] = &[ 24 | "src/blockchain_txn.proto", 25 | "src/decimal.proto", 26 | "src/entropy.proto", 27 | "src/service_provider.proto", 28 | "src/data_rate.proto", 29 | "src/region.proto", 30 | "src/mapper.proto", 31 | "src/reward_manifest.proto", 32 | "src/blockchain_region_param_v1.proto", 33 | "src/price_report.proto", 34 | "src/hex_boosting.proto", 35 | ]; 36 | 37 | macro_rules! config { 38 | ($config:expr) => { 39 | $config 40 | .type_attribute(".", "#[derive(serde::Serialize, serde::Deserialize)]") 41 | .enum_attribute( 42 | ".helium.service_provider", 43 | "#[derive(strum_macros::EnumIter)]", 44 | ) 45 | .field_attribute( 46 | ".helium.tagged_spreading.region_spreading", 47 | "#[serde(with = \"serde_region_spreading\" )]", 48 | ) 49 | }; 50 | } 51 | 52 | #[cfg(feature = "services")] 53 | fn main() -> Result<()> { 54 | config!(tonic_prost_build::configure()) 55 | .build_server(true) 56 | .build_client(true) 57 | .compile_protos( 58 | &MESSAGES 59 | .iter() 60 | .chain(SERVICES) 61 | .copied() 62 | .collect::>(), 63 | &["src"], 64 | )?; 65 | Ok(()) 66 | } 67 | 68 | #[cfg(not(feature = "services"))] 69 | fn main() -> Result<()> { 70 | config!(prost_build::Config::new()).compile_protos(MESSAGES, &["src"])?; 71 | Ok(()) 72 | } 73 | -------------------------------------------------------------------------------- /include/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helium/proto/0f855947f76ced999591fdf1592db05c57df3b57/include/.keep -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@helium/proto", 3 | "version": "2.2.0", 4 | "description": "Helium protobuf definitions compiled to JS with TypeScript types", 5 | "main": "build/index.js", 6 | "repository": "git@github.com:helium/proto.git", 7 | "contributors": [ 8 | "Andrew Allen " 9 | ], 10 | "license": "Apache-2.0", 11 | "publishConfig": { 12 | "access": "public" 13 | }, 14 | "files": [ 15 | "build" 16 | ], 17 | "scripts": { 18 | "clean": "rimraf build", 19 | "setup": "mkdirp build", 20 | "compile": "pbjs -w commonjs -t static-module -o build/index.js src/*.proto src/service/*.proto", 21 | "types": "pbts -o build/index.d.ts build/index.js", 22 | "build": "yarn clean && yarn setup && yarn compile && yarn types", 23 | "test": "jest" 24 | }, 25 | "dependencies": { 26 | "protobufjs": "^6.11.3" 27 | }, 28 | "devDependencies": { 29 | "jest": "^25.4.0", 30 | "mkdirp": "^1.0.4", 31 | "node-notifier": "^10.0.1", 32 | "rimraf": "^3.0.2" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /rebar.config: -------------------------------------------------------------------------------- 1 | {erl_opts, [ 2 | debug_info, 3 | {i, "./_build/default/plugins/gpb/include"}, 4 | warnings_as_errors 5 | ]}. 6 | 7 | 8 | {plugins, [{rebar3_gpb_plugin, "2.22.1"}]}. 9 | 10 | {provider_hooks, [ 11 | {pre, [ 12 | {compile, {protobuf, compile}}, 13 | {clean, {protobuf, clean}} 14 | ]} 15 | ]}. 16 | 17 | {gpb_opts, [ 18 | {i, "src"}, 19 | {recursive, false}, 20 | {o_erl, "src/pb"}, 21 | {o_hrl, "include"}, 22 | {module_name_prefix, ""}, 23 | {module_name_suffix, "_pb"}, 24 | {msg_name_prefix, ""}, 25 | {msg_name_suffix, "_pb"}, 26 | {strings_as_binaries, false}, 27 | type_specs 28 | ]}. 29 | -------------------------------------------------------------------------------- /rebar.lock: -------------------------------------------------------------------------------- 1 | []. 2 | -------------------------------------------------------------------------------- /rebar3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helium/proto/0f855947f76ced999591fdf1592db05c57df3b57/rebar3 -------------------------------------------------------------------------------- /release.toml: -------------------------------------------------------------------------------- 1 | sign-commit = true 2 | dev-version-ext = "dev" 3 | disable-publish = true 4 | -------------------------------------------------------------------------------- /src/blockchain_block.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | import "blockchain_block_v1.proto"; 4 | 5 | message blockchain_block { 6 | oneof block { blockchain_block_v1 v1 = 1; } 7 | } -------------------------------------------------------------------------------- /src/blockchain_block_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | import "blockchain_txn.proto"; 4 | 5 | message blockchain_signature_v1 { 6 | bytes signer = 1; 7 | bytes signature = 2; 8 | } 9 | 10 | message blockchain_seen_vote_v1 { 11 | uint32 index = 1; 12 | bytes vector = 2; 13 | } 14 | 15 | message blockchain_block_v1 { 16 | bytes prev_hash = 1; 17 | uint64 height = 2; 18 | uint64 time = 3; 19 | uint64 hbbft_round = 4; 20 | repeated blockchain_txn transactions = 5; 21 | repeated blockchain_signature_v1 signatures = 6; 22 | uint64 election_epoch = 7; 23 | uint64 epoch_start = 8; 24 | bytes rescue_signature = 9; 25 | repeated blockchain_seen_vote_v1 seen_votes = 10; 26 | bytes bba_completion = 11; 27 | bytes snapshot_hash = 12; 28 | repeated bytes rescue_signatures = 13; 29 | } 30 | -------------------------------------------------------------------------------- /src/blockchain_gossip_handler.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | message blockchain_gossip_block { 4 | bytes from = 1; 5 | bytes block = 2; 6 | bytes hash = 3; 7 | uint64 height = 4; 8 | } 9 | -------------------------------------------------------------------------------- /src/blockchain_ledger_entry_v2.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_ledger_entry_v2 { 5 | // NOTE: might need to add owner:binary here for portability reasons, 6 | // leaving that out for now to revisit later. 7 | 8 | // Top level nonce since entry-specific nonces don't really matter 9 | uint64 nonce = 1; 10 | uint64 hnt_balance = 2; 11 | uint64 hst_balance = 3; 12 | uint64 mobile_balance = 4; 13 | uint64 iot_balance = 5; 14 | } 15 | -------------------------------------------------------------------------------- /src/blockchain_ledger_subnetwork_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | import "blockchain_token_type_v1.proto"; 5 | 6 | message blockchain_ledger_subnetwork_v1 { 7 | blockchain_token_type_v1 type = 1; 8 | uint64 token_treasury = 2; 9 | uint64 hnt_treasury = 3; 10 | bytes subnetwork_key = 4; 11 | repeated bytes reward_server_keys = 5; 12 | // this nonce is updated by the update_subnetwork transaction 13 | uint64 nonce = 6; 14 | uint64 last_rewarded_block = 7; 15 | } 16 | -------------------------------------------------------------------------------- /src/blockchain_poc_core_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | enum origin { 5 | p2p = 0; 6 | radio = 1; 7 | } 8 | 9 | message blockchain_poc_receipt_v1 { 10 | bytes gateway = 1; 11 | uint64 timestamp = 2; 12 | sint32 signal = 3; 13 | bytes data = 4; 14 | origin origin = 5; 15 | bytes signature = 6; 16 | float snr = 7; 17 | float frequency = 8; 18 | int32 channel = 9; 19 | string datarate = 10; 20 | bytes addr_hash = 11; 21 | // Transmit power at which this packet was transmitted 22 | // It is x10, for example: 270 = 27db, 36 = 3.6db etc 23 | int32 tx_power = 12; 24 | // fixed point reward shares added by off-chain poc verifier, 25 | // propose 2 decimal places 26 | uint32 reward_shares = 13; 27 | } 28 | 29 | message blockchain_poc_witness_v1 { 30 | bytes gateway = 1; 31 | uint64 timestamp = 2; 32 | sint32 signal = 3; 33 | bytes packet_hash = 4; 34 | bytes signature = 5; 35 | float snr = 6; 36 | float frequency = 7; 37 | int32 channel = 8; 38 | string datarate = 9; 39 | // fixed point reward shares added by off-chain poc verifier, 40 | // propose 2 decimal places 41 | uint32 reward_shares = 10; 42 | } 43 | 44 | message blockchain_poc_response_v1 { 45 | oneof payload { 46 | blockchain_poc_receipt_v1 receipt = 1; 47 | blockchain_poc_witness_v1 witness = 2; 48 | } 49 | } 50 | 51 | message blockchain_poc_path_element_v1 { 52 | bytes challengee = 1; 53 | blockchain_poc_receipt_v1 receipt = 2; 54 | repeated blockchain_poc_witness_v1 witnesses = 3; 55 | } 56 | -------------------------------------------------------------------------------- /src/blockchain_region_param_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium; 4 | 5 | message blockchain_region_params_v1 { 6 | repeated blockchain_region_param_v1 region_params = 1; 7 | } 8 | 9 | enum RegionSpreading { 10 | SF_INVALID = 0; 11 | SF7 = 1; 12 | SF8 = 2; 13 | SF9 = 3; 14 | SF10 = 4; 15 | SF11 = 5; 16 | SF12 = 6; 17 | } 18 | 19 | message tagged_spreading { 20 | RegionSpreading region_spreading = 1; 21 | uint32 max_packet_size = 2; 22 | } 23 | 24 | message blockchain_region_spreading_v1 { 25 | repeated tagged_spreading tagged_spreading = 1; 26 | } 27 | 28 | message blockchain_region_param_v1 { 29 | // in hertz 30 | uint64 channel_frequency = 1; 31 | // in hertz 32 | uint32 bandwidth = 2; 33 | // in dBi x 10 34 | uint32 max_eirp = 3; 35 | // list of atoms 36 | blockchain_region_spreading_v1 spreading = 4; 37 | } 38 | -------------------------------------------------------------------------------- /src/blockchain_routing_address.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium; 4 | 5 | message routing_address { 6 | bytes pub_key = 1; 7 | bytes uri = 2; 8 | } 9 | -------------------------------------------------------------------------------- /src/blockchain_snapshot_handler.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | message blockchain_snapshot_req { 4 | uint64 height = 1; 5 | bytes hash = 2; 6 | } 7 | 8 | message blockchain_snapshot_resp { 9 | sint64 next_height = 1; 10 | bytes snapshot = 2; 11 | } 12 | -------------------------------------------------------------------------------- /src/blockchain_state_channel_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium; 4 | 5 | import "packet.proto"; 6 | import "region.proto"; 7 | 8 | enum blockchain_state_channel_state_v1 { 9 | open = 0; 10 | closed = 1; 11 | } 12 | 13 | message blockchain_state_channel_summary_v1 { 14 | bytes client_pubkeybin = 1; 15 | uint64 num_packets = 2; 16 | uint64 num_dcs = 3; 17 | } 18 | 19 | message blockchain_state_channel_v1 { 20 | bytes id = 1; 21 | bytes owner = 2; 22 | uint64 credits = 3; 23 | uint64 nonce = 4; 24 | repeated blockchain_state_channel_summary_v1 summaries = 5; 25 | bytes root_hash = 6; 26 | // This is unused but we can't remove it yet 27 | bytes skewed = 7; 28 | blockchain_state_channel_state_v1 state = 8; 29 | uint64 expire_at_block = 9; 30 | bytes signature = 10; 31 | } 32 | 33 | message blockchain_state_channel_response_v1 { 34 | bool accepted = 1; 35 | packet downlink = 4; 36 | } 37 | 38 | message blockchain_state_channel_packet_v1 { 39 | packet packet = 1; 40 | bytes hotspot = 2; 41 | bytes signature = 3; 42 | region region = 4; 43 | uint64 hold_time = 5; 44 | } 45 | 46 | message blockchain_state_channel_offer_v1 { 47 | routing_information routing = 1; 48 | bytes packet_hash = 2; 49 | uint64 payload_size = 3; 50 | uint32 fcnt = 4; 51 | bytes hotspot = 5; 52 | bytes signature = 6; 53 | region region = 7; 54 | bool req_diff = 8; 55 | } 56 | 57 | message blockchain_state_channel_purchase_v1 { 58 | blockchain_state_channel_v1 sc = 1; 59 | bytes hotspot = 2; 60 | bytes packet_hash = 3; 61 | region region = 4; 62 | blockchain_state_channel_diff_v1 sc_diff = 5; 63 | } 64 | 65 | message blockchain_state_channel_diff_v1 { 66 | bytes id = 1; 67 | uint64 add_nonce = 2; 68 | bytes signature = 3; 69 | repeated blockchain_state_channel_diff_entry_v1 diffs = 4; 70 | } 71 | 72 | message blockchain_state_channel_diff_entry_v1 { 73 | oneof entry { 74 | blockchain_state_channel_diff_append_summary_v1 append = 1; 75 | blockchain_state_channel_diff_update_summary_v1 add = 2; 76 | } 77 | } 78 | 79 | message blockchain_state_channel_diff_append_summary_v1 { 80 | bytes client_pubkeybin = 1; 81 | uint64 num_packets = 2; 82 | uint64 num_dcs = 3; 83 | } 84 | 85 | message blockchain_state_channel_diff_update_summary_v1 { 86 | uint64 client_index = 1; 87 | uint64 add_packets = 2; 88 | uint64 add_dcs = 3; 89 | } 90 | 91 | // DEPRECATED 92 | message blockchain_state_channel_banner_v1 { 93 | blockchain_state_channel_v1 sc = 1; 94 | } 95 | 96 | message blockchain_state_channel_rejection_v1 { 97 | uint32 reject = 1; 98 | bytes packet_hash = 2; 99 | } 100 | 101 | message blockchain_state_channel_message_v1 { 102 | oneof msg { 103 | blockchain_state_channel_response_v1 response = 2; 104 | blockchain_state_channel_packet_v1 packet = 4; 105 | blockchain_state_channel_offer_v1 offer = 5; 106 | blockchain_state_channel_purchase_v1 purchase = 6; 107 | blockchain_state_channel_banner_v1 banner = 7; // DEPRECATED 108 | blockchain_state_channel_rejection_v1 reject = 8; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/blockchain_sync_handler.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | message blockchain_sync_hash { 4 | bytes hash = 1; 5 | repeated uint64 heights = 2; 6 | } 7 | 8 | message blockchain_sync_blocks { 9 | repeated bytes blocks = 1; 10 | bool final = 2; 11 | } 12 | 13 | message blockchain_sync_req { 14 | oneof msg { 15 | blockchain_sync_hash hash = 1; 16 | bool response = 2; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/blockchain_token_type_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | enum blockchain_token_type_v1 { 5 | hnt = 0; 6 | hst = 1; 7 | mobile = 2; 8 | iot = 3; 9 | } 10 | -------------------------------------------------------------------------------- /src/blockchain_txn.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium; 4 | 5 | import "blockchain_txn_coinbase_v1.proto"; 6 | import "blockchain_txn_security_coinbase_v1.proto"; 7 | import "blockchain_txn_oui_v1.proto"; 8 | import "blockchain_txn_gen_gateway_v1.proto"; 9 | import "blockchain_txn_routing_v1.proto"; 10 | import "blockchain_txn_payment_v1.proto"; 11 | import "blockchain_txn_security_exchange_v1.proto"; 12 | import "blockchain_txn_consensus_group_v1.proto"; 13 | import "blockchain_txn_consensus_group_failure_v1.proto"; 14 | import "blockchain_txn_add_gateway_v1.proto"; 15 | import "blockchain_txn_assert_location_v1.proto"; 16 | import "blockchain_txn_create_htlc_v1.proto"; 17 | import "blockchain_txn_redeem_htlc_v1.proto"; 18 | import "blockchain_txn_poc_request_v1.proto"; 19 | import "blockchain_txn_poc_receipts_v1.proto"; 20 | import "blockchain_txn_poc_receipts_v2.proto"; 21 | import "blockchain_txn_vars_v1.proto"; 22 | import "blockchain_txn_rewards_v1.proto"; 23 | import "blockchain_txn_token_burn_v1.proto"; 24 | import "blockchain_txn_dc_coinbase_v1.proto"; 25 | import "blockchain_txn_token_burn_exchange_rate_v1.proto"; 26 | import "blockchain_txn_state_channel_open_v1.proto"; 27 | import "blockchain_txn_update_gateway_oui_v1.proto"; 28 | import "blockchain_txn_state_channel_close_v1.proto"; 29 | import "blockchain_txn_payment_v2.proto"; 30 | import "blockchain_txn_price_oracle_v1.proto"; 31 | import "blockchain_txn_gen_price_oracle_v1.proto"; 32 | import "blockchain_txn_transfer_hotspot_v1.proto"; 33 | import "blockchain_txn_rewards_v2.proto"; 34 | 35 | import "blockchain_txn_gen_validator_v1.proto"; 36 | import "blockchain_txn_stake_validator_v1.proto"; 37 | import "blockchain_txn_transfer_validator_stake_v1.proto"; 38 | import "blockchain_txn_unstake_validator_v1.proto"; 39 | import "blockchain_txn_validator_heartbeat_v1.proto"; 40 | 41 | import "blockchain_txn_assert_location_v2.proto"; 42 | import "blockchain_txn_transfer_hotspot_v2.proto"; 43 | 44 | import "blockchain_txn_add_subnetwork_v1.proto"; 45 | import "blockchain_txn_update_subnetwork_v1.proto"; 46 | import "blockchain_txn_subnetwork_rewards_v1.proto"; 47 | import "blockchain_txn_subnetwork_fund_v1.proto"; 48 | 49 | import "blockchain_txn_token_redeem_v1.proto"; 50 | 51 | message blockchain_txn { 52 | oneof txn { 53 | blockchain_txn_add_gateway_v1 add_gateway = 1; 54 | blockchain_txn_assert_location_v1 assert_location = 2; 55 | blockchain_txn_coinbase_v1 coinbase = 3; 56 | blockchain_txn_create_htlc_v1 create_htlc = 4; 57 | blockchain_txn_gen_gateway_v1 gen_gateway = 5; 58 | blockchain_txn_consensus_group_v1 consensus_group = 6; 59 | blockchain_txn_oui_v1 oui = 7; 60 | blockchain_txn_payment_v1 payment = 8; 61 | blockchain_txn_poc_receipts_v1 poc_receipts = 9; 62 | blockchain_txn_poc_request_v1 poc_request = 10; 63 | blockchain_txn_redeem_htlc_v1 redeem_htlc = 11; 64 | blockchain_txn_security_coinbase_v1 security_coinbase = 12; 65 | blockchain_txn_routing_v1 routing = 13; 66 | blockchain_txn_security_exchange_v1 security_exchange = 14; 67 | blockchain_txn_vars_v1 vars = 15; 68 | blockchain_txn_rewards_v1 rewards = 16; 69 | blockchain_txn_token_burn_v1 token_burn = 17; 70 | blockchain_txn_dc_coinbase_v1 dc_coinbase = 18; 71 | blockchain_txn_token_burn_exchange_rate_v1 token_burn_exchange_rate = 19; 72 | blockchain_txn_bundle_v1 bundle = 20; 73 | blockchain_txn_state_channel_open_v1 state_channel_open = 21; 74 | blockchain_txn_update_gateway_oui_v1 update_gateway_oui = 22; 75 | blockchain_txn_state_channel_close_v1 state_channel_close = 23; 76 | blockchain_txn_payment_v2 payment_v2 = 24; 77 | blockchain_txn_price_oracle_v1 price_oracle_submission = 25; 78 | blockchain_txn_gen_price_oracle_v1 gen_price_oracle = 26; 79 | blockchain_txn_transfer_hotspot_v1 transfer_hotspot = 27; 80 | blockchain_txn_gen_validator_v1 gen_validator = 28; 81 | blockchain_txn_stake_validator_v1 stake_validator = 29; 82 | blockchain_txn_transfer_validator_stake_v1 transfer_val_stake = 30; 83 | blockchain_txn_unstake_validator_v1 unstake_validator = 31; 84 | blockchain_txn_validator_heartbeat_v1 val_heartbeat = 32; 85 | blockchain_txn_consensus_group_failure_v1 consensus_group_failure = 33; 86 | blockchain_txn_rewards_v2 rewards_v2 = 34; 87 | blockchain_txn_assert_location_v2 assert_location_v2 = 35; 88 | blockchain_txn_transfer_hotspot_v2 transfer_hotspot_v2 = 36; 89 | blockchain_txn_poc_receipts_v2 poc_receipts_v2 = 37; 90 | blockchain_txn_add_subnetwork_v1 add_subnetwork = 38; 91 | blockchain_txn_update_subnetwork_v1 update_subnetwork = 39; 92 | blockchain_txn_subnetwork_rewards_v1 subnetwork_rewards = 40; 93 | blockchain_txn_token_redeem_v1 token_redeem = 41; 94 | blockchain_txn_subnetwork_fund_v1 subnetwork_fund = 42; 95 | } 96 | } 97 | 98 | message blockchain_txn_bundle_v1 { repeated blockchain_txn transactions = 1; } 99 | -------------------------------------------------------------------------------- /src/blockchain_txn_add_gateway_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium; 4 | 5 | message blockchain_txn_add_gateway_v1 { 6 | bytes owner = 1; 7 | bytes gateway = 2; 8 | bytes owner_signature = 3; 9 | bytes gateway_signature = 4; 10 | bytes payer = 5; 11 | bytes payer_signature = 6; 12 | uint64 staking_fee = 7; 13 | uint64 fee = 8; 14 | } -------------------------------------------------------------------------------- /src/blockchain_txn_add_subnetwork_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | import "blockchain_token_type_v1.proto"; 5 | 6 | message blockchain_txn_add_subnetwork_v1 { 7 | blockchain_token_type_v1 token_type = 1; 8 | 9 | bytes subnetwork_key = 2; 10 | repeated bytes reward_server_keys = 3; 11 | uint64 premine = 4; 12 | 13 | bytes network_signature = 5; 14 | bytes subnetwork_signature = 6; 15 | } 16 | -------------------------------------------------------------------------------- /src/blockchain_txn_assert_location_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_assert_location_v1 { 5 | bytes gateway = 1; 6 | bytes owner = 2; 7 | bytes payer = 3; 8 | bytes gateway_signature = 4; 9 | bytes owner_signature = 5; 10 | bytes payer_signature = 6; 11 | // Use the h3 string representation since it will use all 64 bits 12 | // (and JS doesn't support that) 13 | string location = 7; 14 | uint64 nonce = 8; 15 | uint64 staking_fee = 9; 16 | uint64 fee = 10; 17 | } -------------------------------------------------------------------------------- /src/blockchain_txn_assert_location_v2.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | // NOTE: This transaction does not include gateway_signature field 5 | 6 | message blockchain_txn_assert_location_v2 { 7 | bytes gateway = 1; 8 | bytes owner = 2; 9 | bytes payer = 3; 10 | bytes owner_signature = 4; 11 | bytes payer_signature = 5; 12 | // Use the h3 string representation since it will use all 64 bits 13 | // (and JS doesn't support that) 14 | string location = 6; 15 | uint64 nonce = 7; 16 | // It is assumed that this gain applies to both rx and tx 17 | int32 gain = 8; 18 | int32 elevation = 9; 19 | uint64 staking_fee = 10; 20 | uint64 fee = 11; 21 | } 22 | -------------------------------------------------------------------------------- /src/blockchain_txn_coinbase_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | import "blockchain_token_type_v1.proto"; 5 | 6 | message blockchain_txn_coinbase_v1 { 7 | bytes payee = 1; 8 | uint64 amount = 2; 9 | blockchain_token_type_v1 token_type = 3; 10 | } 11 | -------------------------------------------------------------------------------- /src/blockchain_txn_consensus_group_failure_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_consensus_group_failure_v1 { 5 | repeated bytes failed_members = 1; 6 | uint64 height = 2; 7 | uint64 delay = 3; 8 | repeated bytes members = 4; 9 | repeated bytes signatures = 5; 10 | } 11 | -------------------------------------------------------------------------------- /src/blockchain_txn_consensus_group_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_consensus_group_v1 { 5 | repeated bytes members = 1; 6 | bytes proof = 2; 7 | uint64 height = 3; 8 | uint32 delay = 4; 9 | } 10 | -------------------------------------------------------------------------------- /src/blockchain_txn_create_htlc_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_create_htlc_v1 { 5 | bytes payer = 1; 6 | bytes payee = 2; 7 | bytes address = 3; 8 | bytes hashlock = 4; 9 | uint64 timelock = 5; 10 | uint64 amount = 6; 11 | uint64 fee = 7; 12 | bytes signature = 8; 13 | uint64 nonce = 9; 14 | } -------------------------------------------------------------------------------- /src/blockchain_txn_dc_coinbase_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_dc_coinbase_v1 { 5 | bytes payee = 1; 6 | uint64 amount = 2; 7 | } -------------------------------------------------------------------------------- /src/blockchain_txn_gen_gateway_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_gen_gateway_v1 { 5 | bytes gateway = 1; 6 | bytes owner = 2; 7 | string location = 3; 8 | uint64 nonce = 4; 9 | } 10 | -------------------------------------------------------------------------------- /src/blockchain_txn_gen_price_oracle_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_gen_price_oracle_v1 { uint64 price = 1; } 5 | -------------------------------------------------------------------------------- /src/blockchain_txn_gen_validator_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_gen_validator_v1 { 5 | bytes address = 1; 6 | bytes owner = 2; 7 | uint64 stake = 3; 8 | } 9 | -------------------------------------------------------------------------------- /src/blockchain_txn_handler.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium; 4 | import "blockchain_txn.proto"; 5 | 6 | enum request_type { 7 | submit = 0; 8 | update = 1; 9 | } 10 | 11 | message blockchain_txn_request_v1 { 12 | request_type type = 1; 13 | bytes key = 2; 14 | blockchain_txn txn = 3; 15 | } 16 | 17 | message blockchain_txn_info_v1 { 18 | bytes result = 1; 19 | bytes details = 2; 20 | bytes trace = 3; 21 | uint64 height = 4; 22 | uint32 queue_pos = 5; 23 | uint32 queue_len = 6; 24 | uint32 txn_protocol_version = 7; 25 | } 26 | -------------------------------------------------------------------------------- /src/blockchain_txn_oui_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_oui_v1 { 5 | bytes owner = 1; 6 | repeated bytes addresses = 2; 7 | bytes filter = 3; 8 | uint32 requested_subnet_size = 4; 9 | bytes payer = 5; 10 | uint64 staking_fee = 6; 11 | uint64 fee = 7; 12 | bytes owner_signature = 8; 13 | bytes payer_signature = 9; 14 | uint64 oui = 10; 15 | } 16 | -------------------------------------------------------------------------------- /src/blockchain_txn_payment_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_payment_v1 { 5 | bytes payer = 1; 6 | bytes payee = 2; 7 | uint64 amount = 3; 8 | uint64 fee = 4; 9 | uint64 nonce = 5; 10 | bytes signature = 6; 11 | } -------------------------------------------------------------------------------- /src/blockchain_txn_payment_v2.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | import "blockchain_token_type_v1.proto"; 5 | 6 | message blockchain_txn_payment_v2 { 7 | bytes payer = 1; 8 | repeated payment payments = 2; 9 | uint64 fee = 3; 10 | uint64 nonce = 4; 11 | bytes signature = 5; 12 | } 13 | 14 | message payment { 15 | bytes payee = 1; 16 | uint64 amount = 2; 17 | uint64 memo = 3; 18 | bool max = 4; 19 | blockchain_token_type_v1 token_type = 5; 20 | } 21 | -------------------------------------------------------------------------------- /src/blockchain_txn_poc_receipts_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | import "blockchain_poc_core_v1.proto"; 4 | 5 | message blockchain_txn_poc_receipts_v1 { 6 | bytes challenger = 1; 7 | bytes secret = 2; 8 | bytes onion_key_hash = 3; 9 | repeated blockchain_poc_path_element_v1 path = 4; 10 | uint64 fee = 5; 11 | bytes signature = 6; 12 | bytes request_block_hash = 7; 13 | } 14 | -------------------------------------------------------------------------------- /src/blockchain_txn_poc_receipts_v2.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | import "blockchain_poc_core_v1.proto"; 5 | 6 | message blockchain_txn_poc_receipts_v2 { 7 | bytes challenger = 1; 8 | bytes secret = 2; 9 | bytes onion_key_hash = 3; 10 | repeated blockchain_poc_path_element_v1 path = 4; 11 | uint64 fee = 5; 12 | bytes signature = 6; 13 | bytes block_hash = 7; 14 | // used for off-chain poc replay prevention 15 | uint64 timestamp = 8; 16 | } 17 | -------------------------------------------------------------------------------- /src/blockchain_txn_poc_request_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_poc_request_v1 { 5 | bytes challenger = 1; 6 | bytes secret_hash = 2; 7 | bytes onion_key_hash = 3; 8 | bytes block_hash = 4; 9 | uint64 fee = 5; 10 | bytes signature = 6; 11 | uint32 version = 7; 12 | } 13 | -------------------------------------------------------------------------------- /src/blockchain_txn_price_oracle_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_price_oracle_v1 { 5 | bytes public_key = 1; 6 | uint64 price = 2; 7 | uint64 block_height = 3; 8 | bytes signature = 4; 9 | } 10 | -------------------------------------------------------------------------------- /src/blockchain_txn_redeem_htlc_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_redeem_htlc_v1 { 5 | bytes payee = 1; 6 | bytes address = 2; 7 | bytes preimage = 3; 8 | uint64 fee = 4; 9 | bytes signature = 5; 10 | } -------------------------------------------------------------------------------- /src/blockchain_txn_rewards_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_reward_v1 { 5 | enum Type { 6 | securities = 0; 7 | data_credits = 1; 8 | poc_challengees = 2; 9 | poc_challengers = 3; 10 | poc_witnesses = 4; 11 | consensus = 5; 12 | } 13 | bytes account = 1; 14 | bytes gateway = 3; 15 | uint64 amount = 4; 16 | Type type = 5; 17 | } 18 | 19 | message blockchain_txn_rewards_v1 { 20 | uint64 start_epoch = 1; 21 | uint64 end_epoch = 2; 22 | repeated blockchain_txn_reward_v1 rewards = 3; 23 | } 24 | -------------------------------------------------------------------------------- /src/blockchain_txn_rewards_v2.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_reward_v2 { 5 | bytes account = 1; 6 | uint64 amount = 2; 7 | } 8 | 9 | message blockchain_txn_rewards_v2 { 10 | uint64 start_epoch = 1; 11 | uint64 end_epoch = 2; 12 | repeated blockchain_txn_reward_v2 rewards = 3; 13 | } 14 | -------------------------------------------------------------------------------- /src/blockchain_txn_routing_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message update_routers { 5 | repeated bytes router_addresses = 1; // max of 3 6 | } 7 | 8 | message update_xor { 9 | uint32 index = 1; // we allow up to 5 10 | bytes filter = 2; // 100kb or less 11 | } 12 | 13 | message blockchain_txn_routing_v1 { 14 | uint32 oui = 1; 15 | bytes owner = 2; 16 | oneof update { 17 | update_routers update_routers = 3; 18 | bytes new_xor = 4; // 100kb or less 19 | update_xor update_xor = 5; 20 | uint32 request_subnet = 6; // number of addresses to request 21 | } 22 | uint64 fee = 7; 23 | uint64 nonce = 8; 24 | bytes signature = 9; 25 | uint64 staking_fee = 10; 26 | } 27 | -------------------------------------------------------------------------------- /src/blockchain_txn_security_coinbase_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_security_coinbase_v1 { 5 | bytes payee = 1; 6 | uint64 amount = 2; 7 | } -------------------------------------------------------------------------------- /src/blockchain_txn_security_exchange_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_security_exchange_v1 { 5 | bytes payer = 1; 6 | bytes payee = 2; 7 | uint64 amount = 3; 8 | uint64 fee = 4; 9 | uint64 nonce = 5; 10 | bytes signature = 6; 11 | } -------------------------------------------------------------------------------- /src/blockchain_txn_stake_validator_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_stake_validator_v1 { 5 | bytes address = 1; 6 | bytes owner = 2; 7 | uint64 stake = 3; 8 | bytes owner_signature = 4; 9 | uint64 fee = 5; 10 | } 11 | -------------------------------------------------------------------------------- /src/blockchain_txn_state_channel_close_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium; 4 | 5 | import "blockchain_state_channel_v1.proto"; 6 | 7 | message blockchain_txn_state_channel_close_v1 { 8 | blockchain_state_channel_v1 state_channel = 1; 9 | bytes closer = 2; 10 | bytes signature = 3; 11 | uint64 fee = 4; 12 | blockchain_state_channel_v1 conflicts_with = 5; 13 | } 14 | -------------------------------------------------------------------------------- /src/blockchain_txn_state_channel_open_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium; 4 | 5 | message blockchain_txn_state_channel_open_v1 { 6 | bytes id = 1; 7 | bytes owner = 2; 8 | int64 amount = 3; 9 | int64 expire_within = 4; 10 | uint64 oui = 5; 11 | uint64 nonce = 6; 12 | bytes signature = 7; 13 | uint64 fee = 8; 14 | } 15 | -------------------------------------------------------------------------------- /src/blockchain_txn_subnetwork_fund_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | import "blockchain_token_type_v1.proto"; 5 | 6 | message blockchain_txn_subnetwork_fund_v1 { 7 | blockchain_token_type_v1 token_type = 1; 8 | uint64 amount = 2; 9 | uint64 nonce = 3; 10 | bytes payer = 4; 11 | bytes signature = 5; 12 | uint64 fee = 6; 13 | } 14 | -------------------------------------------------------------------------------- /src/blockchain_txn_subnetwork_rewards_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | import "blockchain_token_type_v1.proto"; 5 | 6 | message subnetwork_reward { 7 | bytes account = 1; 8 | uint64 amount = 2; 9 | } 10 | 11 | message subnetwork_rewards { 12 | uint64 start_epoch = 1; 13 | uint64 end_epoch = 2; 14 | repeated subnetwork_reward rewards = 3; 15 | } 16 | 17 | message blockchain_txn_subnetwork_rewards_v1 { 18 | blockchain_token_type_v1 token_type = 1; 19 | uint64 start_epoch = 2; 20 | uint64 end_epoch = 3; 21 | bytes reward_server_signature = 4; 22 | repeated subnetwork_reward rewards = 5; 23 | } 24 | -------------------------------------------------------------------------------- /src/blockchain_txn_token_burn_exchange_rate_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_token_burn_exchange_rate_v1 { uint64 rate = 1; } -------------------------------------------------------------------------------- /src/blockchain_txn_token_burn_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_token_burn_v1 { 5 | bytes payer = 1; 6 | bytes payee = 2; 7 | uint64 amount = 3; 8 | uint64 nonce = 4; 9 | bytes signature = 5; 10 | uint64 fee = 6; 11 | uint64 memo = 7; 12 | } 13 | -------------------------------------------------------------------------------- /src/blockchain_txn_token_redeem_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | import "blockchain_token_type_v1.proto"; 5 | 6 | message blockchain_txn_token_redeem_v1 { 7 | blockchain_token_type_v1 token_type = 1; 8 | bytes account = 2; 9 | uint64 amount = 3; 10 | 11 | bytes signature = 4; 12 | uint64 nonce = 5; 13 | 14 | uint64 fee = 6; 15 | } 16 | -------------------------------------------------------------------------------- /src/blockchain_txn_transfer_hotspot_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_transfer_hotspot_v1 { 5 | bytes gateway = 1; 6 | bytes seller = 2; 7 | bytes buyer = 3; 8 | bytes seller_signature = 4; 9 | bytes buyer_signature = 5; 10 | uint64 buyer_nonce = 11 | 6; // buyer's next payment nonce, required even if payment is 0 12 | uint64 amount_to_seller = 7; // in bones not raw HNT 13 | uint64 fee = 8; 14 | } 15 | -------------------------------------------------------------------------------- /src/blockchain_txn_transfer_hotspot_v2.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_transfer_hotspot_v2 { 5 | bytes gateway = 1; 6 | bytes owner = 2; 7 | bytes owner_signature = 3; 8 | bytes new_owner = 4; 9 | uint64 fee = 5; 10 | // gateway nonce 11 | uint64 nonce = 6; 12 | } 13 | -------------------------------------------------------------------------------- /src/blockchain_txn_transfer_validator_stake_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_transfer_validator_stake_v1 { 5 | bytes old_address = 1; 6 | bytes new_address = 2; 7 | bytes old_owner = 3; 8 | bytes new_owner = 4; 9 | bytes old_owner_signature = 5; 10 | bytes new_owner_signature = 6; 11 | uint64 fee = 7; 12 | uint64 stake_amount = 8; // for accounting 13 | // optional amount (in bones) the new owner is transferring to the old owner 14 | uint64 payment_amount = 9; 15 | } 16 | -------------------------------------------------------------------------------- /src/blockchain_txn_unstake_validator_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_unstake_validator_v1 { 5 | bytes address = 1; 6 | bytes owner = 2; 7 | bytes owner_signature = 3; 8 | uint64 fee = 4; 9 | uint64 stake_amount = 5; 10 | uint64 stake_release_height = 6; 11 | } 12 | -------------------------------------------------------------------------------- /src/blockchain_txn_update_gateway_oui_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_update_gateway_oui_v1 { 5 | bytes gateway = 1; 6 | uint64 oui = 2; 7 | uint64 nonce = 3; 8 | uint64 fee = 4; 9 | bytes gateway_owner_signature = 5; 10 | bytes oui_owner_signature = 6; 11 | } -------------------------------------------------------------------------------- /src/blockchain_txn_update_subnetwork_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium; 4 | 5 | message blockchain_txn_update_subnetwork_v1 { 6 | bytes subnetwork_key = 1; 7 | bytes network_signature = 2; 8 | 9 | repeated bytes reward_server_keys = 3; 10 | bytes subnetwork_signature = 4; 11 | 12 | uint64 nonce = 5; 13 | } 14 | -------------------------------------------------------------------------------- /src/blockchain_txn_validator_heartbeat_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_txn_validator_heartbeat_v1 { 5 | bytes address = 1; 6 | uint64 height = 2; 7 | uint32 version = 3; 8 | bytes signature = 4; 9 | repeated bytes poc_key_proposals = 5; 10 | repeated bytes reactivated_gws = 6; 11 | } 12 | -------------------------------------------------------------------------------- /src/blockchain_txn_vars_v1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message blockchain_var_v1 { 5 | string name = 1; 6 | string type = 2; 7 | bytes value = 3; 8 | } 9 | 10 | message blockchain_txn_vars_v1 { 11 | repeated blockchain_var_v1 vars = 1; 12 | uint32 version_predicate = 2; 13 | bytes proof = 3; 14 | bytes master_key = 4; 15 | bytes key_proof = 5; 16 | repeated bytes cancels = 6; 17 | repeated bytes unsets = 7; 18 | uint32 nonce = 8; 19 | repeated bytes multi_keys = 9; 20 | repeated bytes multi_proofs = 10; 21 | repeated bytes multi_key_proofs = 11; 22 | } 23 | -------------------------------------------------------------------------------- /src/data_rate.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium; 4 | 5 | enum data_rate { 6 | SF12BW125 = 0; 7 | SF11BW125 = 1; 8 | SF10BW125 = 2; 9 | SF9BW125 = 3; 10 | SF8BW125 = 4; 11 | SF7BW125 = 5; 12 | SF12BW250 = 6; 13 | SF11BW250 = 7; 14 | SF10BW250 = 8; 15 | SF9BW250 = 9; 16 | SF8BW250 = 10; 17 | SF7BW250 = 11; 18 | SF12BW500 = 12; 19 | SF11BW500 = 13; 20 | SF10BW500 = 14; 21 | SF9BW500 = 15; 22 | SF8BW500 = 16; 23 | SF7BW500 = 17; 24 | LRFHSS1BW137 = 18; 25 | LRFHSS2BW137 = 19; 26 | LRFHSS1BW336 = 20; 27 | LRFHSS2BW336 = 21; 28 | LRFHSS1BW1523 = 22; 29 | LRFHSS2BW1523 = 23; 30 | FSK50 = 24; 31 | } 32 | -------------------------------------------------------------------------------- /src/decimal.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package helium; 18 | 19 | option cc_enable_arenas = true; 20 | option go_package = "google.golang.org/genproto/googleapis/type/decimal;decimal"; 21 | option java_multiple_files = true; 22 | option java_outer_classname = "DecimalProto"; 23 | option java_package = "com.google.type"; 24 | option objc_class_prefix = "GTP"; 25 | 26 | // A representation of a decimal value, such as 2.5. Clients may convert values 27 | // into language-native decimal formats, such as Java's [BigDecimal] or 28 | // Python's [decimal.Decimal]. 29 | // 30 | // [BigDecimal]: 31 | // https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/math/BigDecimal.html 32 | // [decimal.Decimal]: https://docs.python.org/3/library/decimal.html 33 | message Decimal { 34 | // The decimal value, as a string. 35 | // 36 | // The string representation consists of an optional sign, `+` (`U+002B`) 37 | // or `-` (`U+002D`), followed by a sequence of zero or more decimal digits 38 | // ("the integer"), optionally followed by a fraction, optionally followed 39 | // by an exponent. 40 | // 41 | // The fraction consists of a decimal point followed by zero or more decimal 42 | // digits. The string must contain at least one digit in either the integer 43 | // or the fraction. The number formed by the sign, the integer and the 44 | // fraction is referred to as the significand. 45 | // 46 | // The exponent consists of the character `e` (`U+0065`) or `E` (`U+0045`) 47 | // followed by one or more decimal digits. 48 | // 49 | // Services **should** normalize decimal values before storing them by: 50 | // 51 | // - Removing an explicitly-provided `+` sign (`+2.5` -> `2.5`). 52 | // - Replacing a zero-length integer value with `0` (`.5` -> `0.5`). 53 | // - Coercing the exponent character to lower-case (`2.5E8` -> `2.5e8`). 54 | // - Removing an explicitly-provided zero exponent (`2.5e0` -> `2.5`). 55 | // 56 | // Services **may** perform additional normalization based on its own needs 57 | // and the internal decimal implementation selected, such as shifting the 58 | // decimal point and exponent value together (example: `2.5e-1` <-> `0.25`). 59 | // Additionally, services **may** preserve trailing zeroes in the fraction 60 | // to indicate increased precision, but are not required to do so. 61 | // 62 | // Note that only the `.` character is supported to divide the integer 63 | // and the fraction; `,` **should not** be supported regardless of locale. 64 | // Additionally, thousand separators **should not** be supported. If a 65 | // service does support them, values **must** be normalized. 66 | // 67 | // The ENBF grammar is: 68 | // 69 | //```text 70 | // DecimalString = 71 | // [Sign] Significand [Exponent]; 72 | // 73 | // Sign = '+' | '-'; 74 | // 75 | // Significand = 76 | // Digits ['.'] [Digits] | [Digits] '.' Digits; 77 | // 78 | // Exponent = ('e' | 'E') [Sign] Digits; 79 | // 80 | // Digits = { '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' }; 81 | //``` 82 | // 83 | // Services **should** clearly document the range of supported values, the 84 | // maximum supported precision (total number of digits), and, if applicable, 85 | // the scale (number of digits after the decimal point), as well as how it 86 | // behaves when receiving out-of-bounds values. 87 | // 88 | // Services **may** choose to accept values passed as input even when the 89 | // value has a higher precision or scale than the service supports, and 90 | // **should** round the value to fit the supported scale. Alternatively, the 91 | // service **may** error with `400 Bad Request` (`INVALID_ARGUMENT` in gRPC) 92 | // if precision would be lost. 93 | // 94 | // Services **should** error with `400 Bad Request` (`INVALID_ARGUMENT` in 95 | // gRPC) if the service receives a value outside of the supported range. 96 | string value = 1; 97 | } 98 | -------------------------------------------------------------------------------- /src/discovery.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium; 4 | 5 | message discovery_start { 6 | bytes hotspot = 1; 7 | repeated bytes packets = 2; 8 | bytes signature = 3; 9 | } 10 | -------------------------------------------------------------------------------- /src/entropy.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium; 4 | 5 | message entropy_report_v1 { 6 | /// The entropy data 7 | bytes data = 1; 8 | /// The start time for the validity of this entropy in seconds since unix 9 | // epoch 10 | uint64 timestamp = 2; 11 | /// The entropy version 12 | uint32 version = 3; 13 | } -------------------------------------------------------------------------------- /src/gateway_staking_mode.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium; 4 | 5 | enum gateway_staking_mode { 6 | dataonly = 0; 7 | full = 1; 8 | light = 2; 9 | } 10 | -------------------------------------------------------------------------------- /src/helium_proto.app.src: -------------------------------------------------------------------------------- 1 | % This file is just here for erl proto gpb 2 | {application, helium_proto, 3 | [{description, "An OTP application"}, 4 | {vsn, "0.1.0"}, 5 | {registered, []}, 6 | {applications, 7 | [kernel, 8 | stdlib, 9 | syntax_tools, 10 | compiler, 11 | crypto, 12 | ssl 13 | ]}, 14 | {env,[]}, 15 | {modules, []}, 16 | {maintainers, []}, 17 | {licenses, ["Apache 2.0"]}, 18 | {links, []} 19 | ]}. 20 | -------------------------------------------------------------------------------- /src/hex_boosting.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium; 4 | 5 | message boosted_hex_info_v1 { 6 | // The res12 h3 index of the boosted hex 7 | uint64 location = 1; 8 | // Unix timestamp in seconds of the start of the boost period 9 | // 0 if the boosting has not yet started 10 | uint64 start_ts = 2; 11 | // Unix timestamp in seconds of the end of the boost period 12 | // 0 if the boosting has not yet started 13 | uint64 end_ts = 3; 14 | // The length of the boost period in months expressed as seconds 15 | // where one month = 30 days 16 | uint32 period_length = 4; 17 | // the multipliers valid for this hex 18 | // for each period 19 | repeated uint32 multipliers = 5; 20 | // the onchain address of the boosted hex account 21 | bytes boosted_hex_pubkey = 6; 22 | // the onchain address of the boost config account 23 | bytes boost_config_pubkey = 7; 24 | 25 | uint32 version = 8; 26 | } 27 | 28 | message boosted_hex_update_v1 { 29 | // Unix timestamp in seconds the hex was updated 30 | uint64 timestamp = 1; 31 | // Details of the updated hex 32 | boosted_hex_info_v1 update = 2; 33 | } 34 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::derive_partial_eq_without_eq)] 2 | #![allow(non_camel_case_types)] 3 | 4 | include!(concat!(env!("OUT_DIR"), "/helium.rs")); 5 | 6 | pub use blockchain_txn::Txn; 7 | pub use prost::{DecodeError, EncodeError, Message, UnknownEnumValue}; 8 | pub use strum::IntoEnumIterator; 9 | 10 | #[cfg(feature = "services")] 11 | pub mod services { 12 | use crate::{ 13 | BlockchainRegionParamsV1, BlockchainTokenTypeV1, BlockchainTxn, BoostedHexInfoV1, DataRate, 14 | Decimal, EntropyReportV1, GatewayStakingMode, MapperAttach, Region, RoutingAddress, 15 | ServiceProvider, ServiceProviderPromotions, 16 | }; 17 | 18 | pub mod sub_dao { 19 | include!(concat!(env!("OUT_DIR"), "/helium.sub_dao.rs")); 20 | pub use sub_dao_client::SubDaoClient; 21 | pub use sub_dao_server::{SubDao, SubDaoServer}; 22 | } 23 | 24 | pub mod iot_config { 25 | include!(concat!(env!("OUT_DIR"), "/helium.iot_config.rs")); 26 | pub use admin_client as config_admin_client; 27 | pub use admin_server::{Admin, AdminServer}; 28 | pub use gateway_client::GatewayClient; 29 | pub use gateway_server::{Gateway, GatewayServer}; 30 | pub use org_client as config_org_client; 31 | pub use org_server::{Org, OrgServer}; 32 | pub use route_client as config_route_client; 33 | pub use route_server::{Route, RouteServer}; 34 | } 35 | 36 | pub mod mobile_config { 37 | include!(concat!(env!("OUT_DIR"), "/helium.mobile_config.rs")); 38 | pub use admin_client as config_admin_client; 39 | pub use admin_server::{Admin, AdminServer}; 40 | pub use authorization_client::AuthorizationClient; 41 | pub use authorization_server::{Authorization, AuthorizationServer}; 42 | pub use carrier_service_client::CarrierServiceClient; 43 | pub use carrier_service_server::{CarrierService, CarrierServiceServer}; 44 | pub use entity_client::EntityClient; 45 | pub use entity_server::{Entity, EntityServer}; 46 | pub use gateway_client::GatewayClient; 47 | pub use gateway_server::{Gateway, GatewayServer}; 48 | pub use hex_boosting_client::HexBoostingClient; 49 | pub use hex_boosting_server::{HexBoosting, HexBoostingServer}; 50 | } 51 | 52 | pub mod downlink { 53 | include!(concat!(env!("OUT_DIR"), "/helium.downlink.rs")); 54 | pub use http_roaming_server::{HttpRoaming, HttpRoamingServer as Server}; 55 | } 56 | 57 | pub mod multi_buy { 58 | include!(concat!(env!("OUT_DIR"), "/helium.multi_buy.rs")); 59 | pub use multi_buy_server::{MultiBuy, MultiBuyServer as Server}; 60 | } 61 | 62 | pub mod router { 63 | pub use crate::router_client::RouterClient; 64 | 65 | include!(concat!(env!("OUT_DIR"), "/helium.packet_router.rs")); 66 | pub use packet_client::PacketClient as PacketRouterClient; 67 | } 68 | 69 | pub mod local { 70 | include!(concat!(env!("OUT_DIR"), "/helium.local.rs")); 71 | pub use api_client::ApiClient as Client; 72 | pub use api_server::{Api, ApiServer as Server}; 73 | } 74 | 75 | pub mod packet_verifier { 76 | include!(concat!(env!("OUT_DIR"), "/helium.packet_verifier.rs")); 77 | } 78 | 79 | pub mod poc_mobile { 80 | include!(concat!(env!("OUT_DIR"), "/helium.poc_mobile.rs")); 81 | pub use poc_mobile_client::PocMobileClient as Client; 82 | pub use poc_mobile_server::{PocMobile, PocMobileServer as Server}; 83 | } 84 | 85 | pub mod poc_lora { 86 | include!(concat!(env!("OUT_DIR"), "/helium.poc_lora.rs")); 87 | pub use poc_lora_client::PocLoraClient as Client; 88 | pub use poc_lora_server::{PocLora, PocLoraServer as Server}; 89 | } 90 | 91 | pub mod poc_entropy { 92 | include!(concat!(env!("OUT_DIR"), "/helium.poc_entropy.rs")); 93 | pub use poc_entropy_client::PocEntropyClient as Client; 94 | pub use poc_entropy_server::{PocEntropy, PocEntropyServer as Server}; 95 | } 96 | 97 | pub mod chain_rewardable_entities { 98 | include!(concat!( 99 | env!("OUT_DIR"), 100 | "/helium.chain_rewardable_entities.rs" 101 | )); 102 | pub use chain_rewardable_entities_client::ChainRewardableEntitiesClient as Client; 103 | pub use chain_rewardable_entities_server::{ 104 | ChainRewardableEntities, ChainRewardableEntitiesServer as Server, 105 | }; 106 | } 107 | 108 | pub mod follower { 109 | include!(concat!(env!("OUT_DIR"), "/helium.follower.rs")); 110 | pub use follower_client::FollowerClient as Client; 111 | pub use follower_server::FollowerServer as Server; 112 | } 113 | 114 | pub mod transaction { 115 | include!(concat!(env!("OUT_DIR"), "/helium.transaction.rs")); 116 | pub use transaction_client::TransactionClient as Client; 117 | pub use transaction_server::TransactionServer as Server; 118 | } 119 | } 120 | 121 | impl std::str::FromStr for ServiceProvider { 122 | type Err = prost::DecodeError; 123 | 124 | fn from_str(s: &str) -> Result { 125 | match s { 126 | "Helium Mobile" => Ok(ServiceProvider::HeliumMobile), 127 | unknown => Err(prost::DecodeError::new(format!( 128 | "unknown service provider: {unknown}" 129 | ))), 130 | } 131 | } 132 | } 133 | 134 | impl std::fmt::Display for ServiceProvider { 135 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 136 | match self { 137 | ServiceProvider::HeliumMobile => f.write_str("Helium Mobile"), 138 | } 139 | } 140 | } 141 | 142 | impl std::str::FromStr for DataRate { 143 | type Err = prost::DecodeError; 144 | 145 | fn from_str(s: &str) -> Result { 146 | match s.to_ascii_uppercase().as_str() { 147 | "SF12BW125" => Ok(DataRate::Sf12bw125), 148 | "SF11BW125" => Ok(DataRate::Sf11bw125), 149 | "SF10BW125" => Ok(DataRate::Sf10bw125), 150 | "SF9BW125" => Ok(DataRate::Sf9bw125), 151 | "SF8BW125" => Ok(DataRate::Sf8bw125), 152 | "SF7BW125" => Ok(DataRate::Sf7bw125), 153 | "SF12BW250" => Ok(DataRate::Sf12bw250), 154 | "SF11BW250" => Ok(DataRate::Sf11bw250), 155 | "SF10BW250" => Ok(DataRate::Sf10bw250), 156 | "SF9BW250" => Ok(DataRate::Sf9bw250), 157 | "SF8BW250" => Ok(DataRate::Sf8bw250), 158 | "SF7BW250" => Ok(DataRate::Sf7bw250), 159 | "SF12BW500" => Ok(DataRate::Sf12bw500), 160 | "SF11BW500" => Ok(DataRate::Sf11bw500), 161 | "SF10BW500" => Ok(DataRate::Sf10bw500), 162 | "SF9BW500" => Ok(DataRate::Sf9bw500), 163 | "SF8BW500" => Ok(DataRate::Sf8bw500), 164 | "SF7BW500" => Ok(DataRate::Sf7bw500), 165 | "LRFHSS1BW137" => Ok(DataRate::Lrfhss1bw137), 166 | "LRFHSS2BW137" => Ok(DataRate::Lrfhss2bw137), 167 | "LRFHSS1BW336" => Ok(DataRate::Lrfhss1bw336), 168 | "LRFHSS2BW336" => Ok(DataRate::Lrfhss2bw336), 169 | "LRFHSS1BW1523" => Ok(DataRate::Lrfhss1bw1523), 170 | "LRFHSS2BW1523" => Ok(DataRate::Lrfhss2bw1523), 171 | "FSK50" => Ok(DataRate::Fsk50), 172 | unknown => Err(prost::DecodeError::new(format!( 173 | "unknown datarate: {unknown}" 174 | ))), 175 | } 176 | } 177 | } 178 | 179 | impl std::fmt::Display for DataRate { 180 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 181 | match self { 182 | DataRate::Sf12bw125 => f.write_str("SF12BW125"), 183 | DataRate::Sf11bw125 => f.write_str("SF11BW125"), 184 | DataRate::Sf10bw125 => f.write_str("SF10BW125"), 185 | DataRate::Sf9bw125 => f.write_str("SF9BW125"), 186 | DataRate::Sf8bw125 => f.write_str("SF8BW125"), 187 | DataRate::Sf7bw125 => f.write_str("SF7BW125"), 188 | DataRate::Sf12bw250 => f.write_str("SF12BW250"), 189 | DataRate::Sf11bw250 => f.write_str("SF11BW250"), 190 | DataRate::Sf10bw250 => f.write_str("SF10BW250"), 191 | DataRate::Sf9bw250 => f.write_str("SF9BW250"), 192 | DataRate::Sf8bw250 => f.write_str("SF8BW250"), 193 | DataRate::Sf7bw250 => f.write_str("SF7BW250"), 194 | DataRate::Sf12bw500 => f.write_str("SF12BW500"), 195 | DataRate::Sf11bw500 => f.write_str("SF11BW500"), 196 | DataRate::Sf10bw500 => f.write_str("SF10BW500"), 197 | DataRate::Sf9bw500 => f.write_str("SF9BW500"), 198 | DataRate::Sf8bw500 => f.write_str("SF8BW500"), 199 | DataRate::Sf7bw500 => f.write_str("SF7BW500"), 200 | DataRate::Lrfhss1bw137 => f.write_str("LRFHSS1BW137"), 201 | DataRate::Lrfhss2bw137 => f.write_str("LRFHSS2BW137"), 202 | DataRate::Lrfhss1bw336 => f.write_str("LRFHSS1BW336"), 203 | DataRate::Lrfhss2bw336 => f.write_str("LRFHSS2BW336"), 204 | DataRate::Lrfhss1bw1523 => f.write_str("LRFHSS1BW1523"), 205 | DataRate::Lrfhss2bw1523 => f.write_str("LRFHSS2BW1523"), 206 | DataRate::Fsk50 => f.write_str("FSK50"), 207 | } 208 | } 209 | } 210 | 211 | impl std::str::FromStr for Region { 212 | type Err = prost::DecodeError; 213 | fn from_str(s: &str) -> Result { 214 | match s.to_ascii_uppercase().as_str() { 215 | "US915" => Ok(Region::Us915), 216 | "EU868" => Ok(Region::Eu868), 217 | "EU868_A" => Ok(Region::Eu868A), 218 | "EU868_B" => Ok(Region::Eu868B), 219 | "EU868_C" => Ok(Region::Eu868C), 220 | "EU868_D" => Ok(Region::Eu868D), 221 | "EU868_E" => Ok(Region::Eu868E), 222 | "EU868_F" => Ok(Region::Eu868F), 223 | "EU433" => Ok(Region::Eu433), 224 | "CN470" => Ok(Region::Cn470), 225 | "CN779" => Ok(Region::Cn779), 226 | "AU915" => Ok(Region::Au915), 227 | "AU915_SB1" => Ok(Region::Au915Sb1), 228 | "AU915_SB2" => Ok(Region::Au915Sb2), 229 | "AS923_1" => Ok(Region::As9231), 230 | "AS923_1A" => Ok(Region::As9231a), 231 | "AS923_1B" => Ok(Region::As9231b), 232 | "AS923_1C" => Ok(Region::As9231c), 233 | "AS923_1D" => Ok(Region::As9231d), 234 | "AS923_1E" => Ok(Region::As9231e), 235 | "AS923_1F" => Ok(Region::As9231f), 236 | "AS923_2" => Ok(Region::As9232), 237 | "AS923_3" => Ok(Region::As9233), 238 | "AS923_4" => Ok(Region::As9234), 239 | "KR920" => Ok(Region::Kr920), 240 | "IN865" => Ok(Region::In865), 241 | "CD900_1A" => Ok(Region::Cd9001a), 242 | "RU864" => Ok(Region::Ru864), 243 | unsupported => Err(prost::DecodeError::new(format!( 244 | "unknown region: {unsupported}" 245 | ))), 246 | } 247 | } 248 | } 249 | 250 | impl std::fmt::Display for Region { 251 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 252 | match self { 253 | Region::Us915 => f.write_str("US915"), 254 | Region::Eu868 => f.write_str("EU868"), 255 | Region::Eu868A => f.write_str("EU868_A"), 256 | Region::Eu868B => f.write_str("EU868_B"), 257 | Region::Eu868C => f.write_str("EU868_C"), 258 | Region::Eu868D => f.write_str("EU868_D"), 259 | Region::Eu868E => f.write_str("EU868_E"), 260 | Region::Eu868F => f.write_str("EU868_F"), 261 | Region::Eu433 => f.write_str("EU433"), 262 | Region::Cn470 => f.write_str("CN470"), 263 | Region::Cn779 => f.write_str("CN779"), 264 | Region::Au915 => f.write_str("AU915"), 265 | Region::Au915Sb1 => f.write_str("AU915_SB1"), 266 | Region::Au915Sb2 => f.write_str("AU915_SB2"), 267 | Region::As9231 => f.write_str("AS923_1"), 268 | Region::As9231a => f.write_str("AS923_1A"), 269 | Region::As9231b => f.write_str("AS923_1B"), 270 | Region::As9231c => f.write_str("AS923_1C"), 271 | Region::As9231d => f.write_str("AS923_1D"), 272 | Region::As9231e => f.write_str("AS923_1E"), 273 | Region::As9231f => f.write_str("AS923_1F"), 274 | Region::As9232 => f.write_str("AS923_2"), 275 | Region::As9233 => f.write_str("AS923_3"), 276 | Region::As9234 => f.write_str("AS923_4"), 277 | Region::Kr920 => f.write_str("KR920"), 278 | Region::In865 => f.write_str("IN865"), 279 | Region::Cd9001a => f.write_str("CD900_1A"), 280 | Region::Ru864 => f.write_str("RU864"), 281 | Region::Unknown => f.write_str("UNKNOWN"), 282 | } 283 | } 284 | } 285 | 286 | impl std::str::FromStr for RegionSpreading { 287 | type Err = prost::DecodeError; 288 | fn from_str(s: &str) -> Result { 289 | match s.to_ascii_uppercase().as_str() { 290 | "SF_INVALID" => Ok(RegionSpreading::SfInvalid), 291 | "SF7" => Ok(RegionSpreading::Sf7), 292 | "SF8" => Ok(RegionSpreading::Sf8), 293 | "SF9" => Ok(RegionSpreading::Sf9), 294 | "SF10" => Ok(RegionSpreading::Sf10), 295 | "SF11" => Ok(RegionSpreading::Sf11), 296 | "SF12" => Ok(RegionSpreading::Sf12), 297 | _ => Ok(RegionSpreading::SfInvalid), 298 | } 299 | } 300 | } 301 | 302 | impl std::fmt::Display for RegionSpreading { 303 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 304 | match self { 305 | RegionSpreading::SfInvalid => f.write_str("SF_INVALID"), 306 | RegionSpreading::Sf7 => f.write_str("SF7"), 307 | RegionSpreading::Sf8 => f.write_str("SF8"), 308 | RegionSpreading::Sf9 => f.write_str("SF9"), 309 | RegionSpreading::Sf10 => f.write_str("SF10"), 310 | RegionSpreading::Sf11 => f.write_str("SF11"), 311 | RegionSpreading::Sf12 => f.write_str("SF12"), 312 | } 313 | } 314 | } 315 | 316 | macro_rules! serde_enum { 317 | ($type:ident, $name:ident) => { 318 | mod $name { 319 | use super::$type; 320 | use std::str::FromStr; 321 | 322 | pub fn serialize(v: &i32, serializer: S) -> std::result::Result 323 | where 324 | S: serde::ser::Serializer, 325 | { 326 | let v = $type::try_from(*v) 327 | .map_err(|_| serde::ser::Error::custom(format!("invalid enum value: {v}")))?; 328 | serializer.serialize_str(&v.to_string()) 329 | } 330 | 331 | pub fn deserialize<'de, D>(deserializer: D) -> std::result::Result 332 | where 333 | D: serde::de::Deserializer<'de>, 334 | { 335 | struct _Visitor; 336 | 337 | impl<'de> serde::de::Visitor<'de> for _Visitor { 338 | type Value = i32; 339 | fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { 340 | formatter.write_str("string value") 341 | } 342 | fn visit_str(self, value: &str) -> std::result::Result 343 | where 344 | E: serde::de::Error, 345 | { 346 | $type::from_str(value).map(|v| v as i32).map_err(|_| { 347 | serde::de::Error::custom(format!("invalid string value \"{value}\"")) 348 | }) 349 | } 350 | } 351 | 352 | deserializer.deserialize_str(_Visitor) 353 | } 354 | } 355 | }; 356 | } 357 | 358 | serde_enum!(RegionSpreading, serde_region_spreading); 359 | -------------------------------------------------------------------------------- /src/longfi.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium.longfi; 4 | 5 | enum LongFiSpreading { 6 | SF_INVALID = 0; 7 | SF7 = 1; 8 | SF8 = 2; 9 | SF9 = 3; 10 | SF10 = 4; 11 | } 12 | 13 | message LongFiReq { 14 | uint32 id = 1; 15 | oneof kind { LongFiTxPacket tx = 2; } 16 | } 17 | 18 | message LongFiResp { 19 | uint32 id = 1; 20 | oneof kind { 21 | LongFiTxStatus tx_status = 2; 22 | LongFiRxPacket rx = 3; 23 | bytes parse_err = 4; 24 | } 25 | bytes miner_name = 5; 26 | } 27 | 28 | message LongFiTxStatus { bool success = 1; } 29 | 30 | message LongFiRxPacket { 31 | // Status of CRC check. 32 | bool crc_check = 1; 33 | // 1uS-resolution timestamp derived from concentrator's internal counter. 34 | uint64 timestamp = 2; 35 | // Average packet RSSI in dB. 36 | float rssi = 3; 37 | // Average packet SNR, in dB. 38 | float snr = 4; 39 | // Organization Unique ID 40 | uint32 oui = 5; 41 | // Device ID 42 | uint32 device_id = 6; 43 | // Fingerprint 44 | uint32 fingerprint = 7; 45 | // Sequence 46 | uint32 sequence = 9; 47 | // Spreading to be used 48 | LongFiSpreading spreading = 10; 49 | // the fully reassembled payload 50 | bytes payload = 11; 51 | // De-golayed datagram id and flag bits. 52 | // NOTE: only the lowest 12 bits are valid. 53 | uint32 tag_bits = 12; 54 | } 55 | 56 | message LongFiTxPacket { 57 | // is device receiver (downlink) or is router receiver (uplink) 58 | // note: when Hotspot is sending Proof of Coverage packet, 59 | // it should behave as a device and flag this as "uplink" 60 | bool downlink = 1; 61 | // should the receiver ACK 62 | bool should_ack = 2; 63 | // on uplink, this indicates the device is ready to receive downlink 64 | bool cts = 3; 65 | // is the packet urgent 66 | bool priority = 4; 67 | // the packet beyond the tag field is encoded with LDPC 68 | bool ldpc = 5; 69 | // Organization Unique ID 70 | uint32 oui = 6; 71 | // Device ID 72 | uint32 device_id = 7; 73 | // Fingerprint 74 | uint32 fingerpint = 8; 75 | // Sequence 76 | uint32 sequence = 9; 77 | // Spreading to be used 78 | LongFiSpreading spreading = 10; 79 | bytes payload = 11; 80 | } 81 | -------------------------------------------------------------------------------- /src/mapper.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package helium; 3 | 4 | message mapper { 5 | oneof message { 6 | mapper_gps gps = 1; 7 | mapper_scan scan = 2; 8 | mapper_attach attach = 3; 9 | } 10 | // the pubkey signs over the message above 11 | // which does not contain the pubkey itself 12 | bytes signature = 4; 13 | bytes pub_key = 5; 14 | 15 | // below is optional metadata which depending 16 | // on the message above, may or may not be populated. 17 | // it is included here because it cannot be signed 18 | 19 | // hotspots that received the mapper message if it 20 | // was received over lorawan 21 | repeated bytes hotspots = 6; 22 | } 23 | 24 | message mapper_attach { 25 | oneof version { mapper_attach_v1 attach_v1 = 1; } 26 | } 27 | 28 | message mapper_attach_v1 { 29 | enum mapper_attach_result { 30 | NONE = 0; 31 | CONNECT = 1; 32 | LIMSERV = 2; 33 | NOCONN = 3; 34 | SEARCH = 4; 35 | NO_NETWORK_SERVICE = 5; 36 | } 37 | message mapper_attach_candidate { 38 | enum cell_tech { 39 | lte = 0; 40 | nr = 1; 41 | } 42 | cell_tech type = 1; 43 | // Corresponds "scan_response_counter" in the scan_response_counter which we 44 | // selected attach candidates from 45 | uint32 from_scan_response = 2; 46 | // delay in seconds between locking to the cell and evaluating connectivity 47 | uint32 delay = 3; 48 | uint32 plmn = 4; 49 | uint32 fcn = 5; 50 | // 28-bit (UMTS, LTE) or 36-bit (5G NR) 51 | uint64 cid = 6; 52 | // RSRQ in units of 0.1 dB 53 | int32 rsrp = 7; 54 | // RSRP in units of 0.1 dBm 55 | int32 rsrq = 8; 56 | } 57 | // This allows us to detect censorship efforts. It can roll over. 58 | uint32 attach_counter = 1; 59 | mapper_gps_v1 gps = 2; 60 | mapper_attach_candidate candidate = 3; 61 | mapper_attach_result result = 4; 62 | } 63 | 64 | message mapper_gps { 65 | oneof version { mapper_gps_v1 gps_v1 = 1; } 66 | } 67 | 68 | message mapper_gps_v1 { 69 | // Unix time in seconds 70 | uint32 unix_time = 1; 71 | // Latitude of the current base station in units of 0.25 sec. 72 | int32 lat = 2; 73 | // Longitude of the current base station in units of 0.25 sec. 74 | int32 lon = 3; 75 | // Horizontal dilution of position in units of 0.01 HDOP. 76 | uint32 hdop = 4; 77 | // Altitude in units of 0.25m above the WGS 84 reference ellipsoid. 78 | int64 altitude = 5; 79 | int32 num_sats = 6; 80 | // Speed in speed in 0.25m/s per second. 81 | uint32 speed = 7; 82 | } 83 | 84 | message mapper_scan { 85 | oneof version { mapper_scan_v1 scan_v1 = 1; } 86 | } 87 | 88 | message mapper_scan_v1 { 89 | uint32 scan_counter = 1; 90 | mapper_gps_v1 gps = 2; 91 | repeated mapper_scan_result results = 3; 92 | } 93 | 94 | message mapper_scan_result { 95 | // 28-bit (UMTS, LTE) or 36-bit (5G NR) 96 | uint64 cid = 1; 97 | // PLMN = (MCC << 16) | MNC 98 | uint32 plmn = 2; 99 | // EARFCN or UARFCN 100 | uint32 fcn = 3; 101 | uint32 pci = 4; 102 | // RSRQ in units of 0.1 dB 103 | int32 rsrp = 5; 104 | // RSRP in units of 0.1 dBm 105 | int32 rsrq = 6; 106 | } 107 | -------------------------------------------------------------------------------- /src/packet.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium; 4 | 5 | message eui { 6 | uint64 deveui = 1; 7 | uint64 appeui = 2; 8 | } 9 | 10 | message routing_information { 11 | oneof data { 12 | uint32 devaddr = 1; 13 | eui eui = 2; 14 | } 15 | } 16 | 17 | message window { 18 | uint64 timestamp = 1; 19 | float frequency = 2; 20 | string datarate = 3; 21 | } 22 | 23 | message packet { 24 | uint32 oui = 1; 25 | enum packet_type { 26 | longfi = 0; 27 | lorawan = 1; 28 | } 29 | packet_type type = 2; 30 | bytes payload = 3; 31 | uint64 timestamp = 4; 32 | float signal_strength = 5; 33 | float frequency = 6; 34 | string datarate = 7; 35 | float snr = 8; 36 | routing_information routing = 9; 37 | window rx2_window = 10; 38 | } 39 | -------------------------------------------------------------------------------- /src/price_report.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium; 4 | 5 | import "blockchain_token_type_v1.proto"; 6 | 7 | message price_report_v1 { 8 | /// The price, specified in 1/1000000ths of a cent, i.e. 1$ = 1000000. 9 | /// NOTE: Helium blockchain specifies $1 = 10^8, whereas on solana only 10^6 10 | /// is supported. 11 | uint64 price = 1; 12 | /// The timestamp for this report (unix epoch) 13 | uint64 timestamp = 2; 14 | /// The token type for this report 15 | blockchain_token_type_v1 token_type = 3; 16 | } 17 | -------------------------------------------------------------------------------- /src/radio.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium.radio; 4 | 5 | enum Radio { 6 | R0 = 0; 7 | R1 = 1; 8 | } 9 | 10 | enum Spreading { 11 | SF_UNDEFINED = 0; 12 | SF7 = 1; 13 | SF8 = 2; 14 | SF9 = 3; 15 | SF10 = 4; 16 | SF11 = 5; 17 | SF12 = 6; 18 | } 19 | 20 | enum Bandwidth { 21 | BW_UNDEFINED = 0; 22 | BW7_8kHz = 1; 23 | BW15_6kHz = 2; 24 | BW31_2kHz = 3; 25 | BW62_5kHz = 4; 26 | BW125kHz = 5; 27 | BW250kHz = 6; 28 | BW500kHz = 7; 29 | } 30 | enum Coderate { 31 | CR_UNDEFINED = 0; 32 | CR4_5 = 1; 33 | CR4_6 = 2; 34 | CR4_7 = 3; 35 | CR4_8 = 4; 36 | } 37 | 38 | message RadioReq { 39 | uint32 id = 1; 40 | oneof kind { RadioTxReq tx = 2; } 41 | } 42 | 43 | message RadioResp { 44 | uint32 id = 1; 45 | oneof kind { 46 | RadioTxResp tx = 2; 47 | RadioRxPacket rx_packet = 3; 48 | bytes parse_err = 4; 49 | } 50 | } 51 | 52 | message RadioTxReq { 53 | // Center frequency to transmit on. 54 | uint32 freq = 1; 55 | // Which radio to transmit on. 56 | Radio radio = 2; 57 | // TX power (in dBm). 58 | int32 power = 3; 59 | // Modulation bandwidth. 60 | Bandwidth bandwidth = 4; 61 | // Spreading factor to use with this packet. 62 | Spreading spreading = 5; 63 | // Error-correcting-code of the packet. 64 | Coderate coderate = 6; 65 | // Invert signal polarity for orthogonal downlinks. 66 | bool invert_polarity = 7; 67 | // Do not send a CRC in the packet. 68 | bool omit_crc = 8; 69 | // Enable implicit header mode. 70 | bool implicit_header = 9; 71 | // Arbitrary user-defined payload to transmit. 72 | bytes payload = 10; 73 | } 74 | 75 | message RadioRxPacket { 76 | // Center frequency of the channel this packet was received on. 77 | uint32 freq = 1; 78 | // Channel this packet packet was received on. 79 | uint32 if_chain = 2; 80 | // Status of CRC check. 81 | bool crc_check = 3; 82 | // 1uS-resolution timestamp derived from concentrator's internal counter. 83 | uint64 timestamp = 4; 84 | // RF chain this packet was received on. 85 | Radio radio = 5; 86 | // Modulation bandwidth. 87 | Bandwidth bandwidth = 6; 88 | // Spreading factor of this packet. 89 | Spreading spreading = 7; 90 | // Error Correcting Code rate of this packet. 91 | Coderate coderate = 8; 92 | // Average packet RSSI in dB. 93 | float rssi = 9; 94 | // Average packet SNR, in dB. 95 | float snr = 10; 96 | // This packet's payload. 97 | bytes payload = 11; 98 | } 99 | 100 | message RadioTxResp { bool success = 1; } -------------------------------------------------------------------------------- /src/region.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium; 4 | 5 | enum region { 6 | US915 = 0; 7 | EU868 = 1; 8 | EU433 = 2; 9 | CN470 = 3; 10 | CN779 = 4 [ deprecated = true ]; 11 | AU915 = 5; 12 | AS923_1 = 6; 13 | KR920 = 7; 14 | IN865 = 8; 15 | AS923_2 = 9; 16 | AS923_3 = 10; 17 | AS923_4 = 11; 18 | AS923_1B = 12; 19 | CD900_1A = 13; 20 | RU864 = 14; 21 | EU868_A = 15; 22 | EU868_B = 16; 23 | EU868_C = 17; 24 | EU868_D = 18; 25 | EU868_E = 19; 26 | EU868_F = 20; 27 | AU915_SB1 = 21; 28 | AU915_SB2 = 22; 29 | AS923_1A = 23; 30 | AS923_1C = 24; 31 | AS923_1D = 25; 32 | AS923_1E = 26; 33 | AS923_1F = 27; 34 | 35 | UNKNOWN = 99; 36 | } 37 | -------------------------------------------------------------------------------- /src/reward_manifest.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium; 4 | 5 | import "decimal.proto"; 6 | import "service_provider.proto"; 7 | 8 | enum mobile_reward_token { 9 | mobile_reward_token_mobile = 0; 10 | mobile_reward_token_hnt = 1; 11 | } 12 | 13 | message mobile_reward_data { 14 | Decimal poc_bones_per_reward_share = 1; 15 | Decimal boosted_poc_bones_per_reward_share = 2; 16 | repeated service_provider_promotions service_provider_promotions = 3; 17 | // HIP-138: Reward output was changed from Subdao Tokens to HNT 18 | mobile_reward_token token = 4; 19 | } 20 | 21 | message service_provider_promotions { 22 | message promotion { 23 | // Name of the Promotion NFT 24 | string entity = 1; 25 | // Unix timestamp in seconds of the start of the promotion 26 | uint64 start_ts = 2; 27 | // Unix timestamp in seconds of the end of the promotion 28 | uint64 end_ts = 3; 29 | // Shares used when distributing promotion incentive allocation 30 | uint32 shares = 4; 31 | } 32 | 33 | service_provider service_provider = 1; 34 | // The percentage of the SP rewards that are allocated to the incentive fund, 35 | // in basis points 36 | uint32 incentive_escrow_fund_bps = 2; 37 | repeated promotion promotions = 3; 38 | } 39 | 40 | enum iot_reward_token { 41 | iot_reward_token_iot = 0; 42 | iot_reward_token_hnt = 1; 43 | } 44 | 45 | message iot_reward_data { 46 | Decimal poc_bones_per_beacon_reward_share = 1; 47 | Decimal poc_bones_per_witness_reward_share = 2; 48 | Decimal dc_bones_per_share = 3; 49 | // HIP-138: Reward output was changed from Subdao Tokens to HNT 50 | iot_reward_token token = 4; 51 | } 52 | 53 | message reward_manifest { 54 | repeated string written_files = 1; 55 | // Unix timestamp in seconds of the start of the inventory period 56 | uint64 start_timestamp = 2; 57 | // Unix timestamp in seconds of the end of the inventory period 58 | uint64 end_timestamp = 3; 59 | oneof reward_data { 60 | mobile_reward_data mobile_reward_data = 4; 61 | iot_reward_data iot_reward_data = 5; 62 | } 63 | // the epoch of the reward share 64 | uint64 epoch = 6; 65 | // Price of the token at time rewards were calculated 66 | // MOBILE is @ 10^6 67 | // IOT is @ 10^6 68 | // HNT is @ 10^8 69 | uint64 price = 7; 70 | } 71 | -------------------------------------------------------------------------------- /src/scaling_factors.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium; 4 | 5 | // map of string h3 res 12 hex address to reward scaling factor 6 | // as an integer representation of the 4-point precision decimal multiplier 7 | // Ex: 5015 = 0.5015 8 | message scaling_factors { map hex_to_sf = 1; } 9 | -------------------------------------------------------------------------------- /src/service/chain_rewardable_entities.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium.chain_rewardable_entities; 4 | 5 | message solana_pub_key { bytes value = 1; } 6 | 7 | message helium_pub_key { 8 | // bytes of a valid helium pub key. 9 | // Should support parsing into helium_crypto::public_key::PublicKey 10 | bytes value = 1; 11 | } 12 | 13 | // ------------------------------------------------------------------ 14 | // Helium Hotspot "rewardable entities" and their metadata 15 | // ------------------------------------------------------------------ 16 | enum mobile_hotspot_device_type { 17 | mobile_hotspot_device_type_UNKNOWN = 18 | 0; // Unknown device type, should not be used 19 | mobile_hotspot_device_type_CBRS = 1; 20 | mobile_hotspot_device_type_WIFI_INDOOR = 2; 21 | mobile_hotspot_device_type_WIFI_OUTDOOR = 3; 22 | mobile_hotspot_device_type_WIFI_DATA_ONLY = 4; 23 | } 24 | 25 | message mobile_hotspot_metadata { 26 | // Serial number of the mobile hotspot device (can be null or empty... in the 27 | // case of data-only devices) 28 | string serial_number = 2; 29 | // Type of the mobile hotspot device 30 | mobile_hotspot_device_type device_type = 3; 31 | // The asserted location in hex format 32 | string asserted_hex = 4; 33 | uint32 azimuth = 5; 34 | } 35 | 36 | // TODO: this meets mvp app needs, but could easily be extended 37 | message iot_hotspot_metadata { 38 | // The asserted hex location of the IoT hotspot 39 | string asserted_hex = 2; 40 | uint32 elevation = 3; 41 | bool is_data_only = 4; 42 | } 43 | 44 | // ------------------------------------------------------------------ 45 | // Rewardable Entity <---> Controlling Wallet 46 | // ------------------------------------------------------------------ 47 | enum entity_owner_type { 48 | // Unknown control type, should not be used 49 | entity_owner_type_UNKNOWN = 0; 50 | // Owner of the NFT 51 | entity_owner_type_DIRECT_OWNER = 1; 52 | // Controlling permission of the Welcome Pack 53 | entity_owner_type_WELCOME_PACK_OWNER = 2; 54 | } 55 | 56 | message entity_owner_info { 57 | // User wallet public key 58 | solana_pub_key wallet = 1; 59 | 60 | // Type of control relationship 61 | entity_owner_type type = 2; 62 | } 63 | 64 | message rewards_split_v1 { 65 | // They key of the on-chain struct that contains/performs the split 66 | solana_pub_key pub_key = 1; 67 | // The cron schedule of the split 68 | string schedule = 2; 69 | // The total shares of the split (user can specify any number of shares, 70 | // defaults to 100) 71 | uint32 total_shares = 3; 72 | // The recipients of the split 73 | repeated split_recipient_info_v1 recipients = 4; 74 | } 75 | 76 | message split_recipient_info_v1 { 77 | // The authority to control `recipient`. Useful for cases where a hot wallet 78 | // has rewards go to a cold wallet. You can safely ignore this field, unless 79 | // we implement a UI to make use of this smart contract feature. 80 | solana_pub_key authority = 1; 81 | // The wallet receiving this part of the split 82 | solana_pub_key recipient = 2; 83 | oneof reward_amount { 84 | // Fixed amount of tokens to be distributed to the wallet each period. 85 | uint64 fixed_amount = 3; 86 | // The shares for this wallet in the fanout. Divide into split.total_shares 87 | // for percentage. 88 | uint32 shares = 4; 89 | } 90 | } 91 | 92 | // ------------------------------------------------------------------ 93 | // changes 94 | // ------------------------------------------------------------------ 95 | // Latest state of chain - effectively the data to be stored 96 | // will be sent in a request to ingestor 97 | // New messages should be created whenever 98 | // - hotspot is deployed 99 | // - hotspot metadata is changed 100 | message mobile_hotspot_change_v1 { 101 | // Block when this data was sourced 102 | uint64 block = 1; 103 | uint64 timestamp_seconds = 2; 104 | 105 | // Public key of the hotspot 106 | helium_pub_key pub_key = 3; 107 | 108 | // Solana public key of the hotspot's NFT (which we call an `asset`) 109 | solana_pub_key asset = 4; 110 | 111 | // Hotspot metadata 112 | mobile_hotspot_metadata metadata = 5; 113 | } 114 | 115 | // Latest state of chain - effectively the data to be stored 116 | // will be sent in a request to ingestor 117 | // New messages should be created whenever 118 | // - hotspot is deployed 119 | // - hotspot metadata is changed 120 | message iot_hotspot_change_v1 { 121 | // Block when this data was sourced 122 | uint64 block = 1; 123 | uint64 timestamp_seconds = 2; 124 | 125 | // Public key of the hotspot 126 | helium_pub_key pub_key = 3; 127 | 128 | // Solana public key of the hotspot's NFT (which we call an `asset`) 129 | solana_pub_key asset = 4; 130 | 131 | // Hotspot metadata 132 | iot_hotspot_metadata metadata = 5; 133 | } 134 | 135 | // Latest state of chain - effectively the data to be stored 136 | // will be sent in a request to ingestor 137 | // New messages should be created whenever 138 | // - entity is created 139 | // - entity ownership changes 140 | message entity_owner_change_v1 { 141 | // Block when this data was sourced 142 | uint64 block = 1; 143 | uint64 timestamp_seconds = 2; 144 | 145 | // Public key of the entity 146 | helium_pub_key entity_pub_key = 3; 147 | 148 | // Solana public key of the entity's NFT (which we call an `asset`) 149 | solana_pub_key asset = 4; 150 | 151 | // Controlling ownership of the NFT 152 | entity_owner_info owner = 5; 153 | } 154 | 155 | // Latest state of chain - effectively the data to be stored 156 | // will be sent in a request to ingestor 157 | // New messages should be created whenever 158 | // - entity is created 159 | // - entity reward structure changes 160 | message entity_reward_destination_change_v1 { 161 | // Block when this data was sourced 162 | uint64 block = 1; 163 | uint64 timestamp_seconds = 2; 164 | 165 | // Public key of the entity 166 | helium_pub_key entity_pub_key = 3; 167 | 168 | // Solana public key of the entity's NFT (which we call an `asset`) 169 | solana_pub_key asset = 4; 170 | 171 | oneof rewards_destination { 172 | solana_pub_key rewards_recipient = 5; 173 | rewards_split_v1 rewards_split_v1 = 6; 174 | } 175 | } 176 | 177 | // Reports 178 | // The change which ingestor/oracles will WRITE to s3 179 | message mobile_hotspot_change_report_v1 { 180 | // The time the server received the request 181 | uint64 received_timestamp_ms = 1; 182 | // The request change 183 | mobile_hotspot_change_req_v1 report = 2; 184 | } 185 | 186 | // The change which ingestor/oracles will WRITE to s3 187 | message iot_hotspot_change_report_v1 { 188 | // The time the server received the request 189 | uint64 received_timestamp_ms = 1; 190 | // The request change 191 | iot_hotspot_change_req_v1 report = 2; 192 | } 193 | 194 | // The change which ingestor/oracles will WRITE to s3 195 | message entity_ownership_change_report_v1 { 196 | // The time the server received the request 197 | uint64 received_timestamp_ms = 1; 198 | // The request change 199 | entity_ownership_change_req_v1 report = 2; 200 | } 201 | 202 | // The change which ingestor/oracles will WRITE to s3 203 | message entity_reward_destination_change_report_v1 { 204 | // The time the server received the request 205 | uint64 received_timestamp_ms = 1; 206 | // The request change 207 | entity_reward_destination_change_req_v1 report = 2; 208 | } 209 | 210 | // RPC 211 | // Req/Resp pairs for the ingestor 212 | 213 | // Service defs 214 | message mobile_hotspot_change_req_v1 { 215 | mobile_hotspot_change_v1 change = 1; 216 | string signer = 2; 217 | bytes signature = 3; 218 | } 219 | 220 | message mobile_hotspot_change_resp_v1 { uint64 timestamp_ms = 1; } 221 | 222 | message iot_hotspot_change_req_v1 { 223 | iot_hotspot_change_v1 change = 1; 224 | string signer = 2; 225 | bytes signature = 3; 226 | } 227 | 228 | message iot_hotspot_change_resp_v1 { uint64 timestamp_ms = 1; } 229 | 230 | message entity_ownership_change_req_v1 { 231 | entity_owner_change_v1 change = 1; 232 | string signer = 2; 233 | bytes signature = 3; 234 | } 235 | message entity_ownership_change_resp_v1 { uint64 timestamp_ms = 1; } 236 | 237 | message entity_reward_destination_change_req_v1 { 238 | entity_reward_destination_change_v1 change = 1; 239 | string signer = 2; 240 | bytes signature = 3; 241 | } 242 | message entity_reward_destination_change_resp_v1 { uint64 timestamp_ms = 1; } 243 | 244 | service chain_rewardable_entities { 245 | rpc submit_mobile_hotspot_change(mobile_hotspot_change_req_v1) 246 | returns (mobile_hotspot_change_resp_v1); 247 | rpc submit_iot_hotspot_change(iot_hotspot_change_req_v1) 248 | returns (iot_hotspot_change_resp_v1); 249 | rpc submit_entity_ownership_change(entity_ownership_change_req_v1) 250 | returns (entity_ownership_change_resp_v1); 251 | rpc submit_entity_reward_destination_change( 252 | entity_reward_destination_change_req_v1) 253 | returns (entity_reward_destination_change_resp_v1); 254 | } 255 | -------------------------------------------------------------------------------- /src/service/downlink.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium.downlink; 4 | 5 | import "region.proto"; 6 | 7 | message http_roaming_register_v1 { 8 | region region = 1; 9 | // milliseconds since unix epoch 10 | uint64 timestamp = 2; 11 | bytes signature = 3; 12 | } 13 | 14 | message http_roaming_downlink_v1 { bytes data = 1; } 15 | 16 | service http_roaming { 17 | rpc stream(http_roaming_register_v1) 18 | returns (stream http_roaming_downlink_v1); 19 | } 20 | -------------------------------------------------------------------------------- /src/service/follower.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium.follower; 4 | 5 | import "blockchain_token_type_v1.proto"; 6 | import "blockchain_txn.proto"; 7 | import "gateway_staking_mode.proto"; 8 | import "region.proto"; 9 | import "blockchain_region_param_v1.proto"; 10 | 11 | message gateway_not_found { bytes address = 1; } 12 | 13 | message follower_error { 14 | oneof type { gateway_not_found not_found = 1; } 15 | } 16 | 17 | message follower_txn_stream_req_v1 { 18 | uint64 height = 1; 19 | bytes txn_hash = 2; 20 | repeated string txn_types = 3; 21 | } 22 | 23 | message follower_txn_stream_resp_v1 { 24 | uint64 height = 1; 25 | bytes txn_hash = 2; 26 | blockchain_txn txn = 3; 27 | uint64 timestamp = 4; 28 | } 29 | 30 | message gateway_info { 31 | /// The asserted h3 (string) location of the gateway. Empty string if the 32 | // gateway is not found 33 | string location = 1; 34 | /// The pubkey_bin address of the requested gateway 35 | bytes address = 2; 36 | /// The pubkey_bin address of the current owner of the gateway. An empty bytes 37 | /// if the hotspot is not found 38 | bytes owner = 3; 39 | /// the staking mode of the gateway 40 | gateway_staking_mode staking_mode = 4; 41 | /// the transmit gain value of the gateway in dbi x 10 For example 1 dbi = 10, 42 | // 15 dbi = 150 43 | int32 gain = 5; 44 | /// The region of the gateway's corresponding location 45 | region region = 6; 46 | /// The region params of the gateway's corresponding region 47 | blockchain_region_params_v1 region_params = 7; 48 | } 49 | 50 | /// Look up the owner of a given hotspot public key 51 | message follower_gateway_req_v1 { 52 | /// The pubkey_bin address of the gateway to look up 53 | bytes address = 1; 54 | } 55 | 56 | message follower_gateway_resp_v1 { 57 | /// The height for at which the ownership was looked up 58 | uint64 height = 1; 59 | oneof result { 60 | gateway_info info = 2; 61 | follower_error error = 3; 62 | } 63 | } 64 | 65 | /// Request a stream of all active gateways from the on-chain metadata 66 | message follower_gateway_stream_req_v1 { uint32 batch_size = 1; } 67 | 68 | /// Active gateway info streaming response containing a batch of gateways 69 | message follower_gateway_stream_resp_v1 { 70 | repeated follower_gateway_resp_v1 gateways = 1; 71 | } 72 | 73 | /// Query the last reward block for the given subnetwork by token type 74 | message follower_subnetwork_last_reward_height_req_v1 { 75 | /// The token type of the subnetwork to query 76 | blockchain_token_type_v1 token_type = 1; 77 | } 78 | 79 | message follower_subnetwork_last_reward_height_resp_v1 { 80 | /// The current height at the time of the request 81 | uint64 height = 1; 82 | /// The height of the reward block 83 | uint64 reward_height = 2; 84 | } 85 | 86 | service follower { 87 | rpc txn_stream(follower_txn_stream_req_v1) 88 | returns (stream follower_txn_stream_resp_v1); 89 | rpc find_gateway(follower_gateway_req_v1) returns (follower_gateway_resp_v1); 90 | rpc active_gateways(follower_gateway_stream_req_v1) 91 | returns (stream follower_gateway_stream_resp_v1); 92 | rpc subnetwork_last_reward_height( 93 | follower_subnetwork_last_reward_height_req_v1) 94 | returns (follower_subnetwork_last_reward_height_resp_v1); 95 | } 96 | -------------------------------------------------------------------------------- /src/service/iot_config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium.iot_config; 4 | 5 | import "blockchain_region_param_v1.proto"; 6 | import "region.proto"; 7 | 8 | // ------------------------------------------------------------------ 9 | // Message Definitions 10 | // ------------------------------------------------------------------ 11 | 12 | // == Field Notes == 13 | // 14 | // - Every message including `signature` will need to be signed over the 15 | // entire message, with the `signature` field set to an empty value. 16 | // Request messages are signed by the caller to allow the config service 17 | // to authenticate them against known public keys and response messages 18 | // are signed by the config service to allow the recipient to validate 19 | // the authenticity of the data returned. 20 | // 21 | // - Every key called `owner`, `payer` and `delegate_keys` are binary 22 | // encoded public keys, Rust encoding example here: 23 | // https://github.com/helium/helium-crypto-rs/blob/main/src/public_key.rs#L347-L354 24 | // 25 | // == DevAddrs == 26 | // 27 | // - `devaddr_range` and `devaddr_constraints` are inclusive on both sides, 28 | // - `start_addr` and `end_addr`. 29 | // 30 | // - `org_res_v1.devaddr_constraints` provides the ranges of DevAddrs available 31 | // to 32 | // any `route_v1` under an Org. 33 | // 34 | // - `devaddr_range_v1` provides the ranges of DevAddrs that should go to 35 | // this specific Route. This ranges must always fall within the 36 | // `devaddr_constraints` of the owning org. 37 | 38 | enum action_v1 { 39 | add = 0; 40 | remove = 1; 41 | } 42 | 43 | // Define an organisation 44 | message org_v1 { 45 | uint64 oui = 1; 46 | // Org admin key 47 | bytes owner = 2; 48 | // Key only used for DC payments 49 | bytes payer = 3; 50 | // List of keys allowed some specific actions, see services. 51 | repeated bytes delegate_keys = 4; 52 | // Is org locked because of no payment 53 | bool locked = 5; 54 | } 55 | 56 | // Device address range, ex: 16#00000001 to 16#0000000A 57 | message devaddr_range_v1 { 58 | string route_id = 1; 59 | uint32 start_addr = 2; 60 | uint32 end_addr = 3; 61 | } 62 | 63 | message devaddr_constraint_v1 { 64 | uint32 start_addr = 1; 65 | uint32 end_addr = 2; 66 | } 67 | 68 | // Device App EUI and Dev EUI 69 | message eui_pair_v1 { 70 | string route_id = 1; 71 | uint64 app_eui = 2; 72 | uint64 dev_eui = 3; 73 | } 74 | 75 | // Packet Router protocol options (empty for now) 76 | message protocol_packet_router_v1 {} 77 | 78 | message protocol_gwmp_mapping_v1 { 79 | region region = 1; 80 | uint32 port = 2; 81 | } 82 | 83 | // GWMP protocol options (region to port mapping, see 84 | // https://github.com/Lora-net/packet_forwarder/blob/master/PROTOCOL.TXT) 85 | message protocol_gwmp_v1 { repeated protocol_gwmp_mapping_v1 mapping = 1; } 86 | 87 | // HTTP Roaming protocol options 88 | message protocol_http_roaming_v1 { 89 | enum flow_type_v1 { 90 | sync = 0; 91 | async = 1; 92 | } 93 | flow_type_v1 flow_type = 1; 94 | // milliseconds 95 | uint32 dedupe_timeout = 2; 96 | // path component of URL of roaming partner 97 | string path = 3; 98 | // Authorization Header 99 | string auth_header = 4; 100 | // Receiver NSID 101 | string receiver_nsid = 5; 102 | } 103 | 104 | // Server Route definition 105 | message server_v1 { 106 | // LNS address, ex: endpoint.test.com 107 | string host = 1; 108 | // LNS port, ex: 8080 109 | uint32 port = 2; 110 | oneof protocol { 111 | protocol_packet_router_v1 packet_router = 3; 112 | protocol_gwmp_v1 gwmp = 4; 113 | protocol_http_roaming_v1 http_roaming = 5; 114 | } 115 | } 116 | 117 | // Route definition 118 | message route_v1 { 119 | // UUID 120 | string id = 1; 121 | // LoraWan Network ID 122 | uint32 net_id = 2; 123 | // Organization Unique ID 124 | uint64 oui = 3; 125 | server_v1 server = 4; 126 | // Number of packet copies bought by this route 127 | uint32 max_copies = 5; 128 | bool active = 6; 129 | // Is route locked because of no payment 130 | bool locked = 7; 131 | // If true, routes are blocked whose devaddrs have empty session key filters 132 | bool ignore_empty_skf = 8; 133 | } 134 | 135 | // ------------------------------------------------------------------ 136 | // Service Message Definitions 137 | // ------------------------------------------------------------------ 138 | 139 | message org_list_req_v1 {} 140 | 141 | message org_list_res_v1 { 142 | repeated org_v1 orgs = 1; 143 | // in seconds since unix epoch 144 | uint64 timestamp = 2; 145 | // pubkey binary of the signing keypair 146 | bytes signer = 3; 147 | // Signature over the response by the config service 148 | bytes signature = 4; 149 | } 150 | 151 | message org_get_req_v1 { uint64 oui = 1; } 152 | 153 | message org_create_helium_req_v1 { 154 | enum helium_net_id { 155 | type0_0x00003c = 0; 156 | type3_0x60002d = 1; 157 | type6_0xc00053 = 2; 158 | } 159 | 160 | bytes owner = 1; 161 | bytes payer = 2; 162 | // Number of device address needed 163 | // Even number required, minimum of 8 164 | uint64 devaddrs = 3; 165 | // in milliseconds since unix epoch 166 | uint64 timestamp = 4; 167 | bytes signature = 5; 168 | repeated bytes delegate_keys = 6; 169 | // pubkey binary of the signing keypair 170 | bytes signer = 7; 171 | helium_net_id net_id = 8; 172 | } 173 | 174 | message org_create_roamer_req_v1 { 175 | bytes owner = 1; 176 | bytes payer = 2; 177 | uint32 net_id = 3; 178 | // in milliseconds since unix epoch 179 | uint64 timestamp = 4; 180 | bytes signature = 5; 181 | repeated bytes delegate_keys = 6; 182 | // pubkey binary of the signing keypair 183 | bytes signer = 7; 184 | } 185 | 186 | message org_update_req_v1 { 187 | message delegate_key_update_v1 { 188 | bytes delegate_key = 1; 189 | action_v1 action = 2; 190 | } 191 | 192 | message devaddr_constraint_update_v1 { 193 | devaddr_constraint_v1 constraint = 1; 194 | action_v1 action = 2; 195 | } 196 | 197 | message update_v1 { 198 | oneof update { 199 | bytes owner = 1; 200 | bytes payer = 2; 201 | delegate_key_update_v1 delegate_key = 3; 202 | // count of devaddrs to add, in even numbers 203 | uint64 devaddrs = 4; 204 | // devaddr constraints to explicitly add or remove 205 | devaddr_constraint_update_v1 constraint = 5; 206 | } 207 | } 208 | 209 | uint64 oui = 1; 210 | repeated update_v1 updates = 2; 211 | uint64 timestamp = 3; 212 | bytes signer = 4; 213 | bytes signature = 5; 214 | } 215 | 216 | message org_res_v1 { 217 | org_v1 org = 1; 218 | uint32 net_id = 2; 219 | repeated devaddr_constraint_v1 devaddr_constraints = 3; 220 | // in seconds since unix epoch 221 | uint64 timestamp = 4; 222 | // pubkey binary of the signing keypair 223 | bytes signer = 5; 224 | // Signature over the response by the config service 225 | bytes signature = 6; 226 | } 227 | 228 | message org_disable_req_v1 { 229 | uint64 oui = 1; 230 | // in milliseconds since unix epoch 231 | uint64 timestamp = 2; 232 | bytes signature = 3; 233 | // pubkey binary of the signing keypair 234 | bytes signer = 4; 235 | } 236 | 237 | message org_disable_res_v1 { 238 | uint64 oui = 1; 239 | // in seconds since unix epoch 240 | uint64 timestamp = 2; 241 | // pubkey binary of the signing keypair 242 | bytes signer = 3; 243 | // Signature over the response by the config service 244 | bytes signature = 4; 245 | } 246 | 247 | message org_enable_req_v1 { 248 | uint64 oui = 1; 249 | // in milliseconds since unix epoch 250 | uint64 timestamp = 2; 251 | bytes signature = 3; 252 | // pubkey binary of the signing keypair 253 | bytes signer = 4; 254 | } 255 | 256 | message org_enable_res_v1 { 257 | uint64 oui = 1; 258 | // in seconds since unix epoch 259 | uint64 timestamp = 2; 260 | // pubkey binary of the signing keypair 261 | bytes signer = 3; 262 | // Signature over the response by the config service 263 | bytes signature = 4; 264 | } 265 | 266 | message route_list_req_v1 { 267 | uint64 oui = 1; 268 | // in milliseconds since unix epoch 269 | uint64 timestamp = 2; 270 | bytes signature = 3; 271 | // pubkey binary of the signing keypair 272 | bytes signer = 4; 273 | } 274 | 275 | message route_list_res_v1 { 276 | repeated route_v1 routes = 1; 277 | // in seconds since unix epoch 278 | uint64 timestamp = 2; 279 | // pubkey binary of the signing keypair 280 | bytes signer = 3; 281 | // Signature over the response by the config service 282 | bytes signature = 4; 283 | } 284 | 285 | message route_get_req_v1 { 286 | string id = 1; 287 | // in milliseconds since unix epoch 288 | uint64 timestamp = 2; 289 | bytes signature = 3; 290 | // pubkey binary of the signing keypair 291 | bytes signer = 4; 292 | } 293 | 294 | message route_create_req_v1 { 295 | uint64 oui = 1; 296 | route_v1 route = 2; 297 | // in milliseconds since unix epoch 298 | uint64 timestamp = 3; 299 | bytes signature = 4; 300 | // pubkey binary of the signing keypair 301 | bytes signer = 5; 302 | } 303 | 304 | message route_update_req_v1 { 305 | route_v1 route = 1; 306 | // in milliseconds since unix epoch 307 | uint64 timestamp = 2; 308 | bytes signature = 3; 309 | // pubkey binary of the signing keypair 310 | bytes signer = 4; 311 | } 312 | 313 | message route_delete_req_v1 { 314 | string id = 1; 315 | // in milliseconds since unix epoch 316 | uint64 timestamp = 2; 317 | bytes signature = 3; 318 | // pubkey binary of the signing keypair 319 | bytes signer = 4; 320 | } 321 | 322 | message route_res_v1 { 323 | route_v1 route = 1; 324 | // in seconds since unix epoch 325 | uint64 timestamp = 2; 326 | // pubkey binary of the signing keypair 327 | bytes signer = 3; 328 | // Signature over the response by the config service 329 | bytes signature = 4; 330 | } 331 | 332 | message route_get_euis_req_v1 { 333 | string route_id = 1; 334 | // in milliseconds since unix epoch 335 | uint64 timestamp = 2; 336 | bytes signature = 3; 337 | // pubkey binary of the signing keypair 338 | bytes signer = 4; 339 | } 340 | 341 | message route_update_euis_req_v1 { 342 | action_v1 action = 1; 343 | eui_pair_v1 eui_pair = 2; 344 | // in milliseconds since unix epoch 345 | uint64 timestamp = 3; 346 | bytes signature = 4; 347 | // pubkey binary of the signing keypair 348 | bytes signer = 5; 349 | } 350 | 351 | message route_euis_res_v1 { 352 | // in seconds since unix epoch 353 | uint64 timestamp = 1; 354 | // pubkey binary of the signing keypair 355 | bytes signer = 2; 356 | // Signature over the response by the config service 357 | bytes signature = 3; 358 | } 359 | 360 | message route_get_devaddr_ranges_req_v1 { 361 | string route_id = 1; 362 | // in milliseconds since unix epoch 363 | uint64 timestamp = 2; 364 | bytes signature = 3; 365 | // pubkey binary of the signing keypair 366 | bytes signer = 4; 367 | } 368 | 369 | message route_update_devaddr_ranges_req_v1 { 370 | action_v1 action = 1; 371 | devaddr_range_v1 devaddr_range = 2; 372 | // in milliseconds since unix epoch 373 | uint64 timestamp = 3; 374 | bytes signature = 4; 375 | // pubkey binary of the signing keypair 376 | bytes signer = 5; 377 | } 378 | 379 | message route_devaddr_ranges_res_v1 { 380 | // in seconds since unix epoch 381 | uint64 timestamp = 1; 382 | // pubkey binary of the signing keypair 383 | bytes signer = 2; 384 | // Signature over the response by the config service 385 | bytes signature = 3; 386 | } 387 | 388 | message route_stream_req_v1 { 389 | // in milliseconds since unix epoch 390 | uint64 timestamp = 1; 391 | bytes signature = 2; 392 | // pubkey binary of the signing keypair 393 | bytes signer = 3; 394 | // timestamp in milliseconds, only changes since this timestamp are 395 | // streamed back to caller 396 | uint64 since = 4; 397 | } 398 | 399 | message route_stream_res_v1 { 400 | // in seconds since unix epoch 401 | uint64 timestamp = 1; 402 | // pubkey binary of the signing keypair 403 | bytes signer = 2; 404 | // Signature over the response by the config service 405 | bytes signature = 3; 406 | action_v1 action = 4; 407 | oneof data { 408 | route_v1 route = 5; 409 | eui_pair_v1 eui_pair = 6; 410 | devaddr_range_v1 devaddr_range = 7; 411 | skf_v1 skf = 8; 412 | } 413 | } 414 | 415 | message skf_v1 { 416 | string route_id = 1; 417 | uint32 devaddr = 2; 418 | // the hex-encoded string of the binary session key 419 | string session_key = 3; 420 | uint32 max_copies = 4; 421 | } 422 | 423 | message route_skf_list_req_v1 { 424 | string route_id = 1; 425 | // in milliseconds since unix epoch 426 | uint64 timestamp = 2; 427 | bytes signature = 3; 428 | // pubkey binary of the signing keypair 429 | bytes signer = 4; 430 | } 431 | 432 | message route_skf_get_req_v1 { 433 | string route_id = 1; 434 | uint32 devaddr = 2; 435 | // in milliseconds since unix epoch 436 | uint64 timestamp = 3; 437 | bytes signature = 4; 438 | // pubkey binary of the signing keypair 439 | bytes signer = 5; 440 | } 441 | 442 | message route_skf_update_req_v1 { 443 | message route_skf_update_v1 { 444 | uint32 devaddr = 1; 445 | // the hex-encoded string of the binary session key 446 | string session_key = 2; 447 | action_v1 action = 3; 448 | uint32 max_copies = 4; 449 | } 450 | 451 | string route_id = 1; 452 | // WARNING: this will limited to 100 updates per req 453 | repeated route_skf_update_v1 updates = 2; 454 | // in milliseconds since unix epoch 455 | uint64 timestamp = 3; 456 | bytes signature = 4; 457 | // pubkey binary of the signing keypair 458 | bytes signer = 5; 459 | } 460 | 461 | message route_skf_update_res_v1 { 462 | // in seconds since unix epoch 463 | uint64 timestamp = 1; 464 | // pubkey binary of the signing keypair 465 | bytes signer = 2; 466 | // Signature over the response by the config service 467 | bytes signature = 3; 468 | } 469 | 470 | message gateway_region_params_req_v1 { 471 | region region = 1; 472 | bytes address = 2; 473 | bytes signature = 3; 474 | } 475 | 476 | message gateway_region_params_res_v1 { 477 | region region = 1; 478 | blockchain_region_params_v1 params = 2; 479 | uint64 gain = 3; 480 | // Signature over the response by the config service 481 | bytes signature = 4; 482 | // in seconds since unix epoch 483 | uint64 timestamp = 5; 484 | // pubkey binary of the signing keypair 485 | bytes signer = 6; 486 | } 487 | 488 | message gateway_location_req_v1 { 489 | bytes gateway = 1; 490 | bytes signature = 2; 491 | // pubkey binary of the signing keypair 492 | bytes signer = 3; 493 | } 494 | 495 | message gateway_location_res_v1 { 496 | string location = 1; 497 | // in seconds since unix epoch 498 | uint64 timestamp = 2; 499 | // pubkey binary of the signing keypair 500 | bytes signer = 3; 501 | // Signature over the response by the config service 502 | bytes signature = 4; 503 | } 504 | 505 | message admin_load_region_req_v1 { 506 | region region = 1; 507 | blockchain_region_params_v1 params = 2; 508 | // Gzip-compressed file content from converting region geojson to a list of h3 509 | // indexes 510 | bytes hex_indexes = 3; 511 | bytes signature = 4; 512 | // pubkey binary of the signing keypair 513 | bytes signer = 5; 514 | } 515 | 516 | message admin_load_region_res_v1 { 517 | // in seconds since unix epoch 518 | uint64 timestamp = 1; 519 | // pubkey binary of the signing keypair 520 | bytes signer = 2; 521 | // Signature over the response by the config service 522 | bytes signature = 3; 523 | } 524 | 525 | message admin_add_key_req_v1 { 526 | enum key_type_v1 { 527 | // administrative operator key 528 | administrator = 0; 529 | // packet routing infrastructure key for routing streams 530 | packet_router = 1; 531 | // keys for verifying requests from other oracles 532 | oracle = 2; 533 | } 534 | 535 | bytes pubkey = 1; 536 | key_type_v1 key_type = 2; 537 | // Signature of the request message signed by an admin key 538 | // already registered to the config service 539 | bytes signature = 3; 540 | // pubkey binary of the signing keypair 541 | bytes signer = 4; 542 | } 543 | 544 | message admin_remove_key_req_v1 { 545 | bytes pubkey = 1; 546 | // Signature of the request message signed by an admin key 547 | // already registered to the config service 548 | bytes signature = 2; 549 | // pubkey binary of the signing keypair 550 | bytes signer = 3; 551 | } 552 | 553 | message admin_key_res_v1 { 554 | // in seconds since unix epoch 555 | uint64 timestamp = 1; 556 | // pubkey binary of the signing keypair 557 | bytes signer = 2; 558 | // Signature over the response by the config service 559 | bytes signature = 3; 560 | } 561 | 562 | message gateway_metadata { 563 | /// The asserted h3 location of the gateway 564 | string location = 1; 565 | /// LoRa region derived from the asserted location 566 | region region = 2; 567 | /// the transmit gain value of the gateway in dbi x 10 568 | /// For example 1 dbi = 10, 15 dbi = 150 569 | int32 gain = 3; 570 | /// The asserted elevation of the gateway 571 | int32 elevation = 4; 572 | } 573 | 574 | message gateway_info { 575 | // The public key binary address and on-chain identity of the gateway 576 | bytes address = 1; 577 | // Whether or not the hotspot participates in PoC or only transfers data 578 | bool is_full_hotspot = 2; 579 | // The gateway's metadata as recorded on the blockchain 580 | gateway_metadata metadata = 3; 581 | } 582 | 583 | /// Look up the details of a given hotspot public key 584 | message gateway_info_req_v1 { 585 | /// The pubkey_bin address of the gateway to look up 586 | bytes address = 1; 587 | /// sig from a key known to the config service 588 | bytes signature = 2; 589 | // pubkey binary of the signing keypair 590 | bytes signer = 3; 591 | } 592 | 593 | message gateway_info_res_v1 { 594 | /// Timestamp of response in seconds since unix epoch 595 | uint64 timestamp = 1; 596 | gateway_info info = 2; 597 | /// sig from the config service 598 | bytes signature = 3; 599 | // pubkey binary of the signing keypair 600 | bytes signer = 4; 601 | } 602 | 603 | /// Request a stream of all active gateways 604 | message gateway_info_stream_req_v1 { 605 | uint32 batch_size = 1; 606 | /// sig from a key known to the config service 607 | bytes signature = 2; 608 | // pubkey binary of the signing keypair 609 | bytes signer = 3; 610 | } 611 | 612 | /// Active gateway info streaming response containing a batch of gateways 613 | message gateway_info_stream_res_v1 { 614 | /// Timestamp of response in seconds since unix epoch 615 | uint64 timestamp = 1; 616 | /// batch of gateways 617 | repeated gateway_info gateways = 2; 618 | /// sig from the config service 619 | bytes signature = 3; 620 | // pubkey binary of the signing keypair 621 | bytes signer = 4; 622 | } 623 | 624 | message region_params_req_v1 { 625 | region region = 1; 626 | /// sig from a key known to the config service 627 | bytes signature = 2; 628 | // pubkey binary of the signing keypair 629 | bytes signer = 3; 630 | } 631 | 632 | message region_params_res_v1 { 633 | region region = 1; 634 | blockchain_region_params_v1 params = 2; 635 | /// sig from the config service 636 | bytes signature = 3; 637 | // pubkey binary of the signing keypair 638 | bytes signer = 4; 639 | // in seconds since unix epoch 640 | uint64 timestamp = 5; 641 | } 642 | 643 | // ------------------------------------------------------------------ 644 | // Service Definitions 645 | // ------------------------------------------------------------------ 646 | 647 | service org { 648 | // List Org (no auth) 649 | rpc list(org_list_req_v1) returns (org_list_res_v1); 650 | // Get Org (no auth) 651 | rpc get(org_get_req_v1) returns (org_res_v1); 652 | // Create Org on Helium Network (auth admin only) 653 | rpc create_helium(org_create_helium_req_v1) returns (org_res_v1); 654 | // Create Org on any network (auth admin only) 655 | rpc create_roamer(org_create_roamer_req_v1) returns (org_res_v1); 656 | // Update any Org (Helium or Roaming) 657 | // Modify payer and add/remove delegate keys (owner/admin) 658 | // Modify owner and add/remove devaddr constraints (auth admin only) 659 | rpc update(org_update_req_v1) returns (org_res_v1); 660 | // Disable an org, this sends a stream route delete update to HPR 661 | // for all associated routes (auth admin only) 662 | rpc disable(org_disable_req_v1) returns (org_disable_res_v1); 663 | // Enable an org, this sends a stream route create update to HPR 664 | // for all associated routes (auth admin only) 665 | rpc enable(org_enable_req_v1) returns (org_enable_res_v1); 666 | } 667 | 668 | service route { 669 | // List Routes for an Org (auth delegate_keys/owner/admin) 670 | rpc list(route_list_req_v1) returns (route_list_res_v1); 671 | // Get Route for an Org (auth delegate_keys/owner/admin) 672 | rpc get(route_get_req_v1) returns (route_res_v1); 673 | // Create Route for an Org (auth delegate_keys/owner/admin) 674 | rpc create(route_create_req_v1) returns (route_res_v1); 675 | // Update Route for an Org (auth delegate_keys/owner/admin) 676 | rpc update(route_update_req_v1) returns (route_res_v1); 677 | // Delete Route for an Org (auth delegate_keys/owner/admin) 678 | rpc delete (route_delete_req_v1) returns (route_res_v1); 679 | 680 | // Stream Routes update (auth admin only) 681 | rpc stream(route_stream_req_v1) returns (stream route_stream_res_v1); 682 | 683 | // EUIs 684 | 685 | // Get EUIs for a Route (auth delegate_keys/owner/admin) 686 | rpc get_euis(route_get_euis_req_v1) returns (stream eui_pair_v1); 687 | // Update (single add or remove) EUIs for a Route (auth 688 | // delegate_keys/owner/admin) 689 | rpc update_euis(stream route_update_euis_req_v1) returns (route_euis_res_v1); 690 | 691 | // DevAddr Ranges 692 | 693 | // Get DevAddr Ranges for a Route (auth delegate_keys/owner/admin) 694 | rpc get_devaddr_ranges(route_get_devaddr_ranges_req_v1) 695 | returns (stream devaddr_range_v1); 696 | // Update (single add or remove) DevAddr Ranges for a Route (auth 697 | // delegate_keys/owner/admin) 698 | rpc update_devaddr_ranges(stream route_update_devaddr_ranges_req_v1) 699 | returns (route_devaddr_ranges_res_v1); 700 | 701 | // Session Key Filters (aka SKFs) 702 | 703 | // List Filters for a Route (auth delegate_keys/owner/admin) 704 | rpc list_skfs(route_skf_list_req_v1) returns (stream skf_v1); 705 | // List Filters for a DevAddr (auth delegate_keys/owner/admin 706 | rpc get_skfs(route_skf_get_req_v1) returns (stream skf_v1); 707 | // Update Filters for an Org (auth delegate_keys/owner/admin) 708 | rpc update_skfs(route_skf_update_req_v1) returns (route_skf_update_res_v1); 709 | } 710 | 711 | service gateway { 712 | // Return the region params for the asserted location of the signed gateway 713 | // address (no auth, but signature validated) 714 | rpc region_params(gateway_region_params_req_v1) 715 | returns (gateway_region_params_res_v1); 716 | // Get H3 Location for a gateway (auth admin only) 717 | rpc location(gateway_location_req_v1) returns (gateway_location_res_v1); 718 | // Get info for the specified gateway 719 | rpc info(gateway_info_req_v1) returns (gateway_info_res_v1); 720 | // Get a stream of gateway info 721 | rpc info_stream(gateway_info_stream_req_v1) 722 | returns (stream gateway_info_stream_res_v1); 723 | } 724 | 725 | service admin { 726 | // Authorize a public key for validating trusted rpcs 727 | rpc add_key(admin_add_key_req_v1) returns (admin_key_res_v1); 728 | // Deauthorize a public key for validating trusted rpcs 729 | rpc remove_key(admin_remove_key_req_v1) returns (admin_key_res_v1); 730 | // Load params and cell indexes for a region into the config service (auth 731 | // admin only) 732 | rpc load_region(admin_load_region_req_v1) returns (admin_load_region_res_v1); 733 | // Return the region params for the specified region 734 | rpc region_params(region_params_req_v1) returns (region_params_res_v1); 735 | } 736 | -------------------------------------------------------------------------------- /src/service/local.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium.local; 4 | 5 | import "gateway_staking_mode.proto"; 6 | 7 | message pubkey_res { 8 | bytes address = 1; 9 | bytes onboarding_address = 2; 10 | } 11 | message pubkey_req {} 12 | 13 | message keyed_uri { 14 | bytes address = 1; 15 | string uri = 2; 16 | } 17 | 18 | message region_req {} 19 | message region_res { int32 region = 1; } 20 | 21 | message router_req {} 22 | message router_res { 23 | string uri = 1; 24 | bool connected = 2; 25 | bytes session_key = 3; 26 | } 27 | 28 | message add_gateway_req { 29 | bytes owner = 1; 30 | bytes payer = 2; 31 | gateway_staking_mode staking_mode = 3; 32 | } 33 | 34 | message add_gateway_res { bytes add_gateway_txn = 1; } 35 | 36 | service api { 37 | rpc pubkey(pubkey_req) returns (pubkey_res); 38 | rpc region(region_req) returns (region_res); 39 | rpc router(router_req) returns (router_res); 40 | rpc add_gateway(add_gateway_req) returns (add_gateway_res); 41 | } 42 | -------------------------------------------------------------------------------- /src/service/mobile_config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium.mobile_config; 4 | 5 | import "hex_boosting.proto"; 6 | import "service_provider.proto"; 7 | import "reward_manifest.proto"; 8 | // ------------------------------------------------------------------ 9 | // Message Definitions 10 | // ------------------------------------------------------------------ 11 | 12 | // == Field Notes == 13 | // 14 | // - Every message including a `signature` field will need to be signed over the 15 | // complete message, with the `signature` field set to an empty value. 16 | // Requests are expected to be signed by the client to validate authorization 17 | // to make the request and responses are signed by the mobile_config server to 18 | // ensure validity of the data returned 19 | // 20 | // - Keypair fields are binary encoded public keys, Rust encoding example here: 21 | // https://github.com/helium/helium-crypto-rs/blob/main/src/public_key.rs#L347-L354 22 | 23 | message wifi_deployment_info { 24 | // antenna id 25 | uint32 antenna = 1; 26 | // The height of the hotspot above ground level in whole meters 27 | uint32 elevation = 2; 28 | uint32 azimuth = 3; 29 | uint32 mechanical_down_tilt = 4; 30 | uint32 electrical_down_tilt = 5; 31 | } 32 | 33 | message cbrs_deployment_info { 34 | repeated cbrs_radio_deployment_info cbrs_radios_deployment_info = 1; 35 | } 36 | 37 | message cbrs_radio_deployment_info { 38 | // CBSD_ID 39 | string radio_id = 1; 40 | // The asserted elevation of the gateway above ground level in whole meters 41 | uint32 elevation = 2; 42 | } 43 | 44 | message gateway_metadata { 45 | option deprecated = true; 46 | // The res12 h3 index asserted address of the gateway as a string 47 | // where an unasserted gateway returns an empty string 48 | string location = 2; 49 | } 50 | 51 | message gateway_metadata_v2 { 52 | // The res12 h3 index asserted address of the gateway as a string 53 | // where an unasserted gateway returns an empty string 54 | string location = 2; 55 | oneof deployment_info { 56 | wifi_deployment_info wifi_deployment_info = 3; 57 | cbrs_deployment_info cbrs_deployment_info = 4; 58 | } 59 | } 60 | 61 | message gateway_info { 62 | option deprecated = true; 63 | // The public key binary address and on-chain identity of the gateway 64 | bytes address = 1; 65 | // The gateway metadata as recorded on the blockchain 66 | gateway_metadata metadata = 2; 67 | // the asserted device type of the gateway 68 | device_type device_type = 3; 69 | } 70 | 71 | message gateway_info_v2 { 72 | // The public key binary address and on-chain identity of the gateway 73 | bytes address = 1; 74 | // The gateway metadata as recorded on the blockchain 75 | gateway_metadata_v2 metadata = 2; 76 | // the asserted device type of the gateway 77 | device_type device_type = 3; 78 | // The unix epoch timestamp (in seconds) 79 | // when the gateway was first added to the database. 80 | uint64 created_at = 4; 81 | // The unix epoch timestamp (in seconds) 82 | // when the gateway parameters (highly possible) were changed in the database. 83 | uint64 updated_at = 5; 84 | } 85 | 86 | // Warning: Be careful, values in v2 differ from v1 87 | enum device_type_v2 { 88 | device_type_v2_indoor = 0; 89 | device_type_v2_outdoor = 1; 90 | device_type_v2_data_only = 2; 91 | } 92 | 93 | message location_info { 94 | // The res12 h3 index asserted address of the gateway as a string 95 | string location = 1; 96 | // The Unix epoch timestamp (in seconds) when the location was last changed 97 | uint64 location_changed_at = 2; 98 | } 99 | 100 | message deployment_info { 101 | // The antenna ID of the gateway 102 | uint32 antenna = 1; 103 | // The height of the hotspot above ground level, in whole meters 104 | uint32 elevation = 2; 105 | // The azimuth (direction) of the antenna, in degrees (whole number) 106 | uint32 azimuth = 3; 107 | } 108 | 109 | message gateway_metadata_v3 { 110 | location_info location_info = 1; 111 | deployment_info deployment_info = 2; 112 | } 113 | 114 | message gateway_info_v3 { 115 | // The public key binary address and on-chain identity of the gateway 116 | bytes address = 1; 117 | // The gateway metadata 118 | gateway_metadata_v3 metadata = 2; 119 | // The asserted device type of the gateway 120 | device_type_v2 device_type = 3; 121 | // The Unix epoch timestamp (in seconds) when the gateway was first added to 122 | // the database 123 | uint64 created_at = 4; 124 | // The Unix epoch timestamp (in seconds) when the gateway parameters were last 125 | // updated. NOTE: This field is also updated when the location changes. 126 | uint64 updated_at = 5; 127 | // Count of hotspot location changes 128 | uint64 num_location_asserts = 6; 129 | } 130 | 131 | message gateway_info_req_v1 { 132 | // The public key address of the gateway to look up 133 | bytes address = 1; 134 | // pubkey binary of the signing keypair 135 | bytes signer = 2; 136 | bytes signature = 3; 137 | } 138 | 139 | message gateway_info_batch_req_v1 { 140 | // List of public key addresses of gateways to look up 141 | repeated bytes addresses = 1; 142 | // max number of gateway info records in each message of the response stream 143 | uint32 batch_size = 2; 144 | // pubkey binary of the signing keypair 145 | bytes signer = 3; 146 | bytes signature = 4; 147 | } 148 | 149 | message gateway_info_res_v1 { 150 | gateway_info info = 1; 151 | // unix epoch timestamp in seconds 152 | uint64 timestamp = 2; 153 | // pubkey binary of the signing keypair 154 | bytes signer = 3; 155 | bytes signature = 4; 156 | } 157 | 158 | message gateway_info_res_v2 { 159 | gateway_info_v2 info = 1; 160 | // unix epoch timestamp in seconds 161 | uint64 timestamp = 2; 162 | // pubkey binary of the signing keypair 163 | bytes signer = 3; 164 | bytes signature = 4; 165 | } 166 | 167 | message gateway_info_stream_req_v1 { 168 | option deprecated = true; 169 | // max number of gateway info records in each message of the response stream 170 | uint32 batch_size = 1; 171 | // pubkey binary of the signing keypair 172 | bytes signer = 2; 173 | bytes signature = 3; 174 | // Device types that will be returned in the response 175 | // Returns all devices if empty 176 | repeated device_type device_types = 4; 177 | } 178 | 179 | message gateway_info_stream_req_v3 { 180 | // max number of gateway info records in each message of the response stream 181 | uint32 batch_size = 1; 182 | // pubkey binary of the signing keypair 183 | bytes signer = 2; 184 | bytes signature = 3; 185 | // Device types that will be returned in the response 186 | // Returns all devices if empty 187 | repeated device_type_v2 device_types = 4; 188 | // The Unix epoch timestamp (in seconds). 189 | // Filters the response based on the last time gateway parameter(s) was 190 | // updated. Use 0 to fetch all gateways. 191 | // NOTE: It is recommended to use the highest `updated_at` field from 192 | // returned radios in the next subsequent requests. 193 | uint64 min_updated_at = 5; 194 | // The Unix epoch timestamp (in seconds). 195 | // Filters the response based on the last time gateway changed its location. 196 | // Use 0 to fetch all gateways. 197 | uint64 min_location_changed_at = 6; 198 | } 199 | 200 | message gateway_info_stream_req_v2 { 201 | // max number of gateway info records in each message of the response stream 202 | uint32 batch_size = 1; 203 | // pubkey binary of the signing keypair 204 | bytes signer = 2; 205 | bytes signature = 3; 206 | // Device types that will be returned in the response 207 | // Returns all devices if empty 208 | repeated device_type device_types = 4; 209 | // The Unix epoch timestamp (in seconds). 210 | // Filters the response based on the last time gateway parameter(s) was 211 | // updated. Use 0 to fetch all gateways. 212 | // NOTE: It is recommended to use the highest `updated_at` field from 213 | // returned radios in the next subsequent requests. 214 | uint64 min_updated_at = 5; 215 | } 216 | 217 | message gateway_info_stream_res_v1 { 218 | // a list of gateway info numbering up to the request batch size 219 | repeated gateway_info gateways = 1; 220 | // unix epoch timestamp in seconds 221 | uint64 timestamp = 2; 222 | // pubkey binary of the signing keypair 223 | bytes signer = 3; 224 | bytes signature = 4; 225 | } 226 | 227 | message gateway_info_stream_res_v2 { 228 | // a list of gateway info numbering up to the request batch size 229 | repeated gateway_info_v2 gateways = 1; 230 | // unix epoch timestamp in seconds 231 | uint64 timestamp = 2; 232 | // pubkey binary of the signing keypair 233 | bytes signer = 3; 234 | bytes signature = 4; 235 | } 236 | 237 | message gateway_info_stream_res_v3 { 238 | // a list of gateway info numbering up to the request batch size 239 | repeated gateway_info_v3 gateways = 1; 240 | // unix epoch timestamp in seconds 241 | uint64 timestamp = 2; 242 | // pubkey binary of the signing keypair 243 | bytes signer = 3; 244 | bytes signature = 4; 245 | } 246 | 247 | message entity_verify_req_v1 { 248 | // binary identifier of the entity 249 | bytes entity_id = 1; 250 | // pubkey binary of the requestor signing keypair 251 | bytes signer = 2; 252 | bytes signature = 3; 253 | } 254 | 255 | message entity_verify_res_v1 { 256 | // unix epoch timestamp in seconds 257 | uint64 timestamp = 2; 258 | // pubkey binary of the requestor signing keypair 259 | bytes signer = 3; 260 | bytes signature = 4; 261 | } 262 | 263 | message carrier_key_to_entity_req_v1 { 264 | // string representation of the helium pubkey of the carrier 265 | string pubkey = 1; 266 | // pubkey binary of the requestor signing keypair 267 | bytes signer = 2; 268 | bytes signature = 3; 269 | } 270 | 271 | message carrier_key_to_entity_res_v1 { 272 | // unix epoch timestamp in seconds 273 | uint64 timestamp = 1; 274 | // string representing the entity key 275 | string entity_key = 2; 276 | // pubkey binary of the requestor signing keypair 277 | bytes signer = 3; 278 | bytes signature = 4; 279 | } 280 | 281 | enum admin_key_role { 282 | // administrative operator key 283 | administrator = 0; 284 | // routing infrastructure key for routing streams 285 | router = 1; 286 | // keys for verifying requests from other oracles 287 | oracle = 2; 288 | // carrier authorizing keys for signing mobile subscriber activity 289 | carrier = 3; 290 | // propagation calculation service of a mobile carrier 291 | pcs = 4; 292 | // key for signing ban requests 293 | admin_key_role_banning = 5; 294 | } 295 | 296 | enum network_key_role { 297 | mobile_carrier = 0; 298 | mobile_router = 1; 299 | // Keys from the Propagation Calculation Service 300 | mobile_pcs = 2; 301 | // Key for signing ban requests 302 | network_key_role_banning = 3; 303 | } 304 | 305 | enum device_type { 306 | option deprecated = true; 307 | cbrs = 0; 308 | wifi_indoor = 1; 309 | wifi_outdoor = 2; 310 | wifi_data_only = 3; 311 | } 312 | 313 | message authorization_verify_req_v1 { 314 | // the pubkey binary of the authorized entity being verified 315 | bytes pubkey = 1; 316 | // the associated role being verified for the key 317 | network_key_role role = 2; 318 | // pubkey binary of the signing keypair 319 | bytes signer = 3; 320 | // Signature over the request by the requesting oracle 321 | bytes signature = 4; 322 | } 323 | 324 | message authorization_verify_res_v1 { 325 | // unix epoch timestamp in seconds 326 | uint64 timestamp = 1; 327 | // pubkey binary of the signing keypair 328 | bytes signer = 2; 329 | // Signature over the response by the config service 330 | bytes signature = 3; 331 | } 332 | 333 | message authorization_list_req_v1 { 334 | // role of the keys being requested 335 | network_key_role role = 1; 336 | // pubkey binary of the signing keypair 337 | bytes signer = 2; 338 | // Signature over the request by the requesting oracle 339 | bytes signature = 3; 340 | } 341 | 342 | message authorization_list_res_v1 { 343 | // List of public key binaries of all registered entities by requested role 344 | repeated bytes pubkeys = 1; 345 | // unix epoch timestamp in seconds 346 | uint64 timestamp = 2; 347 | // pubkey binary of the signing keypair 348 | bytes signer = 3; 349 | // Signature over the response by the config service 350 | bytes signature = 4; 351 | } 352 | 353 | message admin_add_key_req_v1 { 354 | bytes pubkey = 1; 355 | admin_key_role role = 2; 356 | // unix epoch timestamp in seconds 357 | uint64 timestamp = 3; 358 | // pubkey binary of the signing keypair 359 | bytes signer = 4; 360 | // Signature of the request message signed by an admin key 361 | // already registered to the config service 362 | bytes signature = 5; 363 | } 364 | 365 | message admin_remove_key_req_v1 { 366 | bytes pubkey = 1; 367 | // unix epoch timestamp in seconds 368 | uint64 timestamp = 2; 369 | // pubkey binary of the signing keypair 370 | bytes signer = 3; 371 | // Signature of the request message signed by an admin key 372 | // already registered to the config service 373 | bytes signature = 4; 374 | admin_key_role role = 5; 375 | } 376 | 377 | message admin_key_res_v1 { 378 | // unix epoch timestamp in seconds 379 | uint64 timestamp = 1; 380 | // pubkey binary of the signing keypair 381 | bytes signer = 2; 382 | // Signature over the response by the config service 383 | bytes signature = 3; 384 | } 385 | 386 | message boosted_hex_info_stream_req_v1 { 387 | // max number of boosted hex info records in each message of the response 388 | // stream 389 | uint32 batch_size = 1; 390 | // pubkey binary of the signing keypair 391 | bytes signer = 2; 392 | bytes signature = 3; 393 | } 394 | 395 | message boosted_hex_modified_info_stream_req_v1 { 396 | // max number of boosted hex info records in each message of the response 397 | // stream 398 | uint32 batch_size = 1; 399 | // return only those records which were modified after the specified timestamp 400 | // unix epoch timestamp in seconds 401 | uint64 timestamp = 2; 402 | // pubkey binary of the signing keypair 403 | bytes signer = 3; 404 | bytes signature = 4; 405 | } 406 | 407 | message boosted_hex_info_stream_res_v1 { 408 | // a list of boosted hex info 409 | repeated boosted_hex_info_v1 hexes = 1; 410 | // unix epoch timestamp in seconds 411 | uint64 timestamp = 2; 412 | // pubkey binary of the signing keypair 413 | bytes signer = 3; 414 | bytes signature = 4; 415 | } 416 | 417 | message carrier_incentive_promotion_list_req_v1 { 418 | // unix epoch timestamp in seconds 419 | uint64 timestamp = 1; 420 | bytes signer = 2; 421 | bytes signature = 3; 422 | } 423 | 424 | message carrier_incentive_promotion_list_res_v1 { 425 | bytes signer = 1; 426 | bytes signature = 2; 427 | repeated service_provider_promotions service_provider_promotions = 3; 428 | } 429 | 430 | // ------------------------------------------------------------------ 431 | // Service Definitions 432 | // ------------------------------------------------------------------ 433 | 434 | service gateway { 435 | // Get info for the specified gateway 436 | rpc info(gateway_info_req_v1) returns (gateway_info_res_v1) { 437 | option deprecated = true; 438 | } 439 | // Get info for a batch of gateways specified by public key 440 | rpc info_batch(gateway_info_batch_req_v1) 441 | returns (stream gateway_info_stream_res_v1) { 442 | option deprecated = true; 443 | } 444 | // Get a stream of gateway info 445 | rpc info_stream(gateway_info_stream_req_v1) 446 | returns (stream gateway_info_stream_res_v1) { 447 | option deprecated = true; 448 | } 449 | 450 | // V2 451 | // Get info for the specified gateway (V2) 452 | rpc info_v2(gateway_info_req_v1) returns (gateway_info_res_v2); 453 | // Get a stream of gateway info (V2) 454 | rpc info_stream_v2(gateway_info_stream_req_v2) 455 | returns (stream gateway_info_stream_res_v2); 456 | // Get info for a batch of gateways specified by public key (V2) 457 | rpc info_batch_v2(gateway_info_batch_req_v1) 458 | returns (stream gateway_info_stream_res_v2); 459 | 460 | // V3 461 | // Get a stream of gateway info (V3) 462 | rpc info_stream_v3(gateway_info_stream_req_v3) 463 | returns (stream gateway_info_stream_res_v3); 464 | } 465 | 466 | service entity { 467 | // Verify the rewardable entity (mobile subscriber) is registered to the chain 468 | rpc verify(entity_verify_req_v1) returns (entity_verify_res_v1); 469 | } 470 | 471 | service carrier_service { 472 | // Retrieve an entity key for the specified helium pubkey 473 | rpc key_to_entity(carrier_key_to_entity_req_v1) 474 | returns (carrier_key_to_entity_res_v1); 475 | rpc list_incentive_promotions(carrier_incentive_promotion_list_req_v1) 476 | returns (carrier_incentive_promotion_list_res_v1); 477 | } 478 | 479 | service authorization { 480 | // Submit a pubkey binary and network key role for an authorized entity on the 481 | // mobile network to verify if it is registered with the given role. 482 | // `mobile_router` keys have data transfer burn authority while 483 | // `mobile_carrier` keys have subscriber activity report signing authority 484 | rpc verify(authorization_verify_req_v1) returns (authorization_verify_res_v1); 485 | // Retrieve a list of all registered pubkey binaries registered to the config 486 | // service with the requested role 487 | rpc list(authorization_list_req_v1) returns (authorization_list_res_v1); 488 | } 489 | 490 | service admin { 491 | // Authorize a public key for validating trusted rpcs 492 | rpc add_key(admin_add_key_req_v1) returns (admin_key_res_v1); 493 | // Deauthorize a public key for validating trusted rpcs 494 | rpc remove_key(admin_remove_key_req_v1) returns (admin_key_res_v1); 495 | } 496 | 497 | service hex_boosting { 498 | // Get a stream of hex boost info 499 | rpc info_stream(boosted_hex_info_stream_req_v1) 500 | returns (stream boosted_hex_info_stream_res_v1); 501 | // Get a stream of modified hex boost info since the specified timestamp 502 | rpc modified_info_stream(boosted_hex_modified_info_stream_req_v1) 503 | returns (stream boosted_hex_info_stream_res_v1); 504 | } 505 | -------------------------------------------------------------------------------- /src/service/multi_buy.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium.multi_buy; 4 | 5 | message multi_buy_inc_req_v1 { string key = 1; } 6 | 7 | message multi_buy_inc_res_v1 { uint32 count = 1; } 8 | 9 | service multi_buy { 10 | rpc inc(multi_buy_inc_req_v1) returns (multi_buy_inc_res_v1); 11 | } 12 | -------------------------------------------------------------------------------- /src/service/packet_router.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium.packet_router; 4 | 5 | import "region.proto"; 6 | import "data_rate.proto"; 7 | 8 | message packet_router_packet_report_v1 { 9 | enum packet_type { 10 | join = 0; 11 | uplink = 1; 12 | } 13 | 14 | uint64 gateway_tmst = 1; 15 | uint64 oui = 2; 16 | uint32 net_id = 3; 17 | // signal strength in dBm 18 | sint32 rssi = 4; 19 | // Frequency in hz 20 | uint32 frequency = 5; 21 | float snr = 6; 22 | data_rate datarate = 7; 23 | region region = 8; 24 | bytes gateway = 9; 25 | // Hash of `payload` within `message packet` 26 | bytes payload_hash = 10; 27 | uint32 payload_size = 11; 28 | bool free = 12; 29 | packet_type type = 13; 30 | // Timestamp in ms since unix epoch 31 | uint64 received_timestamp = 14; 32 | } 33 | 34 | message packet_router_packet_up_v1 { 35 | bytes payload = 1; 36 | uint64 timestamp = 2; 37 | // signal strength in dBm 38 | sint32 rssi = 3; 39 | // Frequency in hz 40 | uint32 frequency = 4; 41 | data_rate datarate = 5; 42 | float snr = 6; 43 | region region = 7; 44 | uint64 hold_time = 8; 45 | bytes gateway = 9; 46 | bytes signature = 10; 47 | } 48 | 49 | message packet_router_register_v1 { 50 | uint64 timestamp = 1; 51 | bytes gateway = 2; 52 | bytes signature = 3; 53 | bool session_capable = 4; 54 | uint32 packet_ack_interval = 5; 55 | } 56 | 57 | // Session offer from the packet router to the gateway. If the gateway wants to 58 | // initiate a session key it should send a packet_router_session_init_v1 message 59 | // to the packet router using data in this offer to propose a session key. 60 | // 61 | // This message is sent by packet router after the register command is sent by 62 | // the gateway. 63 | message packet_router_session_offer_v1 { bytes nonce = 1; } 64 | 65 | // Initializes a session key with the packet router. The data in this init 66 | // message has to be from the latest session offer the gateway has received, the 67 | // session key is the public key that is to be used to verify packets by packet 68 | // router, and this message is to be signed by the private key of the gateway. 69 | // Once accepted the session key replaces the current (default is gateway) key 70 | // as the verifier used by the packet router for upilnk packets. 71 | // 72 | // The session key is valid for the length of the current stream or until a next 73 | // offer message is received from the packet router. 74 | // 75 | // Once the new verifier is set by the packet router, any signed packets that do 76 | // not pass verification with the active verifier key are dropped. 77 | message packet_router_session_init_v1 { 78 | bytes gateway = 1; 79 | bytes nonce = 2; 80 | bytes session_key = 3; 81 | bytes signature = 4; 82 | } 83 | 84 | message envelope_up_v1 { 85 | oneof data { 86 | packet_router_register_v1 register = 1; 87 | packet_router_packet_up_v1 packet = 2; 88 | packet_router_session_init_v1 session_init = 3; 89 | } 90 | } 91 | 92 | message window_v1 { 93 | uint64 timestamp = 1; 94 | // Frequency in hz 95 | uint32 frequency = 2; 96 | data_rate datarate = 3; 97 | bool immediate = 4; 98 | } 99 | 100 | message packet_router_packet_down_v1 { 101 | bytes payload = 1; 102 | window_v1 rx1 = 2; 103 | window_v1 rx2 = 3; 104 | } 105 | 106 | message packet_router_packet_ack_v1 { bytes payload_hash = 1; } 107 | 108 | message envelope_down_v1 { 109 | oneof data { 110 | packet_router_packet_down_v1 packet = 1; 111 | packet_router_session_offer_v1 session_offer = 2; 112 | packet_router_packet_ack_v1 packet_ack = 3; 113 | } 114 | } 115 | 116 | service packet { 117 | rpc route(stream envelope_up_v1) returns (stream envelope_down_v1); 118 | } 119 | -------------------------------------------------------------------------------- /src/service/packet_verifier.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium.packet_verifier; 4 | 5 | message valid_packet { 6 | uint32 payload_size = 1; 7 | bytes gateway = 2; 8 | bytes payload_hash = 3; 9 | uint32 num_dcs = 4; 10 | uint64 packet_timestamp = 5; 11 | } 12 | 13 | message invalid_packet { 14 | uint32 payload_size = 1; 15 | bytes gateway = 2; 16 | bytes payload_hash = 3; 17 | invalid_packet_reason reason = 4; 18 | } 19 | 20 | enum invalid_packet_reason { 21 | invalid_packet_reason_insufficient_balance = 0; 22 | } 23 | 24 | message valid_data_transfer_session { 25 | bytes pub_key = 1; 26 | uint64 upload_bytes = 2; 27 | uint64 download_bytes = 3; 28 | uint64 num_dcs = 4; 29 | bytes payer = 5; 30 | // Timestamp in millis of the first ingest file we found a data transfer 31 | // session in 32 | uint64 first_timestamp = 6; 33 | // Timestamp in millis of the last ingest file we found a data transfer 34 | // session in 35 | uint64 last_timestamp = 7; 36 | uint64 rewardable_bytes = 8; 37 | // Timestamp in millis dated when burn transaction is confirmed 38 | uint64 burn_timestamp = 9; 39 | } 40 | -------------------------------------------------------------------------------- /src/service/poc_entropy.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium.poc_entropy; 4 | 5 | import "entropy.proto"; 6 | 7 | // request entropy 8 | message entropy_req_v1 {} 9 | 10 | service poc_entropy { rpc entropy(entropy_req_v1) returns (entropy_report_v1); } 11 | -------------------------------------------------------------------------------- /src/service/poc_lora.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium.poc_lora; 4 | 5 | import "data_rate.proto"; 6 | import "service/packet_verifier.proto"; 7 | 8 | enum verification_status { 9 | valid = 0; 10 | invalid = 1; 11 | } 12 | 13 | enum invalid_participant_side { 14 | side_none = 0; 15 | beaconer = 2; 16 | witness = 3; 17 | } 18 | 19 | enum invalid_reason { 20 | reason_none = 0; 21 | bad_signature = 1; 22 | not_asserted = 2; 23 | entropy_expired = 3; 24 | bad_entropy = 4; 25 | invalid_capability = 5; 26 | invalid_pubkey = 6; 27 | irregular_interval = 7; 28 | gateway_not_found = 8; 29 | denied = 9; 30 | invalid_packet = 10; 31 | bad_rssi = 11; 32 | invalid_region = 12; 33 | max_distance_exceeded = 13; 34 | invalid_frequency = 14; 35 | self_witness = 15; 36 | stale = 16; 37 | scaling_factor_not_found = 17; 38 | unknown_error = 18; 39 | below_min_distance = 19; 40 | duplicate = 20; 41 | denied_edge = 21; 42 | too_late = 22; 43 | gateway_no_valid_beacons = 23; 44 | gateway_no_valid_witnesses = 24; 45 | } 46 | 47 | enum non_rewardable_packet_reason { 48 | gateway_not_found_for_packet = 0; 49 | } 50 | 51 | message non_rewardable_packet { 52 | packet_verifier.valid_packet packet = 1; 53 | non_rewardable_packet_reason reason = 2; 54 | // timestamp in millis of when the packet was determined non rewardable 55 | uint64 timestamp = 3; 56 | } 57 | 58 | // beacon report as submitted by gateway to ingestor 59 | message lora_beacon_report_req_v1 { 60 | bytes pub_key = 2; 61 | bytes local_entropy = 3; 62 | bytes remote_entropy = 4; 63 | bytes data = 5; 64 | // Frequency in Hz 65 | uint64 frequency = 6; 66 | int32 channel = 7; 67 | data_rate datarate = 8; 68 | // The Conducted transmit power in ddbm. This is _not_ adjusted with the 69 | // asserted gain of the gateway 70 | int32 tx_power = 9; 71 | // Timestamp of beacon transmit in nanos since unix epoch 72 | uint64 timestamp = 10; 73 | bytes signature = 11; 74 | uint32 tmst = 12; 75 | } 76 | 77 | // response returned to gateway submitting beacon report to ingestor 78 | message lora_beacon_report_resp_v1 { string id = 1; } 79 | 80 | // witness report as submitted by gateway to ingestor 81 | message lora_witness_report_req_v1 { 82 | bytes pub_key = 2; 83 | bytes data = 3; 84 | // Timestamp of witness received in nanos since unix epoch 85 | uint64 timestamp = 4; 86 | uint32 tmst = 5; 87 | // Signal in ddBm 88 | sint32 signal = 6; 89 | // SNR in ddB 90 | int32 snr = 7; 91 | // Frequency in Hz 92 | uint64 frequency = 8; 93 | data_rate datarate = 10; 94 | bytes signature = 11; 95 | } 96 | 97 | // response returned to gateway submitting witness report to ingestor 98 | message lora_witness_report_resp_v1 { string id = 1; } 99 | 100 | // beacon report outputted by ingestor, tagged with received timestamp 101 | message lora_beacon_ingest_report_v1 { 102 | // Timestamp at ingest in millis since unix epoch 103 | uint64 received_timestamp = 1; 104 | lora_beacon_report_req_v1 report = 2; 105 | } 106 | 107 | // witness report outputted by ingestor, tagged with received timestamp 108 | message lora_witness_ingest_report_v1 { 109 | // Timestamp at ingest in millis since unix epoch 110 | uint64 received_timestamp = 1; 111 | lora_witness_report_req_v1 report = 2; 112 | } 113 | 114 | // tagged valid beacon report produced by the verifier 115 | message lora_valid_beacon_report_v1 { 116 | // Timestamp at ingest in millis since unix epoch 117 | uint64 received_timestamp = 1; 118 | // string representation of the gateways u64 hex location 119 | string location = 2; 120 | // integer representation of a 4-point precision decimal multiplier 121 | // ex: 5015 == 0.5015 122 | uint32 hex_scale = 3; 123 | lora_beacon_report_req_v1 report = 4; 124 | // integer representation of a 4-point precision decimal multiplier 125 | // based on the number of witnesses to a poc event 126 | uint32 reward_unit = 5; 127 | /// the transmit gain value of the gateway in dbi x 10 128 | /// For example 1 dbi = 10, 15 dbi = 150 129 | /// derived from gateway metadata 130 | int32 gain = 6; 131 | /// The asserted elevation of the gateway in AGL ( above ground level) 132 | /// derived from gateway metadata 133 | int32 elevation = 7; 134 | } 135 | 136 | // tagged valid witness report produced by the verifier 137 | message lora_valid_witness_report_v1 { 138 | option deprecated = true; 139 | // Timestamp at ingest in millis since unix epoch 140 | uint64 received_timestamp = 1; 141 | // string representation of the gateways u64 hex location 142 | string location = 2; 143 | // integer representation of a 4-point precision decimal multiplier 144 | // ex: 5015 == 0.5015 145 | uint32 hex_scale = 3; 146 | lora_witness_report_req_v1 report = 4; 147 | // integer representation of a 4-point precision decimal multiplier 148 | // based on the number of witnesses to a poc event 149 | uint32 reward_unit = 5; 150 | } 151 | 152 | message invalid_details { 153 | oneof data { string denylist_tag = 1; } 154 | } 155 | 156 | // tagged invalid beacon report produced by the verifier 157 | message lora_invalid_beacon_report_v1 { 158 | // Timestamp at ingest in millis since unix epoch 159 | uint64 received_timestamp = 1; 160 | invalid_reason reason = 2; 161 | lora_beacon_report_req_v1 report = 3; 162 | // string representation of the gateways u64 hex location 163 | string location = 4; 164 | /// the transmit gain value of the gateway in dbi x 10 165 | /// For example 1 dbi = 10, 15 dbi = 150 166 | /// derived from gateway metadata 167 | int32 gain = 5; 168 | /// The asserted elevation of the gateway in AGL ( above ground level) 169 | /// derived from gateway metadata 170 | int32 elevation = 6; 171 | // provides any additional context for invalid reason 172 | // for example the deny list version used as part of the deny list check 173 | invalid_details invalid_details = 7; 174 | } 175 | 176 | // tagged invalid witness report produced by the verifier 177 | message lora_invalid_witness_report_v1 { 178 | // Timestamp at ingest in millis since unix epoch 179 | uint64 received_timestamp = 1; 180 | invalid_reason reason = 2; 181 | lora_witness_report_req_v1 report = 3; 182 | // the participant to which the reason applies, 183 | // which rendered the report as invalid 184 | invalid_participant_side participant_side = 4; 185 | // provides any additional context for invalid reason 186 | // for example the deny list version used as part of the deny list check 187 | invalid_details invalid_details = 5; 188 | } 189 | 190 | // tagged verified witness report produced by the verifier 191 | message lora_verified_witness_report_v1 { 192 | // Timestamp at ingest in millis since unix epoch 193 | uint64 received_timestamp = 1; 194 | verification_status status = 2; 195 | lora_witness_report_req_v1 report = 3; 196 | // string representation of the gateways u64 hex location 197 | string location = 4; 198 | uint32 hex_scale = 5; 199 | // integer representation of a 4-point precision decimal multiplier 200 | // based on the number of witnesses to a poc event 201 | uint32 reward_unit = 6; 202 | invalid_reason invalid_reason = 7; 203 | // the participant to which the reason applies, 204 | // which rendered the report as invalid 205 | invalid_participant_side participant_side = 8; 206 | /// the transmit gain value of the gateway in dbi x 10 207 | /// For example 1 dbi = 10, 15 dbi = 150 208 | /// derived from gateway metadata 209 | int32 gain = 9; 210 | /// The asserted elevation of the gateway in AGL ( above ground level) 211 | /// derived from gateway metadata 212 | int32 elevation = 10; 213 | // provides any additional context for invalid reason 214 | // for example the deny list version used as part of the deny list check 215 | invalid_details invalid_details = 11; 216 | } 217 | 218 | // POC report produced by the verifier 219 | // includes a valid beacon and both valid & invalid witness reports 220 | message lora_poc_v1 { 221 | bytes poc_id = 1; 222 | lora_valid_beacon_report_v1 beacon_report = 2; 223 | repeated lora_verified_witness_report_v1 selected_witnesses = 3; 224 | repeated lora_verified_witness_report_v1 unselected_witnesses = 4; 225 | } 226 | 227 | message gateway_reward { 228 | /// Public key of the hotspot 229 | bytes hotspot_key = 1; 230 | /// Amount in iot bones credited to the hotspot for beaconing 231 | uint64 beacon_amount = 2; 232 | /// Amount in iot bones credited to the hotspot for witnessing 233 | uint64 witness_amount = 3; 234 | /// Amount in iot bones credited to the hotspot for data transfer 235 | uint64 dc_transfer_amount = 4; 236 | } 237 | 238 | message operational_reward { 239 | /// Amount in iot bones credited to the operational fund wallet 240 | uint64 amount = 1; 241 | } 242 | 243 | enum unallocated_reward_type { 244 | unallocated_reward_type_poc = 0; 245 | unallocated_reward_type_operation = 1; 246 | unallocated_reward_type_oracle = 2; 247 | unallocated_reward_type_data = 3; 248 | } 249 | 250 | message unallocated_reward { 251 | // the reward type representing a reward category to which an unallocated 252 | // amount exists 253 | unallocated_reward_type reward_type = 1; 254 | /// Amount in iot bones credited to unallocated 255 | uint64 amount = 2; 256 | } 257 | 258 | message iot_reward_share { 259 | /// Unix timestamp in seconds of the start of the reward period 260 | uint64 start_period = 1; 261 | /// Unix timestamp in seconds of the end of the reward period 262 | uint64 end_period = 2; 263 | /// the reward allocations for this share 264 | oneof reward { 265 | gateway_reward gateway_reward = 3; 266 | operational_reward operational_reward = 4; 267 | unallocated_reward unallocated_reward = 5; 268 | } 269 | } 270 | 271 | message lora_stream_session_offer_v1 { bytes nonce = 1; } 272 | 273 | message lora_stream_session_init_v1 { 274 | bytes pub_key = 1; 275 | bytes nonce = 2; 276 | bytes session_key = 3; 277 | bytes signature = 4; 278 | } 279 | 280 | message lora_stream_request_v1 { 281 | oneof request { 282 | lora_beacon_report_req_v1 beacon_report = 1; 283 | lora_witness_report_req_v1 witness_report = 2; 284 | lora_stream_session_init_v1 session_init = 3; 285 | } 286 | } 287 | 288 | message lora_stream_response_v1 { 289 | oneof response { lora_stream_session_offer_v1 offer = 1; } 290 | } 291 | 292 | service poc_lora { 293 | rpc submit_lora_beacon(lora_beacon_report_req_v1) 294 | returns (lora_beacon_report_resp_v1); 295 | rpc submit_lora_witness(lora_witness_report_req_v1) 296 | returns (lora_witness_report_resp_v1); 297 | rpc stream_requests(stream lora_stream_request_v1) 298 | returns (stream lora_stream_response_v1); 299 | } 300 | -------------------------------------------------------------------------------- /src/service/router.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium; 4 | 5 | import "blockchain_state_channel_v1.proto"; 6 | 7 | service router { 8 | rpc route(blockchain_state_channel_message_v1) 9 | returns (blockchain_state_channel_message_v1); 10 | } -------------------------------------------------------------------------------- /src/service/state_channel.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium; 4 | 5 | import "blockchain_state_channel_v1.proto"; 6 | 7 | service state_channel { 8 | rpc msg(stream blockchain_state_channel_message_v1) 9 | returns (stream blockchain_state_channel_message_v1); 10 | } -------------------------------------------------------------------------------- /src/service/sub_dao.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium.sub_dao; 4 | 5 | message sub_dao_epoch_reward_info { 6 | // The epoch of the reward info 7 | uint64 epoch = 1; 8 | // The on-chain identity of the epoch 9 | string epoch_address = 2; 10 | // The on-chain identity of the subdao 11 | string sub_dao_address = 3; 12 | // The total HNT rewards emitted for the sub dao and epoch minus the 13 | // delegation rewards 14 | uint64 hnt_rewards_issued = 4; 15 | // The total HNT delegation rewards emitted for the sub dao and epoch 16 | uint64 delegation_rewards_issued = 5; 17 | // timestamp in seconds when the rewards were issued 18 | uint64 rewards_issued_at = 6; 19 | } 20 | 21 | message sub_dao_epoch_reward_info_req_v1 { 22 | // The on-chain identity of the subdao to lookup 23 | string sub_dao_address = 1; 24 | // The epoch for the specified subdao to look up 25 | uint64 epoch = 2; 26 | // pubkey binary of the signing keypair 27 | bytes signer = 3; 28 | bytes signature = 4; 29 | } 30 | 31 | message sub_dao_epoch_reward_info_res_v1 { 32 | // The reward info for the specified subdao & epoch 33 | sub_dao_epoch_reward_info info = 1; 34 | // unix epoch timestamp in seconds 35 | uint64 timestamp = 2; 36 | // pubkey binary of the signing keypair 37 | bytes signer = 3; 38 | bytes signature = 4; 39 | } 40 | 41 | service sub_dao { 42 | // Get reward info for the specified subdao & epoch 43 | rpc info(sub_dao_epoch_reward_info_req_v1) 44 | returns (sub_dao_epoch_reward_info_res_v1); 45 | } 46 | -------------------------------------------------------------------------------- /src/service/transaction.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium.transaction; 4 | 5 | import "blockchain_routing_address.proto"; 6 | import "blockchain_txn.proto"; 7 | 8 | enum txn_status { 9 | pending = 0; 10 | not_found = 1; 11 | } 12 | 13 | message acceptor { 14 | uint64 height = 1; 15 | uint32 queue_pos = 2; 16 | uint32 queue_len = 3; 17 | bytes pub_key = 4; 18 | } 19 | 20 | message rejector { 21 | uint64 height = 1; 22 | bytes reason = 2; 23 | bytes pub_key = 3; 24 | } 25 | 26 | message txn_submit_req_v1 { 27 | blockchain_txn txn = 1; 28 | bytes key = 2; 29 | } 30 | 31 | message txn_submit_resp_v1 { 32 | bytes key = 1; 33 | uint64 recv_height = 2; 34 | routing_address validator = 3; 35 | bytes signature = 4; 36 | } 37 | 38 | message txn_query_req_v1 { bytes key = 1; } 39 | 40 | message txn_query_resp_v1 { 41 | txn_status status = 1; 42 | bytes key = 2; 43 | repeated acceptor acceptors = 3; 44 | repeated rejector rejectors = 4; 45 | uint64 recv_height = 5; 46 | uint64 height = 6; 47 | bytes signature = 7; 48 | } 49 | 50 | service transaction { 51 | rpc submit(txn_submit_req_v1) returns (txn_submit_resp_v1); 52 | rpc query(txn_query_req_v1) returns (txn_query_resp_v1); 53 | } 54 | -------------------------------------------------------------------------------- /src/service_provider.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helium; 4 | 5 | enum service_provider { 6 | helium_mobile = 0; 7 | } 8 | -------------------------------------------------------------------------------- /test/assert_location_v2.spec.js: -------------------------------------------------------------------------------- 1 | const proto = require('../build') 2 | 3 | const bob = Buffer.from( 4 | 'ATEzTThkVWJ4eW1FM3h0aUFYc3pSa0dNbWV6TWhCUzhMaTd3RXNNb2pMZGI0U2R4YzR3Yw==', 5 | 'base64', 6 | ) 7 | const alice = Buffer.from( 8 | 'ATE0OGQ4S1RSY0tBNUpLUGVrQmNLRmQ0S2Z2cHJ2RlJwakd0aXZodG1SbW5aOE1GWW5QMw==', 9 | 'base64', 10 | ) 11 | 12 | const makeAssert = () => { 13 | const AssertTxn = proto.helium.blockchain_txn_assert_location_v2 14 | 15 | return AssertTxn.create({ 16 | gateway: bob, 17 | owner: alice, 18 | payer: bob, 19 | ownerSignature: 'some signature', 20 | payerSignature: 'some other signature', 21 | location: 'location', 22 | nonce: 1, 23 | gain: 2, 24 | elevation: 3, 25 | fee: 4, 26 | stakingFee: 5, 27 | }) 28 | } 29 | 30 | describe('assert_location_v2', () => { 31 | it('can be constructed', () => { 32 | const assert = makeAssert() 33 | 34 | expect(assert.gateway).toBe(bob) 35 | expect(assert.owner).toBe(alice) 36 | expect(assert.payer).toBe(bob) 37 | expect(assert.ownerSignature).toBe('some signature') 38 | expect(assert.payerSignature).toBe('some other signature') 39 | expect(assert.location).toBe('location') 40 | expect(assert.nonce).toBe(1) 41 | expect(assert.gain).toBe(2) 42 | expect(assert.elevation).toBe(3) 43 | expect(assert.fee).toBe(4) 44 | expect(assert.stakingFee).toBe(5) 45 | }) 46 | 47 | it('can be serialized', () => { 48 | const BlockchainTxn = proto.helium.blockchain_txn 49 | 50 | const assert = makeAssert() 51 | 52 | const txn = BlockchainTxn.create({ assertLocationV2: assert }) 53 | const serializedTxn = BlockchainTxn.encode(txn).finish() 54 | 55 | expect(serializedTxn.toString('base64')).toBe( 56 | 'mgLQAQo0ATEzTThkVWJ4eW1FM3h0aUFYc3pSa0dNbWV6TWhCUzhMaTd3RXNNb2pMZGI0U2R4YzR3YxI0ATE0OGQ4S1RSY0tBNUpLUGVrQmNLRmQ0S2Z2cHJ2RlJwakd0aXZodG1SbW5aOE1GWW5QMxo0ATEzTThkVWJ4eW1FM3h0aUFYc3pSa0dNbWV6TWhCUzhMaTd3RXNNb2pMZGI0U2R4YzR3YyIJsomesignaturKg2yiZ6i2F6uyKCdq26tMghsb2NhdGlvbjgBQAJIA1AFWAQ=', 57 | ) 58 | }) 59 | }) 60 | -------------------------------------------------------------------------------- /test/payment_v1.spec.js: -------------------------------------------------------------------------------- 1 | const proto = require('../build') 2 | 3 | const bob = Buffer.from( 4 | 'ATEzTThkVWJ4eW1FM3h0aUFYc3pSa0dNbWV6TWhCUzhMaTd3RXNNb2pMZGI0U2R4YzR3Yw==', 5 | 'base64', 6 | ) 7 | const alice = Buffer.from( 8 | 'ATE0OGQ4S1RSY0tBNUpLUGVrQmNLRmQ0S2Z2cHJ2RlJwakd0aXZodG1SbW5aOE1GWW5QMw==', 9 | 'base64', 10 | ) 11 | 12 | describe('payment_v1', () => { 13 | it('can be constructed', () => { 14 | const Payment = proto.helium.blockchain_txn_payment_v1 15 | const payment = Payment.create({ 16 | payer: bob, 17 | payee: alice, 18 | amount: 10, 19 | fee: 1, 20 | nonce: 2, 21 | signature: 'some signature', 22 | }) 23 | expect(payment.payer).toBe(bob) 24 | expect(payment.payee).toBe(alice) 25 | expect(payment.amount).toBe(10) 26 | expect(payment.fee).toBe(1) 27 | expect(payment.nonce).toBe(2) 28 | expect(payment.signature).toBe('some signature') 29 | }) 30 | 31 | it('can be serialized', () => { 32 | const Txn = proto.helium.blockchain_txn 33 | const Payment = proto.helium.blockchain_txn_payment_v1 34 | const payment = Payment.create({ 35 | payer: bob, 36 | payee: alice, 37 | amount: 10, 38 | fee: 1, 39 | nonce: 2, 40 | signature: 'some signature', 41 | }) 42 | const txn = Txn.create({ payment }) 43 | const serializedTxn = Txn.encode(txn).finish() 44 | expect(serializedTxn.toString('base64')).toBe( 45 | 'Qn0KNAExM004ZFVieHltRTN4dGlBWHN6UmtHTW1lek1oQlM4TGk3d0VzTW9qTGRiNFNkeGM0d2MSNAExNDhkOEtUUmNLQTVKS1Bla0JjS0ZkNEtmdnBydkZScGpHdGl2aHRtUm1uWjhNRlluUDMYCiABKAIyCbKJnrIoJ2rbqw==', 46 | ) 47 | }) 48 | }) 49 | -------------------------------------------------------------------------------- /test/payment_v2.spec.js: -------------------------------------------------------------------------------- 1 | const proto = require('../build') 2 | 3 | const bob = Buffer.from( 4 | 'ATEzTThkVWJ4eW1FM3h0aUFYc3pSa0dNbWV6TWhCUzhMaTd3RXNNb2pMZGI0U2R4YzR3Yw==', 5 | 'base64', 6 | ) 7 | const alice = Buffer.from( 8 | 'ATE0OGQ4S1RSY0tBNUpLUGVrQmNLRmQ0S2Z2cHJ2RlJwakd0aXZodG1SbW5aOE1GWW5QMw==', 9 | 'base64', 10 | ) 11 | 12 | describe('payment_v2', () => { 13 | it('can be constructed', () => { 14 | const PaymentTxn = proto.helium.blockchain_txn_payment_v2 15 | const Payment = proto.helium.payment 16 | 17 | const payments = [Payment.create({ 18 | payee: alice, 19 | amount: 10, 20 | memo: 500, 21 | max: false 22 | })] 23 | 24 | const payment = PaymentTxn.create({ 25 | payer: bob, 26 | payments, 27 | fee: 1, 28 | nonce: 2, 29 | signature: 'some signature', 30 | }) 31 | 32 | expect(payment.payer).toBe(bob) 33 | expect(payment.payments[0].payee).toBe(alice) 34 | expect(payment.payments[0].amount).toBe(10) 35 | expect(payment.payments[0].memo).toBe(500) 36 | expect(payment.payments[0].max).toBe(false) 37 | expect(payment.fee).toBe(1) 38 | expect(payment.nonce).toBe(2) 39 | expect(payment.signature).toBe('some signature') 40 | }) 41 | 42 | it('can be serialized', () => { 43 | const BlockchainTxn = proto.helium.blockchain_txn 44 | 45 | const PaymentTxn = proto.helium.blockchain_txn_payment_v2 46 | const Payment = proto.helium.payment 47 | 48 | const payments = [Payment.create({ 49 | payee: alice, 50 | amount: 10, 51 | max: false, 52 | })] 53 | 54 | const paymentV2 = PaymentTxn.create({ 55 | payer: bob, 56 | payments, 57 | fee: 1, 58 | nonce: 2, 59 | signature: 'some signature', 60 | }) 61 | 62 | const txn = BlockchainTxn.create({ paymentV2 }) 63 | const serializedTxn = BlockchainTxn.encode(txn).finish() 64 | 65 | expect(serializedTxn.toString('base64')).toBe( 66 | 'wgGBAQo0ATEzTThkVWJ4eW1FM3h0aUFYc3pSa0dNbWV6TWhCUzhMaTd3RXNNb2pMZGI0U2R4YzR3YxI6CjQBMTQ4ZDhLVFJjS0E1SktQZWtCY0tGZDRLZnZwcnZGUnBqR3Rpdmh0bVJtblo4TUZZblAzEAogABgBIAIqCbKJnrIoJ2rbqw==', 67 | ) 68 | }) 69 | }) 70 | -------------------------------------------------------------------------------- /test/service/downlink.spec.js: -------------------------------------------------------------------------------- 1 | const proto = require('../../build') 2 | 3 | const Downlink = proto.helium.downlink 4 | const Region = proto.helium.region 5 | 6 | describe('http_roaming_register_v1', () => { 7 | it('can be constructed', () => { 8 | const now = new Date().getTime() 9 | const txn = Downlink.http_roaming_register_v1.create({ 10 | region: Region.US915, 11 | timestamp: now, 12 | signature: 'some signature', 13 | }) 14 | 15 | expect(txn.region).toBe(Region.US915) 16 | expect(txn.timestamp).toBe(now) 17 | expect(txn.signature).toBe('some signature') 18 | }) 19 | 20 | it('can be serialized', () => { 21 | const txn = Downlink.http_roaming_register_v1.create({ 22 | region: Region.US915, 23 | timestamp: 123456789, 24 | signature: 'some signature', 25 | }) 26 | 27 | const serializedTxn = Downlink.http_roaming_register_v1.encode(txn).finish() 28 | 29 | expect(serializedTxn.toString('base64')).toBe('CAAQlZrvOhoJsomesignatur') 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /test/service/poc_mobile.spec.js: -------------------------------------------------------------------------------- 1 | const proto = require('../../build') 2 | 3 | const PocMobile = proto.helium.poc_mobile 4 | 5 | describe('seniority_update', () => { 6 | it('can be constructed', () => { 7 | const now = new Date().getTime() 8 | const txn = PocMobile.seniority_update.create({ 9 | cbsdId: 'some_id', 10 | newSeniorityTimestamp: now, 11 | reason: 12 | PocMobile.seniority_update_reason 13 | .seniority_update_reason_heartbeat_not_seen, 14 | }) 15 | expect(txn.cbsdId).toBe('some_id') 16 | expect(txn.newSeniorityTimestamp).toBe(now) 17 | expect(txn.reason).toBe( 18 | PocMobile.seniority_update_reason 19 | .seniority_update_reason_heartbeat_not_seen, 20 | ) 21 | }) 22 | 23 | it('can be serialized', () => { 24 | const txn = PocMobile.seniority_update.create({ 25 | cbsdId: 'some_id', 26 | newSeniorityTimestamp: 123456789, 27 | reason: 28 | PocMobile.seniority_update_reason 29 | .seniority_update_reason_heartbeat_not_seen, 30 | }) 31 | const serializedTxn = PocMobile.seniority_update.encode(txn).finish() 32 | expect(serializedTxn.toString('base64')).toBe('Cgdzb21lX2lkGJWa7zogAA==') 33 | }) 34 | }) 35 | -------------------------------------------------------------------------------- /test/token_redeem_v1.spec.js: -------------------------------------------------------------------------------- 1 | const proto = require('../build') 2 | 3 | const bob = Buffer.from( 4 | 'ATEzTThkVWJ4eW1FM3h0aUFYc3pSa0dNbWV6TWhCUzhMaTd3RXNNb2pMZGI0U2R4YzR3Yw==', 5 | 'base64', 6 | ) 7 | 8 | const tokenType = proto.helium.blockchain_token_type_v1 9 | 10 | describe('payment_v2', () => { 11 | it('can be constructed', () => { 12 | const RedeemTxn = proto.helium.blockchain_txn_token_redeem_v1 13 | 14 | const txn = RedeemTxn.create({ 15 | tokenType: tokenType.mobile, 16 | account: bob, 17 | amount: 100, 18 | signature: 'some signature', 19 | nonce: 2, 20 | fee: 1, 21 | }) 22 | 23 | expect(txn.tokenType).toBe(tokenType.mobile) 24 | expect(txn.account).toBe(bob) 25 | expect(txn.amount).toBe(100) 26 | expect(txn.signature).toBe('some signature') 27 | expect(txn.nonce).toBe(2) 28 | expect(txn.fee).toBe(1) 29 | }) 30 | 31 | it('can be serialized', () => { 32 | const RedeemTxn = proto.helium.blockchain_txn_token_redeem_v1 33 | const BlockchainTxn = proto.helium.blockchain_txn 34 | 35 | const tokenRedeem = RedeemTxn.create({ 36 | tokenType: tokenType.mobile, 37 | account: bob, 38 | amount: 100, 39 | signature: 'some signature', 40 | nonce: 2, 41 | fee: 1, 42 | }) 43 | 44 | const txn = BlockchainTxn.create({ tokenRedeem }) 45 | const serializedTxn = BlockchainTxn.encode(txn).finish() 46 | 47 | expect(serializedTxn.toString('base64')).toBe( 48 | 'ygJJCAISNAExM004ZFVieHltRTN4dGlBWHN6UmtHTW1lek1oQlM4TGk3d0VzTW9qTGRiNFNkeGM0d2MYZCIJsomesignaturKAIwAQ==', 49 | ) 50 | }) 51 | }) 52 | -------------------------------------------------------------------------------- /test/transfer_hotspot_v2.spec.js: -------------------------------------------------------------------------------- 1 | const proto = require('../build') 2 | 3 | describe('transfer_hotspot_v2', () => { 4 | it('can be constructed', () => { 5 | const Txn = proto.helium.blockchain_txn_transfer_hotspot_v2 6 | 7 | const txn = Txn.create({ 8 | gateway: 'some gateway', 9 | owner: 'some owner', 10 | ownerSignature: 'some owner signature', 11 | newOwner: 'some new owner', 12 | fee: 10, 13 | nonce: 1, 14 | }) 15 | 16 | expect(txn.gateway).toBe('some gateway') 17 | expect(txn.owner).toBe('some owner') 18 | expect(txn.ownerSignature).toBe('some owner signature') 19 | expect(txn.newOwner).toBe('some new owner') 20 | expect(txn.fee).toBe(10) 21 | expect(txn.nonce).toBe(1) 22 | }) 23 | 24 | it('can be serialized', () => { 25 | const BlockchainTxn = proto.helium.blockchain_txn 26 | 27 | const Txn = proto.helium.blockchain_txn_transfer_hotspot_v2 28 | 29 | const transferHotspotV2 = Txn.create({ 30 | gateway: 'some gateway', 31 | owner: 'some owner', 32 | ownerSignature: 'some owner signature', 33 | newOwner: 'some new owner', 34 | fee: 10, 35 | nonce: 1, 36 | }) 37 | 38 | const txn = BlockchainTxn.create({ transferHotspotV2 }) 39 | const serializedTxn = BlockchainTxn.encode(txn).finish() 40 | 41 | expect(serializedTxn.toString('base64')).toBe( 42 | 'ogIwCgiyiZ6Bq17BrBIGsomeowneGg2yiZ6jCd6uyKCdq26tIgmyiZ6d7CjCd6soCjAB', 43 | ) 44 | }) 45 | }) 46 | --------------------------------------------------------------------------------