Skip to content

Commit 8f103f6

Browse files
committed
eth: implement streaming handler for large transaction data
1 parent 40319eb commit 8f103f6

1 file changed

Lines changed: 69 additions & 4 deletions

File tree

src/eth.rs

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ use num_bigint::{BigInt, BigUint};
2020
//use num_traits::ToPrimitive;
2121
use serde_json::Value;
2222

23+
/// Threshold above which transaction data is streamed in chunks.
24+
/// Transactions with data larger than this use streaming mode.
25+
const STREAMING_THRESHOLD: usize = 6144;
26+
2327
impl<R: Runtime> PairedBitBox<R> {
2428
async fn query_proto_eth(
2529
&self,
@@ -478,6 +482,31 @@ impl<R: Runtime> PairedBitBox<R> {
478482
}
479483
}
480484

485+
/// Handles streaming of transaction data when in streaming mode.
486+
/// The device requests data chunks, and this method responds with the requested chunks.
487+
async fn handle_eth_data_streaming(
488+
&self,
489+
data: &[u8],
490+
mut response: pb::eth_response::Response,
491+
) -> Result<pb::eth_response::Response, Error> {
492+
while let pb::eth_response::Response::DataRequestChunk(chunk_req) = &response {
493+
let offset = chunk_req.offset as usize;
494+
let length = chunk_req.length as usize;
495+
496+
if offset + length > data.len() {
497+
return Err(Error::UnexpectedResponse);
498+
}
499+
500+
let chunk = data[offset..offset + length].to_vec();
501+
response = self
502+
.query_proto_eth(pb::eth_request::Request::DataResponseChunk(
503+
pb::EthSignDataResponseChunkRequest { chunk },
504+
))
505+
.await?;
506+
}
507+
Ok(response)
508+
}
509+
481510
/// Signs an Ethereum transaction. It returns a 65 byte signature (R, S, and 1 byte recID). The
482511
/// `tx` param can be constructed manually or parsed from a raw transaction using
483512
/// `raw_tx_slice.try_into()` (`rlp` feature required).
@@ -491,6 +520,11 @@ impl<R: Runtime> PairedBitBox<R> {
491520
// passing chainID instead of coin only since v9.10.0
492521
self.validate_version(">=9.10.0")?;
493522

523+
let use_streaming = tx.data.len() > STREAMING_THRESHOLD;
524+
if use_streaming {
525+
self.validate_version(">=9.26.0")?;
526+
}
527+
494528
let host_nonce = crate::antiklepto::gen_host_nonce()?;
495529
let request = pb::eth_request::Request::Sign(pb::EthSignRequest {
496530
coin: 0,
@@ -500,14 +534,27 @@ impl<R: Runtime> PairedBitBox<R> {
500534
gas_limit: crate::util::remove_leading_zeroes(&tx.gas_limit),
501535
recipient: tx.recipient.to_vec(),
502536
value: crate::util::remove_leading_zeroes(&tx.value),
503-
data: tx.data.clone(),
537+
data: if use_streaming {
538+
vec![]
539+
} else {
540+
tx.data.clone()
541+
},
504542
host_nonce_commitment: Some(pb::AntiKleptoHostNonceCommitment {
505543
commitment: crate::antiklepto::host_commit(&host_nonce).to_vec(),
506544
}),
507545
chain_id,
508546
address_case: address_case.unwrap_or(pb::EthAddressCase::Mixed).into(),
547+
data_length: if use_streaming {
548+
tx.data.len() as u32
549+
} else {
550+
0
551+
},
509552
});
510-
let response = self.query_proto_eth(request).await?;
553+
554+
let mut response = self.query_proto_eth(request).await?;
555+
if use_streaming {
556+
response = self.handle_eth_data_streaming(&tx.data, response).await?;
557+
}
511558
self.handle_antiklepto(&response, host_nonce).await
512559
}
513560

@@ -523,6 +570,11 @@ impl<R: Runtime> PairedBitBox<R> {
523570
// EIP1559 is suported from v9.16.0
524571
self.validate_version(">=9.16.0")?;
525572

573+
let use_streaming = tx.data.len() > STREAMING_THRESHOLD;
574+
if use_streaming {
575+
self.validate_version(">=9.26.0")?;
576+
}
577+
526578
let host_nonce = crate::antiklepto::gen_host_nonce()?;
527579
let request = pb::eth_request::Request::SignEip1559(pb::EthSignEip1559Request {
528580
chain_id: tx.chain_id,
@@ -535,13 +587,26 @@ impl<R: Runtime> PairedBitBox<R> {
535587
gas_limit: crate::util::remove_leading_zeroes(&tx.gas_limit),
536588
recipient: tx.recipient.to_vec(),
537589
value: crate::util::remove_leading_zeroes(&tx.value),
538-
data: tx.data.clone(),
590+
data: if use_streaming {
591+
vec![]
592+
} else {
593+
tx.data.clone()
594+
},
539595
host_nonce_commitment: Some(pb::AntiKleptoHostNonceCommitment {
540596
commitment: crate::antiklepto::host_commit(&host_nonce).to_vec(),
541597
}),
542598
address_case: address_case.unwrap_or(pb::EthAddressCase::Mixed).into(),
599+
data_length: if use_streaming {
600+
tx.data.len() as u32
601+
} else {
602+
0
603+
},
543604
});
544-
let response = self.query_proto_eth(request).await?;
605+
606+
let mut response = self.query_proto_eth(request).await?;
607+
if use_streaming {
608+
response = self.handle_eth_data_streaming(&tx.data, response).await?;
609+
}
545610
self.handle_antiklepto(&response, host_nonce).await
546611
}
547612

0 commit comments

Comments
 (0)