1#![deny(warnings)]
2#![deny(clippy::all)]
3extern crate serde;
4#[macro_use]
5extern crate serde_derive;
6extern crate bytes;
7extern crate hex;
8extern crate num_traits;
9extern crate rlp;
10extern crate secp256k1;
11extern crate tiny_keccak;
12
13#[cfg(test)]
14extern crate ethereum_types;
15#[cfg(test)]
16extern crate serde_json;
17
18use rlp::{Encodable, RlpStream};
19use secp256k1::{Message, Secp256k1, SecretKey};
20use serde::de::Error as SerdeErr;
21use serde::ser::SerializeSeq;
22use serde::Deserialize;
23use std::convert::TryInto;
24use tiny_keccak::{Hasher, Keccak};
25
26pub trait Transaction {
28 fn chain(&self) -> u64;
30
31 fn hash(&self) -> [u8; 32] {
33 let rlp = self.rlp_parts();
34 let mut rlp_stream = RlpStream::new();
35 rlp_stream.begin_unbounded_list();
36 for r in rlp.iter() {
37 rlp_stream.append(r);
38 }
39
40 if Self::transaction_type().is_none() {
42 rlp_stream.append(&self.chain());
43 rlp_stream.append_raw(&[0x80], 1);
44 rlp_stream.append_raw(&[0x80], 1);
45 }
46
47 rlp_stream.finalize_unbounded_list();
48 let mut rlp_bytes = rlp_stream.out().to_vec();
49
50 if let Some(tt) = Self::transaction_type() {
51 rlp_bytes.insert(0usize, tt);
52 }
53
54 keccak256_hash(&rlp_bytes)
55 }
56
57 fn ecdsa(&self, private_key: &[u8]) -> Result<EcdsaSig, Error> {
59 let hash = self.hash();
60
61 let chain = match Self::transaction_type() {
62 Some(_) => None,
63 None => Some(self.chain()),
64 };
65
66 EcdsaSig::generate(hash, private_key, chain)
67 }
68
69 fn sign(&self, ecdsa: &EcdsaSig) -> Vec<u8>;
87
88 fn rlp_parts(&self) -> Vec<Box<dyn Encodable>>;
92
93 fn transaction_type() -> Option<u8>;
96}
97
98#[derive(Debug)]
99pub enum Error {
100 Secp256k1(secp256k1::Error),
101}
102
103impl From<secp256k1::Error> for Error {
104 fn from(error: secp256k1::Error) -> Self {
105 Error::Secp256k1(error)
106 }
107}
108
109fn sign_bytes<T: Transaction>(tx_type: Option<u8>, ecdsa: &EcdsaSig, t: &T) -> Vec<u8> {
111 let mut rlp_stream = RlpStream::new();
112 let rlp = t.rlp_parts();
113 rlp_stream.begin_unbounded_list();
114 for r in rlp.iter() {
115 rlp_stream.append(r);
116 }
117 let EcdsaSig { v, s, r } = ecdsa;
118
119 let mut r_n = r.clone();
121 let mut s_n = s.clone();
122 while r_n[0] == 0 {
123 r_n.remove(0);
124 }
125 while s_n[0] == 0 {
126 s_n.remove(0);
127 }
128
129 rlp_stream.append(v);
130 rlp_stream.append(&r_n);
131 rlp_stream.append(&s_n);
132
133 rlp_stream.finalize_unbounded_list();
134
135 let mut vec = rlp_stream.out().to_vec();
136 if let Some(b) = tx_type {
137 vec.insert(0usize, b)
138 }
139 vec
140}
141
142#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)]
144pub struct LegacyTransaction {
145 pub chain: u64,
147 pub nonce: u128,
149 #[serde(serialize_with = "option_array_u8_serialize")]
151 #[serde(deserialize_with = "option_array_u8_deserialize")]
152 #[serde(default)]
153 pub to: Option<[u8; 20]>,
154 pub value: u128,
156 #[serde(rename = "gasPrice")]
158 pub gas_price: u128,
159 #[serde(alias = "gasLimit")]
161 pub gas: u128,
162 #[serde(serialize_with = "slice_u8_serialize")]
164 #[serde(deserialize_with = "slice_u8_deserialize")]
165 #[serde(default)]
166 pub data: Vec<u8>,
167}
168
169impl Transaction for LegacyTransaction {
170 fn chain(&self) -> u64 {
171 self.chain
172 }
173
174 fn rlp_parts(&self) -> Vec<Box<dyn Encodable>> {
175 let to: Vec<u8> = match self.to {
176 Some(ref to) => to.to_vec(),
177 None => vec![],
178 };
179 vec![
180 Box::new(self.nonce),
181 Box::new(self.gas_price),
182 Box::new(self.gas),
183 Box::new(to),
184 Box::new(self.value),
185 Box::new(self.data.clone()),
186 ]
187 }
188
189 fn sign(&self, ecdsa: &EcdsaSig) -> Vec<u8> {
190 sign_bytes(None, ecdsa, self)
191 }
192
193 fn transaction_type() -> Option<u8> {
194 None
195 }
196}
197
198#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq)]
199pub struct Access {
201 #[serde(serialize_with = "array_u8_20_serialize")]
202 #[serde(deserialize_with = "array_u8_20_deserialize")]
203 pub address: [u8; 20],
204 #[serde(serialize_with = "storage_keys_serialize")]
205 #[serde(deserialize_with = "storage_keys_deserialize")]
206 #[serde(rename = "storageKeys")]
207 pub storage_keys: Vec<[u8; 32]>,
208}
209
210#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq)]
211pub struct AccessList(pub Vec<Access>);
213
214impl Encodable for AccessList {
215 fn rlp_append(&self, rlp_stream: &mut RlpStream) {
217 rlp_stream.begin_unbounded_list();
218
219 for access in self.0.iter() {
220 let address_bytes: Vec<u8> = access.address.to_vec();
221
222 rlp_stream.begin_unbounded_list();
223 rlp_stream.append(&address_bytes);
224
225 {
227 rlp_stream.begin_unbounded_list();
228 for storage_key in access.storage_keys.iter() {
229 let storage_key_bytes: Vec<u8> = storage_key.to_vec();
230 rlp_stream.append(&storage_key_bytes);
231 }
232 rlp_stream.finalize_unbounded_list();
233 }
234
235 rlp_stream.finalize_unbounded_list();
236 }
237
238 rlp_stream.finalize_unbounded_list();
239 }
240}
241
242#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
243pub struct AccessListTransaction {
245 pub chain: u64,
247 pub nonce: u128,
249 #[serde(rename = "gasPrice")]
251 pub gas_price: u128,
252 #[serde(alias = "gasLimit")]
254 pub gas: u128,
255 #[serde(serialize_with = "option_array_u8_serialize")]
257 #[serde(deserialize_with = "option_array_u8_deserialize")]
258 #[serde(default)]
259 pub to: Option<[u8; 20]>,
260 pub value: u128,
262 #[serde(serialize_with = "slice_u8_serialize")]
264 #[serde(deserialize_with = "slice_u8_deserialize")]
265 #[serde(default)]
266 pub data: Vec<u8>,
267 #[serde(rename = "accessList")]
269 pub access_list: AccessList,
270}
271
272fn option_array_u8_serialize<S>(to: &Option<[u8; 20]>, s: S) -> Result<S::Ok, S::Error>
273where
274 S: serde::Serializer,
275{
276 match to {
277 Some(ref array) => slice_u8_serialize(array, s),
278 None => s.serialize_none(),
279 }
280}
281
282const HEX_PREFIX: &str = "0x";
285
286fn slice_u8_deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
287where
288 D: serde::Deserializer<'de>,
289{
290 let s: String = String::deserialize(deserializer)?;
291 let s = if s.starts_with(HEX_PREFIX) {
292 s.replace(HEX_PREFIX, "")
293 } else {
294 s
295 };
296 match hex::decode(&s) {
297 Ok(s) => Ok(s),
298 Err(err) => Err(derr::<D>(&s, err)),
299 }
300}
301
302fn storage_keys_deserialize<'de, D>(deserializer: D) -> Result<Vec<[u8; 32]>, D::Error>
303where
304 D: serde::Deserializer<'de>,
305{
306 let storage_key_vec: Vec<String> = Vec::deserialize(deserializer)?;
307 let mut storage_keys = vec![];
308 for storage_key in storage_key_vec.into_iter() {
309 let s = if storage_key.starts_with(HEX_PREFIX) {
310 storage_key.replace(HEX_PREFIX, "")
311 } else {
312 storage_key
313 };
314 let s = match hex::decode(&s) {
315 Ok(s) => s,
316 Err(err) => return Err(derr::<D>(&s, err)),
317 };
318 let s_len = s.len();
319 let arr = match s.try_into() {
320 Ok(a) => a,
321 Err(_) => {
322 return Err(D::Error::invalid_length(
323 s_len,
324 &"a hex string of length 20",
325 ))
326 }
327 };
328 storage_keys.push(arr) }
330 Ok(storage_keys)
331}
332
333fn storage_keys_serialize<S>(storage_keys: &[[u8; 32]], s: S) -> Result<S::Ok, S::Error>
334where
335 S: serde::Serializer,
336{
337 let mut seq = s.serialize_seq(Some(storage_keys.len()))?;
338 for storage_key in storage_keys.iter() {
339 seq.serialize_element(&hex::encode(storage_key))?;
340 }
341 seq.end()
342}
343
344fn array_u8_20_serialize<S>(storage_keys: &[u8; 20], s: S) -> Result<S::Ok, S::Error>
345where
346 S: serde::Serializer,
347{
348 s.serialize_str(&hex::encode(storage_keys))
349}
350
351fn array_u8_20_deserialize<'de, D>(d: D) -> Result<[u8; 20], D::Error>
352where
353 D: serde::Deserializer<'de>,
354{
355 match option_array_u8_deserialize(d)? {
356 Some(a) => Ok(a),
357 None => Err(
358 D::Error::invalid_value(serde::de::Unexpected::Option, &"a hex string of length 20"), ),
360 }
361}
362
363fn option_array_u8_deserialize<'de, D>(deserializer: D) -> Result<Option<[u8; 20]>, D::Error>
364where
365 D: serde::Deserializer<'de>,
366{
367 const TO_LEN: usize = 20;
368 let s_option: Option<String> = Option::deserialize(deserializer)?;
369 match s_option {
370 None => Ok(None),
371 Some(s) => {
372 let s = if s.starts_with(HEX_PREFIX) {
373 s.replace(HEX_PREFIX, "")
374 } else {
375 s
376 };
377 match hex::decode(&s) {
378 Ok(s) => {
379 let mut to = [0u8; 20];
380 if s.len() == TO_LEN {
381 for (i, b) in s.iter().enumerate() {
382 to[i] = *b;
383 }
384
385 Ok(Some(to))
386 } else {
387 Err(D::Error::invalid_length(
388 s.len(),
389 &"a hex string of length 20",
390 ))
391 }
392 }
393 Err(err) => Err(derr::<D>(&s, err)),
394 }
395 }
396 }
397}
398
399fn derr<'de, D: serde::Deserializer<'de>>(s: &str, err: hex::FromHexError) -> D::Error {
400 match err {
401 hex::FromHexError::InvalidHexCharacter { c, .. } => {
402 D::Error::invalid_value(serde::de::Unexpected::Char(c), &"a valid hex character")
403 }
404 hex::FromHexError::OddLength => {
405 D::Error::invalid_length(s.len(), &"a hex string of even length")
406 }
407 hex::FromHexError::InvalidStringLength => {
408 D::Error::invalid_length(s.len(), &"a hex string that matches container length")
409 }
410 }
411}
412
413fn slice_u8_serialize<S>(slice: &[u8], s: S) -> Result<S::Ok, S::Error>
414where
415 S: serde::Serializer,
416{
417 s.serialize_str(&hex::encode(slice))
418}
419
420const EIP_2930_TYPE: u8 = 0x01;
421
422impl Transaction for AccessListTransaction {
423 fn chain(&self) -> u64 {
424 self.chain
425 }
426
427 #[allow(warnings)]
428 fn rlp_parts(&self) -> Vec<Box<dyn Encodable>> {
429 let to: Vec<u8> = match self.to {
430 Some(ref to) => to.to_vec(),
431 None => vec![],
432 };
433 let mut parts: Vec<Box<dyn Encodable>> = vec![
434 Box::new(self.chain),
435 Box::new(self.nonce),
436 Box::new(self.gas_price),
437 Box::new(self.gas),
438 Box::new(to),
439 Box::new(self.value),
440 Box::new(self.data.clone()),
441 Box::new(self.access_list.clone()),
442 ];
443
444 parts
445 }
446
447 fn sign(&self, ecdsa: &EcdsaSig) -> Vec<u8> {
448 sign_bytes(Some(EIP_2930_TYPE), ecdsa, self)
449 }
450
451 fn transaction_type() -> Option<u8> {
452 Some(EIP_2930_TYPE)
453 }
454}
455
456const EIP_1559_TYPE: u8 = 0x02;
457
458#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
459pub struct FeeMarketTransaction {
461 pub chain: u64,
463 pub nonce: u128,
465 #[serde(rename = "maxPriorityFeePerGas")]
467 pub max_priority_fee_per_gas: u128,
468 #[serde(rename = "maxFeePerGas")]
469 pub max_fee_per_gas: u128,
470 #[serde(alias = "gasLimit")]
472 pub gas: u128,
473 #[serde(serialize_with = "option_array_u8_serialize")]
475 #[serde(deserialize_with = "option_array_u8_deserialize")]
476 #[serde(default)]
477 pub to: Option<[u8; 20]>,
478 pub value: u128,
480 #[serde(serialize_with = "slice_u8_serialize")]
482 #[serde(deserialize_with = "slice_u8_deserialize")]
483 #[serde(default)]
484 pub data: Vec<u8>,
485 #[serde(rename = "accessList")]
487 pub access_list: AccessList,
488}
489
490impl Transaction for FeeMarketTransaction {
491 fn chain(&self) -> u64 { self.chain }
492
493 fn sign(&self, ecdsa: &EcdsaSig) -> Vec<u8> {
494 sign_bytes(Some(EIP_1559_TYPE), ecdsa, self)
495 }
496
497 fn rlp_parts(&self) -> Vec<Box<dyn Encodable>> {
498 let to: Vec<u8> = match self.to {
499 Some(ref to) => to.to_vec(),
500 None => vec![],
501 };
502 vec![
503 Box::new(self.chain),
504 Box::new(self.nonce),
505 Box::new(self.max_priority_fee_per_gas),
506 Box::new(self.max_fee_per_gas),
507 Box::new(self.gas),
508 Box::new(to),
509 Box::new(self.value),
510 Box::new(self.data.clone()),
511 Box::new(self.access_list.clone()),
512 ]
513 }
514
515 fn transaction_type() -> Option<u8> {
516 Some(EIP_1559_TYPE)
517 }
518}
519
520#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
521pub struct EcdsaSig {
523 pub v: u64,
524 #[serde(serialize_with = "slice_u8_serialize")]
525 #[serde(deserialize_with = "slice_u8_deserialize")]
526 pub r: Vec<u8>,
527 #[serde(serialize_with = "slice_u8_serialize")]
528 #[serde(deserialize_with = "slice_u8_deserialize")]
529 pub s: Vec<u8>,
530}
531
532impl EcdsaSig {
533 fn generate(
534 hash: [u8; 32],
535 private_key: &[u8],
536 chain_id: Option<u64>,
537 ) -> Result<EcdsaSig, Error> {
538 let s = Secp256k1::signing_only();
539 let msg = Message::from_slice(&hash)?;
540 let key = SecretKey::from_slice(private_key)?;
541 let (v, sig_bytes) = s.sign_ecdsa_recoverable(&msg, &key).serialize_compact();
542
543 let v = v.to_i32() as u64
544 + match chain_id {
545 Some(c) => c * 2 + 35,
546 None => 0,
547 };
548
549 Ok(EcdsaSig {
550 v,
551 r: sig_bytes[0..32].to_vec(),
552 s: sig_bytes[32..64].to_vec(),
553 })
554 }
555}
556
557fn keccak256_hash(bytes: &[u8]) -> [u8; 32] {
558 let mut hasher = Keccak::v256();
559 hasher.update(bytes);
560 let mut resp: [u8; 32] = Default::default();
561 hasher.finalize(&mut resp);
562 resp
563}
564
565#[cfg(test)]
566mod test {
567 use crate::{AccessListTransaction, EcdsaSig, LegacyTransaction, Transaction, FeeMarketTransaction};
568
569 use serde_json;
570 use std::collections::HashMap;
571 use std::fmt::Debug;
572 use std::fs::File;
573 use std::io::Read;
574
575 #[test]
578 fn test_random_fee_market_transaction_001() {
579 run_signing_test::<FeeMarketTransaction>("./test/random_eip_1559_001.json");
580 }
581
582 #[test]
583 fn test_random_fee_market_transaction_001_ecdsa() {
584 run_ecdsa_test::<FeeMarketTransaction>("./test/random_eip_1559_001.json");
585 }
586
587 #[test]
588 fn test_random_fee_market_transaction_001_hash() {
589 run_hash_test::<FeeMarketTransaction>("./test/random_eip_1559_001.json");
590 }
591
592 #[test]
595 fn test_random_fee_market_transaction_002() {
596 run_signing_test::<FeeMarketTransaction>("./test/random_eip_1559_002.json");
597 }
598
599 #[test]
600 fn test_random_fee_market_transaction_002_ecdsa() {
601 run_ecdsa_test::<FeeMarketTransaction>("./test/random_eip_1559_002.json");
602 }
603
604 #[test]
605 fn test_random_fee_market_transaction_002_hash() {
606 run_hash_test::<FeeMarketTransaction>("./test/random_eip_1559_002.json");
607 }
608
609 #[test]
612 fn test_random_fee_market_transaction_003() {
613 run_signing_test::<FeeMarketTransaction>("./test/random_eip_1559_003.json");
614 }
615
616 #[test]
617 fn test_random_fee_market_transaction_003_ecdsa() {
618 run_ecdsa_test::<FeeMarketTransaction>("./test/random_eip_1559_003.json");
619 }
620
621 #[test]
622 fn test_random_fee_market_transaction_003_hash() {
623 run_hash_test::<FeeMarketTransaction>("./test/random_eip_1559_003.json");
624 }
625
626 #[test]
629 fn test_random_access_list_transaction_001() {
630 run_signing_test::<AccessListTransaction>("./test/random_eip_2930_001.json");
631 }
632
633 #[test]
634 fn test_random_access_list_transaction_001_ecdsa() {
635 run_ecdsa_test::<AccessListTransaction>("./test/random_eip_2930_001.json");
636 }
637
638 #[test]
639 fn test_random_access_list_transaction_001_hash() {
640 run_hash_test::<AccessListTransaction>("./test/random_eip_2930_001.json");
641 }
642
643 #[test]
646 fn test_random_access_list_transaction_002() {
647 run_signing_test::<AccessListTransaction>("./test/random_eip_2930_002.json");
648 }
649
650 #[test]
651 fn test_random_access_list_transaction_002_ecdsa() {
652 run_ecdsa_test::<AccessListTransaction>("./test/random_eip_2930_002.json");
653 }
654
655 #[test]
656 fn test_random_access_list_transaction_002_hash() {
657 run_hash_test::<AccessListTransaction>("./test/random_eip_2930_002.json");
658 }
659
660 #[test]
663 fn test_random_access_list_transaction_003() {
664 run_signing_test::<AccessListTransaction>("./test/random_eip_2930_003.json");
665 }
666
667 #[test]
668 fn test_random_access_list_transaction_003_ecdsa() {
669 run_ecdsa_test::<AccessListTransaction>("./test/random_eip_2930_003.json");
670 }
671
672 #[test]
673 fn test_random_access_list_transaction_003_hash() {
674 run_hash_test::<AccessListTransaction>("./test/random_eip_2930_003.json");
675 }
676
677 #[test]
680 fn test_random_legacy_001() {
681 run_signing_test::<LegacyTransaction>("./test/random_legacy_001.json");
682 }
683
684 #[test]
685 fn test_random_legacy_001_ecdsa() {
686 run_ecdsa_test::<LegacyTransaction>("./test/random_legacy_001.json");
687 }
688
689 #[test]
690 fn test_random_legacy_001_hash() {
691 run_hash_test::<LegacyTransaction>("./test/random_legacy_001.json");
692 }
693
694 #[test]
697 fn test_random_legacy_002() {
698 run_signing_test::<LegacyTransaction>("./test/random_legacy_002.json");
699 }
700
701 #[test]
702 fn test_random_legacy_002_ecdsa() {
703 run_ecdsa_test::<LegacyTransaction>("./test/random_legacy_002.json");
704 }
705
706 #[test]
707 fn test_random_legacy_002_hash() {
708 run_hash_test::<LegacyTransaction>("./test/random_legacy_002.json");
709 }
710
711 #[test]
714 fn test_random_legacy_003() {
715 run_signing_test::<LegacyTransaction>("./test/random_legacy_003.json");
716 }
717
718 #[test]
719 fn test_random_legacy_003_ecdsa() {
720 run_ecdsa_test::<LegacyTransaction>("./test/random_legacy_003.json");
721 }
722
723 #[test]
724 fn test_random_legacy_003_hash() {
725 run_hash_test::<LegacyTransaction>("./test/random_legacy_003.json");
726 }
727
728 #[test]
731 fn test_random_legacy_004() {
732 run_signing_test::<LegacyTransaction>("./test/random_legacy_004.json");
733 }
734
735 #[test]
736 fn test_random_legacy_004_ecdsa() {
737 run_ecdsa_test::<LegacyTransaction>("./test/random_legacy_004.json");
738 }
739
740 #[test]
741 fn test_random_legacy_004_hash() {
742 run_hash_test::<LegacyTransaction>("./test/random_legacy_004.json");
743 }
744
745 #[test]
748 fn test_random_legacy_005() {
749 run_signing_test::<LegacyTransaction>("./test/random_legacy_005.json");
750 }
751
752 #[test]
753 fn test_random_legacy_005_ecdsa() {
754 run_ecdsa_test::<LegacyTransaction>("./test/random_legacy_005.json");
755 }
756
757 #[test]
758 fn test_random_legacy_005_hash() {
759 run_hash_test::<LegacyTransaction>("./test/random_legacy_005.json");
760 }
761
762 #[test]
765 fn test_random_legacy_leading_zeroes_001_ecdsa() {
766 run_ecdsa_test::<LegacyTransaction>("./test/random_legacy_leading_zeroes_001.json");
767 }
768
769 #[test]
770 fn test_random_legacy_leading_zeroes_001_hash() {
771 run_hash_test::<LegacyTransaction>("./test/random_legacy_leading_zeroes_001.json");
772 }
773
774 #[test]
777 fn test_random_legacy_leading_zeroes_002_ecdsa() {
778 run_ecdsa_test::<LegacyTransaction>("./test/random_legacy_leading_zeroes_002.json");
779 }
780
781 #[test]
782 fn test_random_legacy_leading_zeroes_002_hash() {
783 run_hash_test::<LegacyTransaction>("./test/random_legacy_leading_zeroes_002.json");
784 }
785
786 #[test]
789 fn test_random_legacy_leading_zeroes_003_ecdsa() {
790 run_ecdsa_test::<LegacyTransaction>("./test/random_legacy_leading_zeroes_003.json");
791 }
792
793 #[test]
794 fn test_random_legacy_leading_zeroes_003_hash() {
795 run_hash_test::<LegacyTransaction>("./test/random_legacy_leading_zeroes_003.json");
796 }
797
798 #[test]
801 fn test_zero_legacy_001() {
802 run_signing_test::<LegacyTransaction>("./test/zero_legacy_001.json");
803 }
804
805 #[test]
806 fn test_zero_legacy_001_ecdsa() {
807 run_ecdsa_test::<LegacyTransaction>("./test/zero_legacy_001.json");
808 }
809
810 #[test]
811 fn test_zero_legacy_001_hash() {
812 run_hash_test::<LegacyTransaction>("./test/zero_legacy_001.json");
813 }
814
815 #[test]
818 fn test_zero_legacy_002() {
819 run_signing_test::<LegacyTransaction>("./test/zero_legacy_002.json");
820 }
821
822 #[test]
823 fn test_zero_legacy_002_ecdsa() {
824 run_ecdsa_test::<LegacyTransaction>("./test/zero_legacy_002.json");
825 }
826
827 #[test]
828 fn test_zero_legacy_002_hash() {
829 run_hash_test::<LegacyTransaction>("./test/zero_legacy_002.json");
830 }
831
832 #[test]
835 fn test_zero_legacy_003() {
836 run_signing_test::<LegacyTransaction>("./test/zero_legacy_003.json");
837 }
838
839 #[test]
840 fn test_zero_legacy_003_ecdsa() {
841 run_ecdsa_test::<LegacyTransaction>("./test/zero_legacy_003.json");
842 }
843
844 #[test]
845 fn test_zero_legacy_003_hash() {
846 run_hash_test::<LegacyTransaction>("./test/zero_legacy_003.json");
847 }
848
849 #[test]
852 fn test_zero_access_list_transaction_001() {
853 run_signing_test::<AccessListTransaction>("./test/zero_eip_2718_001.json");
854 }
855
856 #[test]
857 fn test_zero_access_list_transaction_001_ecdsa() {
858 run_ecdsa_test::<AccessListTransaction>("./test/zero_eip_2718_001.json");
859 }
860
861 #[test]
862 fn test_zero_access_list_transaction_001_hash() {
863 run_hash_test::<AccessListTransaction>("./test/zero_eip_2718_001.json");
864 }
865
866 #[test]
869 fn test_zero_access_list_transaction_002() {
870 run_signing_test::<AccessListTransaction>("./test/zero_eip_2718_002.json");
871 }
872
873 #[test]
874 fn test_zero_access_list_transaction_002_ecdsa() {
875 run_ecdsa_test::<AccessListTransaction>("./test/zero_eip_2718_002.json");
876 }
877
878 #[test]
879 fn test_zero_access_list_transaction_002_hash() {
880 run_hash_test::<AccessListTransaction>("./test/zero_eip_2718_002.json");
881 }
882
883 #[test]
886 fn test_zero_access_list_transaction_003() {
887 run_signing_test::<AccessListTransaction>("./test/zero_eip_2718_003.json");
888 }
889
890 #[test]
891 fn test_zero_access_list_transaction_003_ecdsa() {
892 run_ecdsa_test::<AccessListTransaction>("./test/zero_eip_2718_003.json");
893 }
894
895 #[test]
896 fn test_zero_access_list_transaction_003_hash() {
897 run_ecdsa_test::<AccessListTransaction>("./test/zero_eip_2718_003.json");
898 }
899
900 #[test]
903 fn test_zero_fee_market_transaction_001() {
904 run_signing_test::<FeeMarketTransaction>("./test/zero_eip_1559_001.json");
905 }
906
907 #[test]
908 fn test_zero_fee_market_transaction_001_ecdsa() {
909 run_ecdsa_test::<FeeMarketTransaction>("./test/zero_eip_1559_001.json");
910 }
911
912 #[test]
913 fn test_zero_fee_market_transaction_001_hash() {
914 run_ecdsa_test::<FeeMarketTransaction>("./test/zero_eip_1559_001.json");
915 }
916
917 #[test]
920 fn test_zero_fee_market_transaction_002() {
921 run_signing_test::<FeeMarketTransaction>("./test/zero_eip_1559_002.json");
922 }
923
924 #[test]
925 fn test_zero_fee_market_transaction_002_ecdsa() {
926 run_ecdsa_test::<FeeMarketTransaction>("./test/zero_eip_1559_002.json");
927 }
928
929 #[test]
930 fn test_zero_fee_market_transaction_002_hash() {
931 run_ecdsa_test::<FeeMarketTransaction>("./test/zero_eip_1559_002.json");
932 }
933
934 #[test]
937 fn test_zero_fee_market_transaction_003() {
938 run_signing_test::<FeeMarketTransaction>("./test/zero_eip_1559_003.json");
939 }
940
941 #[test]
942 fn test_zero_fee_market_transaction_003_ecdsa() {
943 run_ecdsa_test::<FeeMarketTransaction>("./test/zero_eip_1559_003.json");
944 }
945
946 #[test]
947 fn test_zero_fee_market_transaction_003_hash() {
948 run_ecdsa_test::<FeeMarketTransaction>("./test/zero_eip_1559_003.json");
949 }
950
951 #[test]
956 fn test_serde_random_access_list_transaction_001() {
957 run_serialization_deserialization_test::<AccessListTransaction>(
958 "./test/random_eip_2930_001.json",
959 );
960 }
961
962 #[test]
963 fn test_serde_random_access_list_transaction_002() {
964 run_serialization_deserialization_test::<AccessListTransaction>(
965 "./test/random_eip_2930_002.json",
966 );
967 }
968
969 #[test]
970 fn test_serde_random_access_list_transaction_003() {
971 run_serialization_deserialization_test::<AccessListTransaction>(
972 "./test/random_eip_2930_003.json",
973 );
974 }
975
976 #[test]
979 fn test_serde_random_fee_market_transaction_001() {
980 run_serialization_deserialization_test::<FeeMarketTransaction>(
981 "./test/random_eip_1559_001.json",
982 );
983 }
984
985 #[test]
986 fn test_serde_random_fee_market_transaction_002() {
987 run_serialization_deserialization_test::<FeeMarketTransaction>(
988 "./test/random_eip_1559_002.json",
989 );
990 }
991
992 #[test]
993 fn test_serde_random_fee_market_transaction_003() {
994 run_serialization_deserialization_test::<FeeMarketTransaction>(
995 "./test/random_eip_1559_003.json",
996 );
997 }
998
999 fn run_serialization_deserialization_test<
1000 T: Transaction
1001 + serde::de::DeserializeOwned
1002 + std::fmt::Debug
1003 + serde::Serialize
1004 + serde::de::DeserializeOwned
1005 + std::cmp::Eq,
1006 >(
1007 path: &str,
1008 ) {
1009 let mut file = File::open(path).unwrap_or_else(|_| panic!("Failed to open: {}", path));
1010 let mut f_string = String::new();
1011 file.read_to_string(&mut f_string).unwrap();
1012
1013 let values: HashMap<String, serde_json::Value> = serde_json::from_str(&f_string).unwrap();
1014 let transaction_original: T = serde_json::from_value(values["input"].clone()).unwrap();
1015 let transaction_string = serde_json::to_string(&transaction_original).unwrap();
1016
1017 assert_eq!(
1018 transaction_original,
1019 serde_json::from_str(&transaction_string).unwrap()
1020 )
1021 }
1022
1023 fn run_signing_test<T: Transaction + Debug + serde::de::DeserializeOwned>(path: &str) {
1026 let mut file = File::open(path).unwrap_or_else(|_| panic!("Failed to open: {}", path));
1027 let mut f_string = String::new();
1028 file.read_to_string(&mut f_string).unwrap();
1029
1030 let values: HashMap<String, serde_json::Value> = serde_json::from_str(&f_string).unwrap();
1031
1032 let transaction: T = serde_json::from_value(values["input"].clone()).unwrap();
1033 let ecdsa: EcdsaSig = serde_json::from_value(values["output"].clone()).unwrap();
1034 let expected_bytes_string: String =
1035 serde_json::from_value(values["output"]["bytes"].clone()).unwrap();
1036 let expected_bytes_string = expected_bytes_string.replace("0x", "");
1037
1038 let actual_bytes = transaction.sign(&ecdsa);
1039 let actual_bytes_string = hex::encode(&actual_bytes);
1040
1041 println!(
1042 "Expecting {} byte(s), got {} byte(s)",
1043 expected_bytes_string.len(),
1044 actual_bytes_string.len()
1045 );
1046
1047 assert_eq!(expected_bytes_string, actual_bytes_string);
1048 }
1049
1050 fn run_ecdsa_test<T: Transaction + serde::de::DeserializeOwned>(path: &str)
1051 where
1052 T: std::fmt::Debug,
1053 {
1054 let mut file = File::open(path).unwrap_or_else(|_| panic!("Failed to open: {}", path));
1055 let mut f_string = String::new();
1056 file.read_to_string(&mut f_string).unwrap();
1057
1058 let values: HashMap<String, serde_json::Value> = serde_json::from_str(&f_string).unwrap();
1059
1060 let transaction: T = serde_json::from_value(values["input"].clone()).unwrap();
1061 let private_key: String = match &values["privateKey"] {
1062 serde_json::Value::String(ref pk) => pk.clone(),
1063 _ => panic!("Unexpected type for private key (expected string)"),
1064 };
1065 let decoded_pk = hex::decode(private_key.replace("0x", "")).unwrap();
1066 let signed_ecdsa = transaction.ecdsa(&decoded_pk).unwrap();
1067 let expected_ecdsa: EcdsaSig = serde_json::from_value(values["output"].clone()).unwrap();
1068
1069 assert_eq!(expected_ecdsa, signed_ecdsa)
1070 }
1071
1072 fn run_hash_test<T: Transaction + serde::de::DeserializeOwned>(path: &str)
1073 where
1074 T: std::fmt::Debug,
1075 {
1076 let mut file = File::open(&path).unwrap_or_else(|_| panic!("Failed to open: {}", path));
1077 let mut f_string = String::new();
1078 file.read_to_string(&mut f_string).unwrap();
1079
1080 let values: HashMap<String, serde_json::Value> = serde_json::from_str(&f_string).unwrap();
1081
1082 let transaction: T = serde_json::from_value(values["input"].clone()).unwrap();
1083 let expected_hash = match &values["output"]["hash"] {
1084 serde_json::Value::String(ref h) => h.clone().replace("0x", ""),
1085 serde_json::Value::Null => panic!("Test is missing `hash`"),
1086 v => panic!("Unexpected type for hash (expected string, got {:?})", v),
1087 };
1088 let actual_hash = hex::encode(transaction.hash());
1089
1090 assert_eq!(expected_hash, actual_hash)
1091 }
1092}