@@ -15,12 +15,13 @@ use crate::{
1515 in_mem_rpc:: InMemoryRpcClient ,
1616 mining_engine:: MiningEngine ,
1717 service:: {
18- BackendWithOverlay , Client , Service ,
18+ BackendError , BackendWithOverlay , Client , Service ,
1919 storage:: {
2020 AccountType , ByteCodeType , CodeInfo , ContractInfo , ReviveAccountInfo ,
2121 SystemAccountInfo ,
2222 } ,
2323 } ,
24+ snapshot:: { RevertInfo , SnapshotManager } ,
2425 } ,
2526} ;
2627use alloy_eips:: { BlockId , BlockNumberOrTag } ;
@@ -31,6 +32,11 @@ use anvil_core::eth::{EthRequest, Params as MineParams};
3132use anvil_rpc:: response:: ResponseResult ;
3233use codec:: { Decode , Encode } ;
3334use futures:: { StreamExt , channel:: mpsc} ;
35+ use pallet_revive_eth_rpc:: {
36+ BlockInfoProvider , EthRpcError , ReceiptExtractor , ReceiptProvider , SubxtBlockInfoProvider ,
37+ client:: { Client as EthRpcClient , ClientError , SubscriptionType } ,
38+ subxt_client:: { self , SrcChainConfig } ,
39+ } ;
3440use polkadot_sdk:: {
3541 pallet_revive:: {
3642 ReviveApi ,
@@ -39,15 +45,13 @@ use polkadot_sdk::{
3945 TransactionSigned ,
4046 } ,
4147 } ,
42- pallet_revive_eth_rpc:: {
43- EthRpcError , ReceiptExtractor , ReceiptProvider , SubxtBlockInfoProvider ,
44- client:: { Client as EthRpcClient , ClientError , SubscriptionType } ,
45- subxt_client:: { self , SrcChainConfig } ,
46- } ,
4748 parachains_common:: { AccountId , Hash , Nonce } ,
49+ polkadot_sdk_frame:: runtime:: types_common:: OpaqueBlock ,
4850 sc_client_api:: HeaderBackend ,
51+ sc_service:: SpawnTaskHandle ,
4952 sp_api:: { Metadata , ProvideRuntimeApi } ,
5053 sp_arithmetic:: Permill ,
54+ sp_blockchain:: Info ,
5155 sp_core:: { self , Hasher , keccak_256} ,
5256 sp_runtime:: traits:: BlakeTwo256 ,
5357} ;
@@ -67,13 +71,15 @@ pub struct Wallet {
6771}
6872
6973pub struct ApiServer {
74+ eth_rpc_client : EthRpcClient ,
7075 req_receiver : mpsc:: Receiver < ApiRequest > ,
7176 backend : BackendWithOverlay ,
7277 logging_manager : LoggingManager ,
7378 client : Arc < Client > ,
7479 mining_engine : Arc < MiningEngine > ,
75- eth_rpc_client : EthRpcClient ,
80+ block_provider : SubxtBlockInfoProvider ,
7681 wallet : Wallet ,
82+ snapshot_manager : SnapshotManager ,
7783 impersonation_manager : ImpersonationManager ,
7884}
7985
@@ -82,11 +88,24 @@ impl ApiServer {
8288 substrate_service : Service ,
8389 req_receiver : mpsc:: Receiver < ApiRequest > ,
8490 logging_manager : LoggingManager ,
91+ snapshot_manager : SnapshotManager ,
8592 impersonation_manager : ImpersonationManager ,
8693 ) -> Result < Self > {
87- let eth_rpc_client = create_revive_rpc_client ( & substrate_service) . await ?;
94+ let rpc_client = RpcClient :: new ( InMemoryRpcClient ( substrate_service. rpc_handlers . clone ( ) ) ) ;
95+ let api = create_online_client ( & substrate_service, rpc_client. clone ( ) ) . await ?;
96+ let rpc = LegacyRpcMethods :: < SrcChainConfig > :: new ( rpc_client. clone ( ) ) ;
97+ let block_provider = SubxtBlockInfoProvider :: new ( api. clone ( ) , rpc. clone ( ) ) . await ?;
98+ let eth_rpc_client = create_revive_rpc_client (
99+ api. clone ( ) ,
100+ rpc_client. clone ( ) ,
101+ rpc,
102+ block_provider. clone ( ) ,
103+ substrate_service. spawn_handle . clone ( ) ,
104+ )
105+ . await ?;
88106
89107 Ok ( Self {
108+ block_provider,
90109 req_receiver,
91110 logging_manager,
92111 backend : BackendWithOverlay :: new (
@@ -96,6 +115,7 @@ impl ApiServer {
96115 client : substrate_service. client . clone ( ) ,
97116 mining_engine : substrate_service. mining_engine . clone ( ) ,
98117 eth_rpc_client,
118+ snapshot_manager,
99119 impersonation_manager,
100120 wallet : Wallet {
101121 accounts : vec ! [
@@ -129,6 +149,7 @@ impl ApiServer {
129149 EthRequest :: SetAutomine ( enabled) => self . set_auto_mine ( enabled) . to_rpc_result ( ) ,
130150 EthRequest :: EvmMine ( mine) => self . evm_mine ( mine) . await . to_rpc_result ( ) ,
131151 EthRequest :: EvmMineDetailed ( mine) => self . evm_mine_detailed ( mine) . await . to_rpc_result ( ) ,
152+
132153 //------- TimeMachine---------
133154 EthRequest :: EvmSetBlockTimeStampInterval ( time) => {
134155 self . set_block_timestamp_interval ( time) . to_rpc_result ( )
@@ -141,6 +162,7 @@ impl ApiServer {
141162 }
142163 EthRequest :: EvmIncreaseTime ( time) => self . increase_time ( time) . to_rpc_result ( ) ,
143164 EthRequest :: EvmSetTime ( timestamp) => self . set_time ( timestamp) . to_rpc_result ( ) ,
165+
144166 // -- Impersonation --
145167 EthRequest :: ImpersonateAccount ( addr) => {
146168 self . impersonate_account ( H160 :: from_slice ( addr. 0 . as_ref ( ) ) ) . to_rpc_result ( )
@@ -151,6 +173,10 @@ impl ApiServer {
151173 EthRequest :: AutoImpersonateAccount ( enable) => {
152174 self . auto_impersonate_account ( enable) . to_rpc_result ( )
153175 }
176+ EthRequest :: EthSendUnsignedTransaction ( request) => {
177+ node_info ! ( "eth_sendUnsignedTransaction" ) ;
178+ self . send_transaction ( * request. clone ( ) , true ) . await . to_rpc_result ( )
179+ }
154180
155181 //------- Eth RPCs---------
156182 EthRequest :: EthChainId ( _) => self . eth_chain_id ( ) . to_rpc_result ( ) ,
@@ -190,6 +216,11 @@ impl ApiServer {
190216 . map ( |val| AlloyU256 :: from ( val) . inner ( ) )
191217 . to_rpc_result ( ) ,
192218
219+ // --- Snapshot ---
220+ EthRequest :: EvmSnapshot ( ( ) ) => self . snapshot ( ) . await . to_rpc_result ( ) ,
221+ EthRequest :: Rollback ( depth) => self . rollback ( depth) . await . to_rpc_result ( ) ,
222+ EthRequest :: EvmRevert ( id) => self . revert ( id) . await . to_rpc_result ( ) ,
223+
193224 // ------- State injector ---------
194225 EthRequest :: SetBalance ( address, value) => {
195226 self . set_balance ( address, value) . to_rpc_result ( )
@@ -252,10 +283,6 @@ impl ApiServer {
252283 node_info ! ( "eth_getLogs" ) ;
253284 self . get_logs ( filter) . await . to_rpc_result ( )
254285 }
255- EthRequest :: EthSendUnsignedTransaction ( request) => {
256- node_info ! ( "eth_sendUnsignedTransaction" ) ;
257- self . send_transaction ( * request. clone ( ) , true ) . await . to_rpc_result ( )
258- }
259286 _ => Err :: < ( ) , _ > ( Error :: RpcUnimplemented ) . to_rpc_result ( ) ,
260287 } ;
261288
@@ -614,6 +641,36 @@ impl ApiServer {
614641 Ok ( Some ( block) )
615642 }
616643
644+ pub ( crate ) async fn snapshot ( & mut self ) -> Result < U256 > {
645+ node_info ! ( "evm_snapshot" ) ;
646+ Ok ( self . snapshot_manager . snapshot ( ) )
647+ }
648+
649+ pub ( crate ) async fn revert ( & mut self , id : U256 ) -> Result < bool > {
650+ node_info ! ( "evm_revert" ) ;
651+ let res = self
652+ . snapshot_manager
653+ . revert ( id)
654+ . map_err ( |err| Error :: Backend ( BackendError :: Client ( err) ) ) ?;
655+ let Some ( res) = res else { return Ok ( false ) } ;
656+
657+ self . on_revert_update ( res) . await ?;
658+
659+ Ok ( true )
660+ }
661+
662+ pub ( crate ) async fn rollback ( & mut self , depth : Option < u64 > ) -> Result < ( ) > {
663+ node_info ! ( "anvil_rollback" ) ;
664+ let res = self
665+ . snapshot_manager
666+ . rollback ( depth)
667+ . map_err ( |err| Error :: Backend ( BackendError :: Client ( err) ) ) ?;
668+
669+ self . on_revert_update ( res) . await ?;
670+
671+ Ok ( ( ) )
672+ }
673+
617674 async fn get_block_transaction_count_by_hash ( & self , block_hash : B256 ) -> Result < Option < U256 > > {
618675 let block_hash = H256 :: from_slice ( block_hash. as_slice ( ) ) ;
619676 Ok ( self . eth_rpc_client . receipts_count_per_block ( & block_hash) . await . map ( U256 :: from) )
@@ -729,13 +786,6 @@ impl ApiServer {
729786 Ok ( FilterResults :: Logs ( logs) )
730787 }
731788
732- // Helpers
733- async fn get_block_hash_for_tag ( & self , block_id : Option < BlockId > ) -> Result < H256 > {
734- self . eth_rpc_client
735- . block_hash_for_tag ( ReviveBlockId :: from ( block_id) . inner ( ) )
736- . await
737- . map_err ( Error :: from)
738- }
739789 // State injector RPCs
740790 fn set_chain_id ( & self , chain_id : u64 ) -> Result < ( ) > {
741791 node_info ! ( "anvil_setChainId" ) ;
@@ -894,7 +944,52 @@ impl ApiServer {
894944
895945 Ok ( ( ) )
896946 }
947+
897948 // ----- Helpers
949+ async fn update_block_provider_on_revert ( & self , info : & Info < OpaqueBlock > ) -> Result < ( ) > {
950+ let new_best_block = self . block_provider . block_by_number ( info. best_number ) . await ?;
951+ let new_finalized_block =
952+ self . block_provider . block_by_number ( info. finalized_number ) . await ?;
953+
954+ if let Some ( block) = new_best_block. and_then ( Arc :: into_inner) {
955+ self . block_provider . update_latest ( block, SubscriptionType :: BestBlocks ) . await ;
956+ }
957+
958+ if let Some ( block) = new_finalized_block. and_then ( Arc :: into_inner) {
959+ self . block_provider . update_latest ( block, SubscriptionType :: FinalizedBlocks ) . await ;
960+ }
961+
962+ Ok ( ( ) )
963+ }
964+
965+ async fn update_time_on_revert ( & self , best_hash : Hash ) -> Result < ( ) > {
966+ let timestamp = self . backend . read_timestamp ( best_hash) ?;
967+ self . mining_engine . set_time ( Duration :: from_millis ( timestamp) ) ;
968+ Ok ( ( ) )
969+ }
970+
971+ async fn on_revert_update ( & self , revert_info : RevertInfo ) -> Result < ( ) > {
972+ if revert_info. reverted > 0 {
973+ self . update_block_provider_on_revert ( & revert_info. info ) . await ?;
974+ }
975+
976+ let hash = self
977+ . get_block_hash_for_tag ( Some ( BlockId :: Number ( BlockNumberOrTag :: Number (
978+ revert_info. info . best_number . into ( ) ,
979+ ) ) ) )
980+ . await ?;
981+ self . update_time_on_revert ( hash) . await ?;
982+
983+ Ok ( ( ) )
984+ }
985+
986+ async fn get_block_hash_for_tag ( & self , block_id : Option < BlockId > ) -> Result < H256 > {
987+ self . eth_rpc_client
988+ . block_hash_for_tag ( ReviveBlockId :: from ( block_id) . inner ( ) )
989+ . await
990+ . map_err ( Error :: from)
991+ }
992+
898993 fn get_account_id ( & self , block : Hash , address : Address ) -> Result < AccountId > {
899994 Ok ( self . client . runtime_api ( ) . account_id ( block, ReviveAddress :: from ( address) . inner ( ) ) ?)
900995 }
@@ -961,9 +1056,10 @@ fn new_contract_info(address: &Address, code_hash: H256, nonce: Nonce) -> Contra
9611056 }
9621057}
9631058
964- async fn create_revive_rpc_client ( substrate_service : & Service ) -> Result < EthRpcClient > {
965- let rpc_client = RpcClient :: new ( InMemoryRpcClient ( substrate_service. rpc_handlers . clone ( ) ) ) ;
966-
1059+ async fn create_online_client (
1060+ substrate_service : & Service ,
1061+ rpc_client : RpcClient ,
1062+ ) -> Result < OnlineClient < SrcChainConfig > > {
9671063 let genesis_block_number = substrate_service. genesis_block_number . try_into ( ) . map_err ( |_| {
9681064 Error :: InternalError ( format ! (
9691065 "Genesis block number {} is too large for u32 (max: {})" ,
@@ -996,9 +1092,11 @@ async fn create_revive_rpc_client(substrate_service: &Service) -> Result<EthRpcC
9961092 else {
9971093 return Err ( Error :: InternalError ( "Unable to fetch metadata versions" . to_string ( ) ) ) ;
9981094 } ;
1095+
9991096 let Some ( latest_metadata_version) = supported_metadata_versions. into_iter ( ) . max ( ) else {
10001097 return Err ( Error :: InternalError ( "No stable metadata versions supported" . to_string ( ) ) ) ;
10011098 } ;
1099+
10021100 let opaque_metadata = substrate_service
10031101 . client
10041102 . runtime_api ( )
@@ -1014,16 +1112,24 @@ async fn create_revive_rpc_client(substrate_service: &Service) -> Result<EthRpcC
10141112 let subxt_metadata = SubxtMetadata :: decode ( & mut ( * opaque_metadata) . as_slice ( ) )
10151113 . map_err ( |_| Error :: InternalError ( "Unable to decode metadata" . to_string ( ) ) ) ?;
10161114
1017- let api = OnlineClient :: < SrcChainConfig > :: from_rpc_client_with (
1115+ OnlineClient :: < SrcChainConfig > :: from_rpc_client_with (
10181116 genesis_hash,
10191117 subxt_runtime_version,
10201118 subxt_metadata,
1021- rpc_client. clone ( ) ,
1022- ) ?;
1023- let rpc = LegacyRpcMethods :: < SrcChainConfig > :: new ( rpc_client. clone ( ) ) ;
1024-
1025- let block_provider = SubxtBlockInfoProvider :: new ( api. clone ( ) , rpc. clone ( ) ) . await ?;
1119+ rpc_client,
1120+ )
1121+ . map_err ( |err| {
1122+ Error :: InternalError ( format ! ( "Failed to initialize the subxt online client: {err}" ) )
1123+ } )
1124+ }
10261125
1126+ async fn create_revive_rpc_client (
1127+ api : OnlineClient < SrcChainConfig > ,
1128+ rpc_client : RpcClient ,
1129+ rpc : LegacyRpcMethods < SrcChainConfig > ,
1130+ block_provider : SubxtBlockInfoProvider ,
1131+ task_spawn_handle : SpawnTaskHandle ,
1132+ ) -> Result < EthRpcClient > {
10271133 let ( pool, keep_latest_n_blocks) = {
10281134 // see sqlite in-memory issue: https://github.com/launchbadge/sqlx/issues/2510
10291135 let pool = SqlitePoolOptions :: new ( )
@@ -1069,16 +1175,17 @@ async fn create_revive_rpc_client(substrate_service: &Service) -> Result<EthRpcC
10691175 . await
10701176 . map_err ( Error :: from) ?;
10711177 let eth_rpc_client_clone = eth_rpc_client. clone ( ) ;
1072- substrate_service . spawn_handle . spawn ( "block-subscription" , "None" , async move {
1178+ task_spawn_handle . spawn ( "block-subscription" , "None" , async move {
10731179 let eth_rpc_client = eth_rpc_client_clone;
10741180 let best_future =
10751181 eth_rpc_client. subscribe_and_cache_new_blocks ( SubscriptionType :: BestBlocks ) ;
10761182 let finalized_future =
10771183 eth_rpc_client. subscribe_and_cache_new_blocks ( SubscriptionType :: FinalizedBlocks ) ;
10781184 let res = tokio:: try_join!( best_future, finalized_future) . map ( |_| ( ) ) ;
10791185 if let Err ( err) = res {
1080- panic ! ( "Block subscription task failed: {err:?}" , )
1186+ panic ! ( "Block subscription task failed: {err:?}" )
10811187 }
10821188 } ) ;
1189+
10831190 Ok ( eth_rpc_client)
10841191}
0 commit comments