@@ -72,7 +72,7 @@ impl ProviderData {
72
72
network_id : config. network_id ,
73
73
beneficiary : config. coinbase ,
74
74
// TODO: Add config option (https://github.com/NomicFoundation/edr/issues/111)
75
- min_gas_price : U256 :: MAX ,
75
+ min_gas_price : U256 :: from ( 1 ) ,
76
76
prevrandao_generator,
77
77
block_time_offset_seconds : block_time_offset_seconds ( config) ?,
78
78
next_block_timestamp : None ,
@@ -411,6 +411,51 @@ impl ProviderData {
411
411
self . impersonated_accounts . remove ( & address)
412
412
}
413
413
414
+ /// Get a transaction by hash from the blockchain or from the mempool if
415
+ /// it's not mined yet.
416
+ pub async fn transaction_by_hash (
417
+ & self ,
418
+ hash : & B256 ,
419
+ ) -> Result < Option < GetTransactionResult > , ProviderError > {
420
+ let transaction = if let Some ( tx) = self . mem_pool . transaction_by_hash ( hash) {
421
+ let signed_transaction = tx. pending ( ) . transaction ( ) . clone ( ) ;
422
+
423
+ Some ( GetTransactionResult {
424
+ signed_transaction,
425
+ spec_id : self . blockchain . spec_id ( ) ,
426
+ block_metadata : None ,
427
+ } )
428
+ } else if let Some ( tx_block) = self . blockchain . block_by_transaction_hash ( hash) . await ? {
429
+ let tx_index = self
430
+ . blockchain
431
+ . receipt_by_transaction_hash ( hash)
432
+ . await ?
433
+ . expect ( "If the transaction was inserted in a block, it must have a receipt" )
434
+ . transaction_index ;
435
+
436
+ let tx_index_usize =
437
+ usize:: try_from ( tx_index) . expect ( "Indices cannot be larger than usize::MAX" ) ;
438
+ let signed_transaction = tx_block. transactions ( ) [ tx_index_usize] . clone ( ) ;
439
+
440
+ let block_metadata = BlockMetadataForTransaction {
441
+ base_fee_per_gas : tx_block. header ( ) . base_fee_per_gas ,
442
+ block_hash : * tx_block. hash ( ) ,
443
+ block_number : tx_block. header ( ) . number ,
444
+ transaction_index : tx_index,
445
+ } ;
446
+
447
+ Some ( GetTransactionResult {
448
+ signed_transaction,
449
+ spec_id : self . blockchain . spec_id ( ) ,
450
+ block_metadata : Some ( block_metadata) ,
451
+ } )
452
+ } else {
453
+ None
454
+ } ;
455
+
456
+ Ok ( transaction)
457
+ }
458
+
414
459
fn add_pending_transaction (
415
460
& mut self ,
416
461
transaction : PendingTransaction ,
@@ -738,23 +783,45 @@ async fn create_blockchain_and_state(
738
783
}
739
784
}
740
785
786
+ /// The result returned by requesting a transaction.
787
+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
788
+ pub struct GetTransactionResult {
789
+ /// The signed transaction.
790
+ pub signed_transaction : SignedTransaction ,
791
+ /// Information about the active hardforks.
792
+ pub spec_id : SpecId ,
793
+ /// The block metadata for the transaction. None if the transaction is
794
+ /// pending.
795
+ pub block_metadata : Option < BlockMetadataForTransaction > ,
796
+ }
797
+
798
+ /// Block metadata for a transaction.
799
+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
800
+ pub struct BlockMetadataForTransaction {
801
+ pub base_fee_per_gas : Option < U256 > ,
802
+ pub block_hash : B256 ,
803
+ pub block_number : u64 ,
804
+ pub transaction_index : u64 ,
805
+ }
806
+
741
807
#[ cfg( test) ]
742
808
mod tests {
809
+ use anyhow:: Context ;
743
810
use tempfile:: TempDir ;
744
811
745
812
use super :: * ;
746
813
use crate :: { test_utils:: create_test_config_with_impersonated_accounts, ProviderConfig } ;
747
814
748
- struct NodeTestFixture {
815
+ struct ProviderTestFixture {
749
816
// We need to keep the tempdir alive for the duration of the test
750
817
_cache_dir : TempDir ,
751
818
config : ProviderConfig ,
752
819
provider_data : ProviderData ,
753
820
impersonated_account : Address ,
754
821
}
755
822
756
- impl NodeTestFixture {
757
- pub ( crate ) async fn new ( runtime : & runtime :: Handle ) -> anyhow:: Result < Self > {
823
+ impl ProviderTestFixture {
824
+ pub ( crate ) async fn new ( ) -> anyhow:: Result < Self > {
758
825
let cache_dir = TempDir :: new ( ) ?;
759
826
760
827
let impersonated_account = Address :: random ( ) ;
@@ -763,7 +830,8 @@ mod tests {
763
830
vec ! [ impersonated_account] ,
764
831
) ;
765
832
766
- let mut provider_data = ProviderData :: new ( runtime, & config) . await ?;
833
+ let runtime = runtime:: Handle :: try_current ( ) ?;
834
+ let mut provider_data = ProviderData :: new ( & runtime, & config) . await ?;
767
835
provider_data
768
836
. impersonated_accounts
769
837
. insert ( impersonated_account) ;
@@ -786,7 +854,7 @@ mod tests {
786
854
. expect ( "there are local accounts" ) ,
787
855
to : Some ( Address :: zero ( ) ) ,
788
856
gas : Some ( 100_000 ) ,
789
- gas_price : Some ( U256 :: from ( 1 ) ) ,
857
+ gas_price : Some ( U256 :: from ( 42_000_000_000_u64 ) ) ,
790
858
value : Some ( U256 :: from ( 1 ) ) ,
791
859
data : None ,
792
860
nonce : None ,
@@ -813,7 +881,7 @@ mod tests {
813
881
814
882
#[ tokio:: test]
815
883
async fn test_sign_transaction_request ( ) -> anyhow:: Result < ( ) > {
816
- let fixture = NodeTestFixture :: new ( & runtime :: Handle :: current ( ) ) . await ?;
884
+ let fixture = ProviderTestFixture :: new ( ) . await ?;
817
885
818
886
let transaction = fixture. signed_dummy_transaction ( ) ?;
819
887
let recovered_address = transaction. recover ( ) ?;
@@ -828,7 +896,7 @@ mod tests {
828
896
829
897
#[ tokio:: test]
830
898
async fn test_sign_transaction_request_impersonated_account ( ) -> anyhow:: Result < ( ) > {
831
- let fixture = NodeTestFixture :: new ( & runtime :: Handle :: current ( ) ) . await ?;
899
+ let fixture = ProviderTestFixture :: new ( ) . await ?;
832
900
833
901
let transaction = fixture. impersonated_dummy_transaction ( ) ?;
834
902
@@ -838,7 +906,7 @@ mod tests {
838
906
}
839
907
840
908
fn test_add_pending_transaction (
841
- fixture : & mut NodeTestFixture ,
909
+ fixture : & mut ProviderTestFixture ,
842
910
transaction : PendingTransaction ,
843
911
) -> anyhow:: Result < ( ) > {
844
912
let filter_id = fixture. provider_data . new_pending_transaction_filter ( ) ;
@@ -869,23 +937,23 @@ mod tests {
869
937
870
938
#[ tokio:: test]
871
939
async fn add_pending_transaction ( ) -> anyhow:: Result < ( ) > {
872
- let mut fixture = NodeTestFixture :: new ( & runtime :: Handle :: current ( ) ) . await ?;
940
+ let mut fixture = ProviderTestFixture :: new ( ) . await ?;
873
941
let transaction = fixture. signed_dummy_transaction ( ) ?;
874
942
875
943
test_add_pending_transaction ( & mut fixture, transaction)
876
944
}
877
945
878
946
#[ tokio:: test]
879
947
async fn add_pending_transaction_from_impersonated_account ( ) -> anyhow:: Result < ( ) > {
880
- let mut fixture = NodeTestFixture :: new ( & runtime :: Handle :: current ( ) ) . await ?;
948
+ let mut fixture = ProviderTestFixture :: new ( ) . await ?;
881
949
let transaction = fixture. impersonated_dummy_transaction ( ) ?;
882
950
883
951
test_add_pending_transaction ( & mut fixture, transaction)
884
952
}
885
953
886
954
#[ tokio:: test]
887
955
async fn chain_id ( ) -> anyhow:: Result < ( ) > {
888
- let fixture = NodeTestFixture :: new ( & runtime :: Handle :: current ( ) ) . await ?;
956
+ let fixture = ProviderTestFixture :: new ( ) . await ?;
889
957
890
958
let chain_id = fixture. provider_data . chain_id ( ) . await ;
891
959
assert_eq ! ( chain_id, fixture. config. chain_id) ;
@@ -895,7 +963,7 @@ mod tests {
895
963
896
964
#[ tokio:: test]
897
965
async fn next_filter_id ( ) -> anyhow:: Result < ( ) > {
898
- let mut fixture = NodeTestFixture :: new ( & runtime :: Handle :: current ( ) ) . await ?;
966
+ let mut fixture = ProviderTestFixture :: new ( ) . await ?;
899
967
900
968
let mut prev_filter_id = fixture. provider_data . last_filter_id ;
901
969
for _ in 0 ..10 {
@@ -909,7 +977,7 @@ mod tests {
909
977
910
978
#[ tokio:: test]
911
979
async fn set_balance_updates_mem_pool ( ) -> anyhow:: Result < ( ) > {
912
- let mut fixture = NodeTestFixture :: new ( & runtime :: Handle :: current ( ) ) . await ?;
980
+ let mut fixture = ProviderTestFixture :: new ( ) . await ?;
913
981
914
982
let transaction = {
915
983
let mut request = fixture. dummy_transaction_request ( ) ;
@@ -942,7 +1010,7 @@ mod tests {
942
1010
943
1011
#[ tokio:: test]
944
1012
async fn set_nonce_updates_mem_pool ( ) -> anyhow:: Result < ( ) > {
945
- let mut fixture = NodeTestFixture :: new ( & runtime :: Handle :: current ( ) ) . await ?;
1013
+ let mut fixture = ProviderTestFixture :: new ( ) . await ?;
946
1014
947
1015
// Artificially raise the nonce, to ensure the transaction is not rejected
948
1016
fixture
@@ -990,4 +1058,75 @@ mod tests {
990
1058
991
1059
Ok ( ( ) )
992
1060
}
1061
+
1062
+ #[ tokio:: test]
1063
+ async fn transaction_by_invalid_hash ( ) -> anyhow:: Result < ( ) > {
1064
+ let fixture = ProviderTestFixture :: new ( ) . await ?;
1065
+
1066
+ let non_existing_tx = fixture
1067
+ . provider_data
1068
+ . transaction_by_hash ( & B256 :: zero ( ) )
1069
+ . await ?;
1070
+
1071
+ assert_eq ! ( non_existing_tx, None ) ;
1072
+
1073
+ Ok ( ( ) )
1074
+ }
1075
+
1076
+ #[ tokio:: test]
1077
+ async fn pending_transaction_by_hash ( ) -> anyhow:: Result < ( ) > {
1078
+ let mut fixture = ProviderTestFixture :: new ( ) . await ?;
1079
+
1080
+ let transaction_request = fixture. signed_dummy_transaction ( ) ?;
1081
+ let transaction_hash = fixture
1082
+ . provider_data
1083
+ . add_pending_transaction ( transaction_request) ?;
1084
+
1085
+ let transaction_result = fixture
1086
+ . provider_data
1087
+ . transaction_by_hash ( & transaction_hash)
1088
+ . await ?
1089
+ . context ( "transaction not found" ) ?;
1090
+
1091
+ assert_eq ! (
1092
+ transaction_result. signed_transaction. hash( ) ,
1093
+ & transaction_hash
1094
+ ) ;
1095
+
1096
+ Ok ( ( ) )
1097
+ }
1098
+
1099
+ #[ tokio:: test]
1100
+ async fn transaction_by_hash ( ) -> anyhow:: Result < ( ) > {
1101
+ let mut fixture = ProviderTestFixture :: new ( ) . await ?;
1102
+
1103
+ let transaction_request = fixture. signed_dummy_transaction ( ) ?;
1104
+ let transaction_hash = fixture
1105
+ . provider_data
1106
+ . add_pending_transaction ( transaction_request) ?;
1107
+
1108
+ let results = fixture. provider_data . mine_and_commit_block ( None ) . await ?;
1109
+
1110
+ // Make sure transaction was mined successfully.
1111
+ assert ! ( results
1112
+ . transaction_results
1113
+ . first( )
1114
+ . context( "failed to mine transaction" ) ?
1115
+ . is_success( ) ) ;
1116
+ // Sanity check that the mempool is empty.
1117
+ assert_eq ! ( fixture. provider_data. mem_pool. transactions( ) . count( ) , 0 ) ;
1118
+
1119
+ let transaction_result = fixture
1120
+ . provider_data
1121
+ . transaction_by_hash ( & transaction_hash)
1122
+ . await ?
1123
+ . context ( "transaction not found" ) ?;
1124
+
1125
+ assert_eq ! (
1126
+ transaction_result. signed_transaction. hash( ) ,
1127
+ & transaction_hash
1128
+ ) ;
1129
+
1130
+ Ok ( ( ) )
1131
+ }
993
1132
}
0 commit comments