Skip to content

Commit 28fe042

Browse files
authored
Merge pull request #293 from semiotic-ai/suchapalaver/refactor-tap-receipt-unique-hash
refactor(eip712): simplify message unique id
2 parents 2f06fc7 + 57a01d9 commit 28fe042

File tree

8 files changed

+38
-67
lines changed

8 files changed

+38
-67
lines changed

tap_aggregator/src/aggregator/v1.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub fn check_and_aggregate_receipts(
1919
wallet: &PrivateKeySigner,
2020
accepted_addresses: &HashSet<Address>,
2121
) -> Result<Eip712SignedMessage<ReceiptAggregateVoucher>> {
22-
check_signatures_unique(domain_separator, receipts)?;
22+
check_signatures_unique(receipts)?;
2323

2424
// Check that the receipts are signed by an accepted signer address
2525
receipts.par_iter().try_for_each(|receipt| {
@@ -93,17 +93,14 @@ fn check_allocation_id(
9393
Ok(())
9494
}
9595

96-
fn check_signatures_unique(
97-
domain_separator: &Eip712Domain,
98-
receipts: &[Eip712SignedMessage<Receipt>],
99-
) -> Result<()> {
96+
fn check_signatures_unique(receipts: &[Eip712SignedMessage<Receipt>]) -> Result<()> {
10097
let mut receipt_signatures = HashSet::new();
10198
for receipt in receipts.iter() {
102-
let signature = receipt.unique_id(domain_separator)?;
99+
let signature = receipt.unique_id();
103100
if !receipt_signatures.insert(signature) {
104101
return Err(tap_core::Error::DuplicateReceiptSignature(format!(
105102
"{:?}",
106-
receipt.unique_id(domain_separator)?
103+
receipt.unique_id()
107104
))
108105
.into());
109106
}
@@ -221,7 +218,7 @@ mod tests {
221218

222219
// This should return an error because the signatures are different
223220
// but the messages are the same, which if allowed would present a security vulnerability
224-
let result = check_signatures_unique(&domain_separator, &receipts);
221+
let result = check_signatures_unique(&receipts);
225222

226223
// The result should be an error because the malleated signature is not treated as unique
227224
// and is detected as a duplicate
@@ -246,7 +243,7 @@ mod tests {
246243
receipts.push(receipt.clone());
247244
receipts.push(receipt);
248245

249-
let res = check_signatures_unique(&domain_separator, &receipts);
246+
let res = check_signatures_unique(&receipts);
250247
assert!(res.is_err());
251248
}
252249

@@ -273,7 +270,7 @@ mod tests {
273270
.unwrap(),
274271
];
275272

276-
let res = check_signatures_unique(&domain_separator, &receipts);
273+
let res = check_signatures_unique(&receipts);
277274
assert!(res.is_ok());
278275
}
279276

tap_aggregator/src/aggregator/v2.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub fn check_and_aggregate_receipts(
1919
wallet: &PrivateKeySigner,
2020
accepted_addresses: &HashSet<Address>,
2121
) -> Result<Eip712SignedMessage<ReceiptAggregateVoucher>> {
22-
check_signatures_unique(domain_separator, receipts)?;
22+
check_signatures_unique(receipts)?;
2323

2424
// Check that the receipts are signed by an accepted signer address
2525
receipts.par_iter().try_for_each(|receipt| {
@@ -148,17 +148,14 @@ fn check_allocation_id(
148148
Ok(())
149149
}
150150

151-
fn check_signatures_unique(
152-
domain_separator: &Eip712Domain,
153-
receipts: &[Eip712SignedMessage<Receipt>],
154-
) -> Result<()> {
151+
fn check_signatures_unique(receipts: &[Eip712SignedMessage<Receipt>]) -> Result<()> {
155152
let mut receipt_signatures = HashSet::new();
156153
for receipt in receipts.iter() {
157-
let signature = receipt.unique_id(domain_separator)?;
154+
let signature = receipt.unique_id();
158155
if !receipt_signatures.insert(signature) {
159156
return Err(tap_core::Error::DuplicateReceiptSignature(format!(
160157
"{:?}",
161-
receipt.unique_id(domain_separator)?
158+
receipt.unique_id()
162159
))
163160
.into());
164161
}
@@ -254,7 +251,7 @@ mod tests {
254251
receipts.push(receipt.clone());
255252
receipts.push(receipt);
256253

257-
let res = super::check_signatures_unique(&domain_separator, &receipts);
254+
let res = super::check_signatures_unique(&receipts);
258255
assert!(res.is_err());
259256
}
260257

@@ -284,7 +281,7 @@ mod tests {
284281
.unwrap(),
285282
];
286283

287-
let res = super::check_signatures_unique(&domain_separator, &receipts);
284+
let res = super::check_signatures_unique(&receipts);
288285
assert!(res.is_ok());
289286
}
290287

tap_core/src/manager/tap_manager.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,13 +138,12 @@ where
138138
let mut failed_receipts = vec![];
139139

140140
// check for timestamp
141-
let (checking_receipts, already_failed) = TimestampCheck(min_timestamp_ns)
142-
.check_batch(&self.domain_separator, checking_receipts)?;
141+
let (checking_receipts, already_failed) =
142+
TimestampCheck(min_timestamp_ns).check_batch(checking_receipts)?;
143143
failed_receipts.extend(already_failed);
144144

145145
// check for uniqueness
146-
let (checking_receipts, already_failed) =
147-
UniqueCheck.check_batch(&self.domain_separator, checking_receipts)?;
146+
let (checking_receipts, already_failed) = UniqueCheck.check_batch(checking_receipts)?;
148147
failed_receipts.extend(already_failed);
149148

150149
for receipt in checking_receipts.into_iter() {

tap_core/tests/manager_test.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ async fn manager_verify_and_store_varying_initial_checks(
139139
&signer,
140140
)
141141
.unwrap();
142-
let query_id = signed_receipt.unique_hash(&domain_separator).unwrap();
142+
let query_id = signed_receipt.unique_hash();
143143
query_appraisals.write().unwrap().insert(query_id, value);
144144
escrow_storage
145145
.write()
@@ -182,7 +182,7 @@ async fn manager_create_rav_request_all_valid_receipts(
182182
&signer,
183183
)
184184
.unwrap();
185-
let query_id = signed_receipt.unique_hash(&domain_separator).unwrap();
185+
let query_id = signed_receipt.unique_hash();
186186
stored_signed_receipts.push(signed_receipt.clone());
187187
query_appraisals.write().unwrap().insert(query_id, value);
188188
assert!(manager
@@ -277,7 +277,7 @@ async fn manager_create_multiple_rav_requests_all_valid_receipts(
277277
&signer,
278278
)
279279
.unwrap();
280-
let query_id = signed_receipt.unique_hash(&domain_separator).unwrap();
280+
let query_id = signed_receipt.unique_hash();
281281
stored_signed_receipts.push(signed_receipt.clone());
282282
query_appraisals.write().unwrap().insert(query_id, value);
283283
assert!(manager
@@ -321,7 +321,7 @@ async fn manager_create_multiple_rav_requests_all_valid_receipts(
321321
)
322322
.unwrap();
323323

324-
let query_id = signed_receipt.unique_hash(&domain_separator).unwrap();
324+
let query_id = signed_receipt.unique_hash();
325325
stored_signed_receipts.push(signed_receipt.clone());
326326
query_appraisals.write().unwrap().insert(query_id, value);
327327
assert!(manager
@@ -389,7 +389,7 @@ async fn manager_create_multiple_rav_requests_all_valid_receipts_consecutive_tim
389389
receipt.timestamp_ns = starting_min_timestamp + query_id + 1;
390390
let signed_receipt = Eip712SignedMessage::new(&domain_separator, receipt, &signer).unwrap();
391391

392-
let query_id = signed_receipt.unique_hash(&domain_separator).unwrap();
392+
let query_id = signed_receipt.unique_hash();
393393
stored_signed_receipts.push(signed_receipt.clone());
394394
query_appraisals.write().unwrap().insert(query_id, value);
395395
assert!(manager
@@ -436,7 +436,7 @@ async fn manager_create_multiple_rav_requests_all_valid_receipts_consecutive_tim
436436
let mut receipt = Receipt::new(allocation_ids[0], value).unwrap();
437437
receipt.timestamp_ns = starting_min_timestamp + query_id + 1;
438438
let signed_receipt = Eip712SignedMessage::new(&domain_separator, receipt, &signer).unwrap();
439-
let query_id = signed_receipt.unique_hash(&domain_separator).unwrap();
439+
let query_id = signed_receipt.unique_hash();
440440
stored_signed_receipts.push(signed_receipt.clone());
441441
query_appraisals.write().unwrap().insert(query_id, value);
442442
assert!(manager

tap_core/tests/received_receipt_test.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ async fn partial_then_full_check_valid_receipt(
113113
)
114114
.unwrap();
115115

116-
let query_id = signed_receipt.unique_hash(&domain_separator).unwrap();
116+
let query_id = signed_receipt.unique_hash();
117117

118118
// add escrow for sender
119119
escrow_storage
@@ -156,7 +156,7 @@ async fn partial_then_finalize_valid_receipt(
156156
&signer,
157157
)
158158
.unwrap();
159-
let query_id = signed_receipt.unique_hash(&domain_separator).unwrap();
159+
let query_id = signed_receipt.unique_hash();
160160

161161
// add escrow for sender
162162
escrow_storage
@@ -203,7 +203,7 @@ async fn standard_lifetime_valid_receipt(
203203
)
204204
.unwrap();
205205

206-
let query_id = signed_receipt.unique_hash(&domain_separator).unwrap();
206+
let query_id = signed_receipt.unique_hash();
207207

208208
// add escrow for sender
209209
escrow_storage

tap_eip712_message/src/lib.rs

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
use serde::{Deserialize, Serialize};
2626
use thegraph_core::alloy::{
2727
dyn_abi::Eip712Domain,
28-
primitives::{keccak256, Address, Signature},
28+
primitives::{Address, Signature},
2929
signers::{local::PrivateKeySigner, SignerSync},
3030
sol_types::SolStruct,
3131
};
@@ -105,21 +105,8 @@ impl<M: SolStruct> Eip712SignedMessage<M> {
105105
Ok(recovered_address)
106106
}
107107

108-
/// Generate a uniqueness identifier using both the message content and the recovered signer
109-
pub fn unique_hash(&self, domain_separator: &Eip712Domain) -> Result<MessageId, Eip712Error> {
110-
// Get the hash of just the message content
111-
let message_hash = self.message.eip712_hash_struct();
112-
113-
// Recover the signer address
114-
let signer = self.recover_signer(domain_separator)?;
115-
116-
// Create a new hash combining both the message hash and the signer address
117-
let mut input = Vec::with_capacity(32 + 20); // 32 bytes for hash, 20 bytes for address
118-
input.extend_from_slice(&message_hash.0);
119-
input.extend_from_slice(signer.as_ref());
120-
121-
let combined_hash = keccak256(&input);
122-
123-
Ok(MessageId(*combined_hash))
108+
/// Use this as a simple key for testing
109+
pub fn unique_hash(&self) -> MessageId {
110+
MessageId(self.message.eip712_hash_struct().into())
124111
}
125112
}

tap_receipt/src/checks.rs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ use std::{
3737
};
3838

3939
use tap_eip712_message::Eip712Error;
40-
use thegraph_core::alloy::dyn_abi::Eip712Domain;
4140

4241
use super::{
4342
state::{Checking, Failed},
@@ -97,7 +96,6 @@ type CheckBatchResponse<Rcpt> = (
9796
pub trait CheckBatch<Rcpt> {
9897
fn check_batch(
9998
&self,
100-
domain_separator: &Eip712Domain,
10199
receipts: Vec<ReceiptWithState<Checking, Rcpt>>,
102100
) -> Result<CheckBatchResponse<Rcpt>, Eip712Error>;
103101
}
@@ -157,7 +155,6 @@ where
157155
{
158156
fn check_batch(
159157
&self,
160-
_domain_separator: &Eip712Domain,
161158
receipts: Vec<ReceiptWithState<Checking, Rcpt>>,
162159
) -> Result<CheckBatchResponse<Rcpt>, Eip712Error> {
163160
let (mut checking, mut failed) = (vec![], vec![]);
@@ -189,14 +186,13 @@ where
189186
{
190187
fn check_batch(
191188
&self,
192-
domain_separator: &Eip712Domain,
193189
receipts: Vec<ReceiptWithState<Checking, Rcpt>>,
194190
) -> Result<CheckBatchResponse<Rcpt>, Eip712Error> {
195191
let mut signatures = HashSet::new();
196192
let (mut checking, mut failed) = (vec![], vec![]);
197193

198194
for received_receipt in receipts.into_iter() {
199-
let unique_id = received_receipt.receipt.unique_id(domain_separator)?;
195+
let unique_id = received_receipt.receipt.unique_id();
200196
if signatures.insert(unique_id) {
201197
checking.push(received_receipt);
202198
} else {
@@ -277,10 +273,7 @@ mod tests {
277273
let signed_receipt_2 = create_signed_receipt_with_custom_value(15);
278274
let signed_receipt_copy = signed_receipt.clone();
279275
let receipts_batch = vec![signed_receipt, signed_receipt_2, signed_receipt_copy];
280-
let domain_separator = create_test_domain_separator();
281-
let (valid_receipts, invalid_receipts) = UniqueCheck
282-
.check_batch(&domain_separator, receipts_batch)
283-
.unwrap();
276+
let (valid_receipts, invalid_receipts) = UniqueCheck.check_batch(receipts_batch).unwrap();
284277
assert_eq!(valid_receipts.len(), 2);
285278
assert_eq!(invalid_receipts.len(), 1);
286279
}
@@ -290,12 +283,10 @@ mod tests {
290283
let signed_receipt = create_signed_receipt_with_custom_value(10);
291284
let signed_receipt_2 = create_signed_receipt_with_custom_value(15);
292285

293-
let domain_separator = create_test_domain_separator();
294-
295286
let receipts_batch = vec![signed_receipt.clone(), signed_receipt_2];
296287
let min_time_stamp = signed_receipt.receipt.message.timestamp_ns + 1;
297288
let (valid_receipts, invalid_receipts) = TimestampCheck(min_time_stamp)
298-
.check_batch(&domain_separator, receipts_batch)
289+
.check_batch(receipts_batch)
299290
.unwrap();
300291
assert_eq!(valid_receipts.len(), 1);
301292
assert_eq!(invalid_receipts.len(), 1);

tap_receipt/src/lib.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ pub mod state;
2727

2828
pub use error::ReceiptError;
2929
pub use received_receipt::ReceiptWithState;
30-
use tap_eip712_message::{Eip712Error, Eip712SignedMessage, MessageId};
31-
use thegraph_core::alloy::{dyn_abi::Eip712Domain, sol_types::SolStruct};
30+
use tap_eip712_message::{Eip712SignedMessage, SignatureBytes, SignatureBytesExt};
31+
use thegraph_core::alloy::sol_types::SolStruct;
3232

3333
/// Result type for receipt
3434
pub type ReceiptResult<T> = Result<T, ReceiptError>;
@@ -45,7 +45,7 @@ pub trait WithValueAndTimestamp {
4545
/// Extension that allows UniqueCheck for any SolStruct receipt
4646
pub trait WithUniqueId {
4747
type Output: Eq + std::hash::Hash;
48-
fn unique_id(&self, domain_separator: &Eip712Domain) -> Result<Self::Output, Eip712Error>;
48+
fn unique_id(&self) -> Self::Output;
4949
}
5050

5151
impl<T> WithValueAndTimestamp for Eip712SignedMessage<T>
@@ -65,9 +65,9 @@ impl<T> WithUniqueId for Eip712SignedMessage<T>
6565
where
6666
T: SolStruct,
6767
{
68-
type Output = MessageId;
68+
type Output = SignatureBytes;
6969

70-
fn unique_id(&self, domain_separator: &Eip712Domain) -> Result<Self::Output, Eip712Error> {
71-
self.unique_hash(domain_separator)
70+
fn unique_id(&self) -> Self::Output {
71+
self.signature.normalized_s().get_signature_bytes()
7272
}
7373
}

0 commit comments

Comments
 (0)