Skip to content

Commit

Permalink
Attach hex_scale and reward_unit to poc receipt txns (#350)
Browse files Browse the repository at this point in the history
  • Loading branch information
vihu authored Feb 23, 2023
1 parent 1c2f4ab commit 865b109
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 9 deletions.
11 changes: 9 additions & 2 deletions iot_config/src/gateway_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use file_store::traits::MsgVerify;
use helium_crypto::{Keypair, PublicKey, Sign};
use helium_proto::{
services::iot_config::{
self, GatewayLoadRegionReqV1, GatewayLoadRegionResV1, GatewayRegionParamsReqV1,
GatewayRegionParamsResV1,
self, GatewayLoadRegionReqV1, GatewayLoadRegionResV1, GatewayLocationReqV1,
GatewayLocationResV1, GatewayRegionParamsReqV1, GatewayRegionParamsResV1,
},
Message, Region,
};
Expand Down Expand Up @@ -54,6 +54,13 @@ impl GatewayService {

#[tonic::async_trait]
impl iot_config::Gateway for GatewayService {
async fn location(
&self,
_request: Request<GatewayLocationReqV1>,
) -> GrpcResult<GatewayLocationResV1> {
unimplemented!()
}

async fn region_params(
&self,
request: Request<GatewayRegionParamsReqV1>,
Expand Down
147 changes: 140 additions & 7 deletions poc_iot_injector/src/receipt_txn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ pub fn handle_report_msg(

path.push(path_element);

let (bare_txn, hash, hash_b64_url) = construct_bare_txn(path, beacon_received_ts, &keypair)?;
let (bare_txn, hash, hash_b64_url) = construct_signed_txn(path, beacon_received_ts, &keypair)?;
Ok(TxnDetails {
txn: wrap_txn(bare_txn),
hash,
Expand Down Expand Up @@ -102,27 +102,61 @@ fn wrap_txn(txn: BlockchainTxnPocReceiptsV2) -> BlockchainTxn {
}
}

fn construct_bare_txn(
fn construct_signed_txn(
path: PocPath,
timestamp: i64,
keypair: &Keypair,
) -> Result<(BlockchainTxnPocReceiptsV2, Vec<u8>, String), TxnConstructionError> {
let strip_path = strip_path(path.clone());

let mut txn = BlockchainTxnPocReceiptsV2 {
challenger: keypair.public_key().to_vec(),
secret: vec![],
onion_key_hash: vec![],
path,
path: strip_path,
fee: 0,
signature: vec![],
block_hash: vec![],
timestamp: timestamp as u64,
};

txn.signature = sign_txn(&txn, keypair)?;

// Re-attach the original (unstripped) path back to the txn after signing
txn.path = path;

let (txn_hash, txn_hash_b64url) = hash_txn(&txn);
Ok((txn, txn_hash, txn_hash_b64url))
}

/// Before signing the txn we strip the path of hex_scale and reward_unit contained in the
/// individual receipt and witnesses
fn strip_path(path: PocPath) -> PocPath {
let mut strip_path: PocPath = Vec::with_capacity(1);
for element in path {
let challengee = element.challengee;
let mut new_element = BlockchainPocPathElementV1 {
challengee,
witnesses: vec![],
receipt: None,
};
let mut witnesses = vec![];
for mut witness in element.witnesses {
witness.reward_unit = 0;
witness.hex_scale = 0;
witnesses.push(witness)
}
new_element.witnesses = witnesses;
if let Some(mut receipt) = element.receipt {
receipt.hex_scale = 0;
receipt.reward_unit = 0;
new_element.receipt = Some(receipt)
}
strip_path.push(new_element)
}
strip_path
}

fn construct_path_element(
challengee: Vec<u8>,
poc_receipt: BlockchainPocReceiptV1,
Expand All @@ -141,8 +175,9 @@ fn construct_poc_witnesses(
let mut poc_witnesses: Vec<BlockchainPocWitnessV1> = Vec::with_capacity(witness_reports.len());
for witness_report in witness_reports {
let witness_invalid_reason = witness_report.invalid_reason as i32;
let reward_shares = ((witness_report.hex_scale * witness_report.reward_unit)
* *REWARD_SHARE_MULTIPLIER)
let hex_scale = witness_report.hex_scale;
let reward_unit = witness_report.reward_unit;
let reward_shares = ((hex_scale * reward_unit) * *REWARD_SHARE_MULTIPLIER)
.to_u32()
.unwrap_or_default();

Expand All @@ -169,6 +204,8 @@ fn construct_poc_witnesses(
datarate: witness_report.report.datarate.to_string(),
channel: witness_invalid_reason,
reward_shares,
reward_unit: reward_unit.to_u32().unwrap_or(0),
hex_scale: hex_scale.to_u32().unwrap_or(0),
};

poc_witnesses.push(poc_witness)
Expand All @@ -183,8 +220,9 @@ fn hz_to_mhz(freq_hz: u64) -> f32 {
}

fn construct_poc_receipt(beacon_report: IotValidBeaconReport) -> (BlockchainPocReceiptV1, i64) {
let reward_shares = ((beacon_report.hex_scale * beacon_report.reward_unit)
* *REWARD_SHARE_MULTIPLIER)
let hex_scale = beacon_report.hex_scale;
let reward_unit = beacon_report.reward_unit;
let reward_shares = ((hex_scale * reward_unit) * *REWARD_SHARE_MULTIPLIER)
.to_u32()
.unwrap_or_default();

Expand All @@ -206,6 +244,8 @@ fn construct_poc_receipt(beacon_report: IotValidBeaconReport) -> (BlockchainPocR
tx_power: beacon_report.report.tx_power,
addr_hash: vec![],
reward_shares,
reward_unit: reward_unit.to_u32().unwrap_or(0),
hex_scale: hex_scale.to_u32().unwrap_or(0),
};

(poc_receipt, beacon_received_ts)
Expand Down Expand Up @@ -233,8 +273,99 @@ fn sign_txn(
#[cfg(test)]
mod tests {
use super::*;
use helium_crypto::{KeyTag, KeyType, Keypair, Network, Verify};
use rust_decimal_macros::dec;

#[test]
fn txn_construction_test() {
const ENTROPY: [u8; 32] = [
248, 55, 78, 168, 99, 123, 22, 203, 36, 250, 136, 86, 110, 119, 198, 170, 248, 55, 78,
168, 99, 123, 22, 203, 36, 250, 136, 86, 110, 119, 198, 170,
];
let kt = KeyTag {
network: Network::MainNet,
key_type: KeyType::Ed25519,
};
let keypair = Keypair::generate_from_entropy(kt, &ENTROPY).expect("keypair");
let pubkey = keypair.public_key();

let poc_witness = BlockchainPocWitnessV1 {
gateway: vec![],
timestamp: 123,
signal: 0,
packet_hash: vec![],
signature: vec![],
snr: 0.0,
frequency: 0.0,
datarate: "dr".to_string(),
channel: 0,
reward_shares: 0,
reward_unit: 2,
hex_scale: 3,
};
let poc_receipt = BlockchainPocReceiptV1 {
gateway: vec![],
timestamp: 123,
signal: 0,
data: vec![],
origin: 0,
signature: vec![],
snr: 0.0,
frequency: 0.0,
channel: 0,
datarate: "dr".to_string(),
tx_power: -1,
addr_hash: vec![],
reward_shares: 0,
reward_unit: 1,
hex_scale: 4,
};
let poc_path_element = BlockchainPocPathElementV1 {
challengee: vec![],
receipt: Some(poc_receipt),
witnesses: vec![poc_witness],
};
let path = vec![poc_path_element];

// txn0 will be signed over the path with the reward_unit and hex_scale
let mut txn0 = BlockchainTxnPocReceiptsV2 {
challenger: keypair.public_key().to_vec(),
secret: vec![],
onion_key_hash: vec![],
path: path.clone(),
fee: 0,
signature: vec![],
block_hash: vec![],
timestamp: 456,
};
let signature0 = sign_txn(&txn0, &keypair).expect("unable to sign txn");
txn0.signature = signature0.clone();
let (_txn_hash, txn0_hash_b64_url) = hash_txn(&txn0);

// txn1 signature will be stripped of the reward_unit and hex_scale
let (txn1, _, txn1_hash_b64_url) = construct_signed_txn(path.clone(), 456, &keypair)
.expect("unable to construct signed txn");

// The txn hashes should be equal
assert_eq!(txn0_hash_b64_url, txn1_hash_b64_url);

let mut txn0 = txn0;
txn0.signature = vec![];
// This txn0 should be verifiable as is
assert!(pubkey.verify(&txn0.encode_to_vec(), &signature0).is_ok());

let signature1 = txn1.clone().signature;

// The two signatures should be different
assert_ne!(signature0, signature1);

let mut txn1 = txn1;
txn1.signature = vec![];
// For txn1, we strip the path before verifying
txn1.path = strip_path(path);
assert!(pubkey.verify(&txn1.encode_to_vec(), &signature1).is_ok());
}

#[test]
fn max_witnesses_per_receipt_test() {
let poc_witness = BlockchainPocWitnessV1 {
Expand All @@ -248,6 +379,8 @@ mod tests {
datarate: "dr".to_string(),
channel: 0,
reward_shares: 0,
reward_unit: 0,
hex_scale: 0,
};
let poc_id: Vec<u8> = vec![0];
let max_witnesses_per_receipt = 14;
Expand Down

0 comments on commit 865b109

Please sign in to comment.