1use crate::{DBErrorMarker, Database, DatabaseCommit, DatabaseRef};
3use core::{
4 convert::Infallible,
5 future::Future,
6 marker::PhantomData,
7 pin::Pin,
8 ptr::NonNull,
9 task::{Context, Poll},
10};
11use corosensei::{stack::DefaultStack, Coroutine, CoroutineResult, Yielder};
12use primitives::{Address, AddressMap, StorageKey, StorageValue, B256};
13use state::{Account, AccountId, AccountInfo, Bytecode};
14use std::{cell::Cell, fmt, io};
15use tokio::{
16 runtime::{Handle, Runtime},
17 task,
18};
19
20type Resume = AsyncResult<NonNull<Context<'static>>>;
21type Yield = ();
22type Complete<R> = AsyncResult<R>;
23type DatabaseFiber<R> = Coroutine<Resume, Yield, Complete<R>, DefaultStack>;
24
25const DEFAULT_STACK_SIZE: usize = 1024 * 1024;
26
27#[derive(Default)]
29pub struct FiberStack {
30 stack: Option<DefaultStack>,
31}
32
33impl Clone for FiberStack {
34 #[inline]
35 fn clone(&self) -> Self {
36 Self::default()
37 }
38}
39
40impl fmt::Debug for FiberStack {
41 #[inline]
42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43 f.debug_struct("FiberStack").finish_non_exhaustive()
44 }
45}
46
47impl FiberStack {
48 #[inline]
49 fn take_or_new(&mut self) -> AsyncResult<DefaultStack> {
50 match self.stack.take() {
51 Some(stack) => Ok(stack),
52 None => DefaultStack::new(DEFAULT_STACK_SIZE).map_err(AsyncError::Io),
53 }
54 }
55
56 #[inline]
57 fn put(&mut self, stack: DefaultStack) {
58 debug_assert!(self.stack.is_none());
59 self.stack = Some(stack);
60 }
61}
62
63thread_local! {
64 static CURRENT: Cell<Option<NonNull<CurrentFiber>>> = const { Cell::new(None) };
65}
66
67pub type AsyncResult<T, E = Infallible> = Result<T, AsyncError<E>>;
69
70#[derive(Debug, thiserror::Error)]
72#[non_exhaustive]
73pub enum AsyncError<E = Infallible> {
74 #[error("async EVM execution was cancelled")]
76 Cancelled,
77 #[error("async host operation requires EVM async fiber execution")]
79 NotOnFiber,
80 #[error("async host operation requires a Tokio multi-thread runtime")]
82 Runtime,
83 #[error(transparent)]
85 Io(io::Error),
86 #[error(transparent)]
88 Inner(#[from] E),
89}
90
91impl AsyncError {
92 fn with_inner_error<E>(self) -> AsyncError<E> {
93 match self {
94 Self::Cancelled => AsyncError::Cancelled,
95 Self::NotOnFiber => AsyncError::NotOnFiber,
96 Self::Runtime => AsyncError::Runtime,
97 Self::Io(error) => AsyncError::Io(error),
98 Self::Inner(error) => match error {},
99 }
100 }
101}
102
103impl<E: DBErrorMarker> DBErrorMarker for AsyncError<E> {
104 #[inline]
105 fn is_fatal(&self) -> bool {
106 match self {
107 Self::Inner(error) => error.is_fatal(),
108 _ => true,
109 }
110 }
111}
112
113struct CurrentFiber {
114 suspend: NonNull<Yielder<Resume, Yield>>,
115 future_cx: NonNull<Context<'static>>,
116 cancelled: bool,
117}
118
119impl CurrentFiber {
120 #[inline]
121 fn context(&mut self) -> &mut Context<'_> {
122 unsafe { restore_context_lifetime(self.future_cx.as_mut()) }
123 }
124
125 #[inline]
126 fn suspend(&mut self) -> AsyncResult<()> {
127 match unsafe { self.suspend.as_ref() }.suspend(()) {
128 Ok(cx) => {
129 self.future_cx = cx;
130 Ok(())
131 }
132 Err(error) => {
133 self.cancelled = true;
134 Err(error)
135 }
136 }
137 }
138
139 #[inline]
140 const fn is_cancelled(&self) -> bool {
141 self.cancelled
142 }
143}
144
145struct ResetCurrentFiber(Option<NonNull<CurrentFiber>>);
146
147impl Drop for ResetCurrentFiber {
148 fn drop(&mut self) {
149 CURRENT.set(self.0);
150 }
151}
152
153#[cfg(test)]
158pub(crate) fn on_fiber_result<'a, R, E>(
159 func: impl FnOnce() -> Result<R, E> + 'a,
160) -> impl Future<Output = AsyncResult<R, E>> + Send + 'a
161where
162 R: Send + 'a,
163 E: Send + 'a,
164{
165 OnFiber::new(func)
166}
167
168pub unsafe fn on_fiber_result_with_stack<'a, R, E>(
175 stack: NonNull<FiberStack>,
176 func: impl FnOnce() -> Result<R, E> + 'a,
177) -> impl Future<Output = AsyncResult<R, E>> + Send + 'a
178where
179 R: Send + 'a,
180 E: Send + 'a,
181{
182 OnFiber::with_stack(stack, func)
183}
184
185#[cfg(test)]
186pub(crate) fn on_fiber<'a, R>(
187 func: impl FnOnce() -> R + 'a,
188) -> impl Future<Output = AsyncResult<R>> + Send + 'a
189where
190 R: Send + 'a,
191{
192 on_fiber_result(move || Ok::<_, Infallible>(func()))
193}
194
195pub unsafe fn on_fiber_with_stack<'a, R>(
201 stack: NonNull<FiberStack>,
202 func: impl FnOnce() -> R + 'a,
203) -> impl Future<Output = AsyncResult<R>> + Send + 'a
204where
205 R: Send + 'a,
206{
207 unsafe { on_fiber_result_with_stack(stack, move || Ok::<_, Infallible>(func())) }
208}
209
210enum OnFiber<'a, R, E> {
211 Running(FiberFuture<'a, Result<R, E>>),
212 Error(Option<AsyncError>),
213 Done,
214}
215
216impl<'a, R, E> OnFiber<'a, R, E> {
217 #[cfg(test)]
218 fn new(func: impl FnOnce() -> Result<R, E> + 'a) -> Self {
219 Self::new_inner(None, func)
220 }
221
222 fn with_stack(stack: NonNull<FiberStack>, func: impl FnOnce() -> Result<R, E> + 'a) -> Self {
223 Self::new_inner(Some(stack), func)
224 }
225
226 fn new_inner(
227 stack: Option<NonNull<FiberStack>>,
228 func: impl FnOnce() -> Result<R, E> + 'a,
229 ) -> Self {
230 match FiberFuture::new(stack, func) {
231 Ok(fiber) => Self::Running(fiber),
232 Err(error) => Self::Error(Some(error)),
233 }
234 }
235}
236
237impl<R, E> Future for OnFiber<'_, R, E> {
238 type Output = AsyncResult<R, E>;
239
240 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
241 let this = self.get_mut();
242 match this {
243 Self::Running(fiber) => match Pin::new(fiber).poll(cx) {
244 Poll::Ready(Ok(Ok(value))) => {
245 *this = Self::Done;
246 Poll::Ready(Ok(value))
247 }
248 Poll::Ready(Ok(Err(error))) => {
249 *this = Self::Done;
250 Poll::Ready(Err(AsyncError::Inner(error)))
251 }
252 Poll::Ready(Err(error)) => {
253 *this = Self::Done;
254 Poll::Ready(Err(error.with_inner_error()))
255 }
256 Poll::Pending => Poll::Pending,
257 },
258 Self::Error(error) => {
259 let error = error
260 .take()
261 .expect("async EVM fiber error already returned");
262 Poll::Ready(Err(error.with_inner_error()))
263 }
264 Self::Done => panic!("async EVM fiber polled after completion"),
265 }
266 }
267}
268
269struct FiberFuture<'a, R> {
270 fiber: Option<DatabaseFiber<R>>,
271 stack: Option<NonNull<FiberStack>>,
272 _marker: PhantomData<&'a ()>,
273}
274
275unsafe impl<R: Send> Send for FiberFuture<'_, R> {}
279
280impl<'a, R> FiberFuture<'a, R> {
281 fn new(
282 mut stack: Option<NonNull<FiberStack>>,
283 func: impl FnOnce() -> R + 'a,
284 ) -> AsyncResult<Self> {
285 let fiber_stack = match &mut stack {
286 Some(stack) => unsafe { stack.as_mut() }.take_or_new()?,
287 None => DefaultStack::new(DEFAULT_STACK_SIZE).map_err(AsyncError::Io)?,
288 };
289 let body = move |suspend: &Yielder<Resume, Yield>, resume| {
290 let future_cx = resume?;
291 let mut current = CurrentFiber {
292 suspend: NonNull::from(suspend),
293 future_cx,
294 cancelled: false,
295 };
296 let current = NonNull::from(&mut current);
297 let previous = CURRENT.replace(Some(current));
298 let _reset = ResetCurrentFiber(previous);
299 Ok(func())
300 };
301 let fiber = unsafe { Coroutine::with_stack_unchecked(fiber_stack, body) };
304 Ok(Self {
305 fiber: Some(fiber),
306 stack,
307 _marker: PhantomData,
308 })
309 }
310
311 fn recycle_stack(&mut self) {
312 let Some(fiber) = self.fiber.take() else {
313 return;
314 };
315 debug_assert!(fiber.done());
316 let stack = fiber.into_stack();
317 if let Some(mut slot) = self.stack {
318 unsafe { slot.as_mut() }.put(stack);
319 }
320 }
321}
322
323impl<R> Future for FiberFuture<'_, R> {
324 type Output = AsyncResult<R>;
325
326 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
327 let this = self.get_mut();
328 let cx = NonNull::from(unsafe { change_context_lifetime(cx) });
329 let fiber = this
330 .fiber
331 .as_mut()
332 .expect("async EVM fiber polled after completion");
333 match fiber.resume(Ok(cx)) {
334 CoroutineResult::Return(result) => {
335 this.recycle_stack();
336 Poll::Ready(result)
337 }
338 CoroutineResult::Yield(()) => Poll::Pending,
339 }
340 }
341}
342
343impl<R> Drop for FiberFuture<'_, R> {
344 fn drop(&mut self) {
345 let Some(fiber) = self.fiber.as_mut() else {
346 return;
347 };
348 if fiber.done() {
349 self.recycle_stack();
350 } else if matches!(
351 fiber.resume(Err(AsyncError::Cancelled)),
352 CoroutineResult::Yield(())
353 ) {
354 unsafe { fiber.force_reset() };
357 } else {
358 self.recycle_stack();
359 }
360 }
361}
362
363pub fn block_on_current<F: Future>(future: F) -> AsyncResult<F::Output> {
374 let mut future = core::pin::pin!(future);
375 loop {
376 match with_current(|current| {
377 if current.is_cancelled() {
378 return Err(AsyncError::Cancelled);
379 }
380 let poll = future.as_mut().poll(current.context());
381 if poll.is_pending() {
382 current.suspend()?;
383 }
384 Ok(poll)
385 })? {
386 Poll::Ready(value) => return Ok(value),
387 Poll::Pending => {}
388 }
389 }
390}
391
392fn current_tokio_handle() -> Option<Handle> {
393 match Handle::try_current() {
394 Ok(handle) => match handle.runtime_flavor() {
395 tokio::runtime::RuntimeFlavor::CurrentThread => None,
396 _ => Some(handle),
397 },
398 Err(_) => None,
399 }
400}
401
402fn block_on_handle<F>(handle: &Handle, future: F) -> F::Output
403where
404 F: Future + Send,
405 F::Output: Send,
406{
407 let should_use_block_in_place = Handle::try_current()
408 .ok()
409 .map(|current| {
410 !matches!(
411 current.runtime_flavor(),
412 tokio::runtime::RuntimeFlavor::CurrentThread
413 )
414 })
415 .unwrap_or(false);
416
417 if should_use_block_in_place {
418 task::block_in_place(move || handle.block_on(future))
419 } else {
420 handle.block_on(future)
421 }
422}
423
424fn block_on_runtime<F>(runtime: Option<&Handle>, future: F) -> AsyncResult<F::Output>
425where
426 F: Future + Send,
427 F::Output: Send,
428{
429 if CURRENT.get().is_some() {
430 return block_on_current(future);
431 }
432
433 if let Some(runtime) = runtime {
434 return Ok(block_on_handle(runtime, future));
435 }
436
437 Err(AsyncError::Runtime)
438}
439
440fn block_on_runtime_result<F, T, E>(runtime: Option<&Handle>, future: F) -> AsyncResult<T, E>
441where
442 F: Future<Output = Result<T, E>> + Send,
443 T: Send,
444 E: Send,
445{
446 match block_on_runtime(runtime, future).map_err(AsyncError::with_inner_error)? {
447 Ok(value) => Ok(value),
448 Err(error) => Err(AsyncError::Inner(error)),
449 }
450}
451
452fn with_current<R>(f: impl FnOnce(&mut CurrentFiber) -> AsyncResult<R>) -> AsyncResult<R> {
453 let mut current = CURRENT.get().ok_or(AsyncError::NotOnFiber)?;
454 f(unsafe { current.as_mut() })
455}
456
457unsafe fn change_context_lifetime<'a>(cx: &'a mut Context<'_>) -> &'a mut Context<'static> {
458 unsafe { core::mem::transmute::<&'a mut Context<'_>, &'a mut Context<'static>>(cx) }
459}
460
461unsafe fn restore_context_lifetime<'a>(cx: &'a mut Context<'static>) -> &'a mut Context<'a> {
462 unsafe { core::mem::transmute::<&'a mut Context<'static>, &'a mut Context<'a>>(cx) }
463}
464
465pub trait DatabaseAsync {
471 type Error: DBErrorMarker;
473
474 fn basic_async(
476 &mut self,
477 address: Address,
478 ) -> impl Future<Output = Result<Option<AccountInfo>, Self::Error>> + Send;
479
480 fn code_by_hash_async(
482 &mut self,
483 code_hash: B256,
484 ) -> impl Future<Output = Result<Bytecode, Self::Error>> + Send;
485
486 fn storage_async(
488 &mut self,
489 address: Address,
490 index: StorageKey,
491 ) -> impl Future<Output = Result<StorageValue, Self::Error>> + Send;
492
493 #[inline]
497 fn storage_by_account_id_async(
498 &mut self,
499 address: Address,
500 account_id: AccountId,
501 storage_key: StorageKey,
502 ) -> impl Future<Output = Result<StorageValue, Self::Error>> + Send {
503 let _ = account_id;
504 self.storage_async(address, storage_key)
505 }
506
507 fn block_hash_async(
509 &mut self,
510 number: u64,
511 ) -> impl Future<Output = Result<B256, Self::Error>> + Send;
512}
513
514pub trait DatabaseAsyncRef {
520 type Error: DBErrorMarker;
522
523 fn basic_async_ref(
525 &self,
526 address: Address,
527 ) -> impl Future<Output = Result<Option<AccountInfo>, Self::Error>> + Send;
528
529 fn code_by_hash_async_ref(
531 &self,
532 code_hash: B256,
533 ) -> impl Future<Output = Result<Bytecode, Self::Error>> + Send;
534
535 fn storage_async_ref(
537 &self,
538 address: Address,
539 index: StorageKey,
540 ) -> impl Future<Output = Result<StorageValue, Self::Error>> + Send;
541
542 #[inline]
546 fn storage_by_account_id_async_ref(
547 &self,
548 address: Address,
549 account_id: AccountId,
550 storage_key: StorageKey,
551 ) -> impl Future<Output = Result<StorageValue, Self::Error>> + Send {
552 let _ = account_id;
553 self.storage_async_ref(address, storage_key)
554 }
555
556 fn block_hash_async_ref(
558 &self,
559 number: u64,
560 ) -> impl Future<Output = Result<B256, Self::Error>> + Send;
561}
562
563#[derive(Debug)]
565pub struct AsyncDb<T> {
566 db: T,
567 rt: Option<HandleOrRuntime>,
568}
569
570impl<T> AsyncDb<T> {
571 #[inline]
575 pub fn new(db: T) -> Self {
576 Self {
577 db,
578 rt: current_tokio_handle().map(HandleOrRuntime::Handle),
579 }
580 }
581
582 #[inline]
586 pub fn blocking(db: T) -> Option<Self> {
587 Some(Self {
588 db,
589 rt: Some(HandleOrRuntime::Handle(current_tokio_handle()?)),
590 })
591 }
592
593 #[inline]
595 pub const fn with_runtime(db: T, runtime: Runtime) -> Self {
596 Self {
597 db,
598 rt: Some(HandleOrRuntime::Runtime(runtime)),
599 }
600 }
601
602 #[inline]
604 pub const fn with_handle(db: T, handle: Handle) -> Self {
605 Self {
606 db,
607 rt: Some(HandleOrRuntime::Handle(handle)),
608 }
609 }
610
611 #[inline]
613 pub const fn inner(&self) -> &T {
614 &self.db
615 }
616
617 #[inline]
619 pub const fn inner_mut(&mut self) -> &mut T {
620 &mut self.db
621 }
622
623 #[inline]
625 pub fn into_inner(self) -> T {
626 self.db
627 }
628}
629
630impl<T: DatabaseAsync> Database for AsyncDb<T> {
631 type Error = AsyncError<T::Error>;
632
633 #[inline]
634 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
635 let Self { db, rt } = self;
636 block_on_runtime_result(
637 rt.as_ref().map(HandleOrRuntime::handle),
638 db.basic_async(address),
639 )
640 }
641
642 #[inline]
643 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
644 let Self { db, rt } = self;
645 block_on_runtime_result(
646 rt.as_ref().map(HandleOrRuntime::handle),
647 db.code_by_hash_async(code_hash),
648 )
649 }
650
651 #[inline]
652 fn storage(
653 &mut self,
654 address: Address,
655 index: StorageKey,
656 ) -> Result<StorageValue, Self::Error> {
657 let Self { db, rt } = self;
658 block_on_runtime_result(
659 rt.as_ref().map(HandleOrRuntime::handle),
660 db.storage_async(address, index),
661 )
662 }
663
664 #[inline]
665 fn storage_by_account_id(
666 &mut self,
667 address: Address,
668 account_id: AccountId,
669 storage_key: StorageKey,
670 ) -> Result<StorageValue, Self::Error> {
671 let Self { db, rt } = self;
672 block_on_runtime_result(
673 rt.as_ref().map(HandleOrRuntime::handle),
674 db.storage_by_account_id_async(address, account_id, storage_key),
675 )
676 }
677
678 #[inline]
679 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
680 let Self { db, rt } = self;
681 block_on_runtime_result(
682 rt.as_ref().map(HandleOrRuntime::handle),
683 db.block_hash_async(number),
684 )
685 }
686}
687
688impl<T: DatabaseAsyncRef> DatabaseRef for AsyncDb<T> {
689 type Error = AsyncError<T::Error>;
690
691 #[inline]
692 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
693 block_on_runtime_result(
694 self.rt.as_ref().map(HandleOrRuntime::handle),
695 self.db.basic_async_ref(address),
696 )
697 }
698
699 #[inline]
700 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
701 block_on_runtime_result(
702 self.rt.as_ref().map(HandleOrRuntime::handle),
703 self.db.code_by_hash_async_ref(code_hash),
704 )
705 }
706
707 #[inline]
708 fn storage_ref(
709 &self,
710 address: Address,
711 index: StorageKey,
712 ) -> Result<StorageValue, Self::Error> {
713 block_on_runtime_result(
714 self.rt.as_ref().map(HandleOrRuntime::handle),
715 self.db.storage_async_ref(address, index),
716 )
717 }
718
719 #[inline]
720 fn storage_by_account_id_ref(
721 &self,
722 address: Address,
723 account_id: AccountId,
724 storage_key: StorageKey,
725 ) -> Result<StorageValue, Self::Error> {
726 block_on_runtime_result(
727 self.rt.as_ref().map(HandleOrRuntime::handle),
728 self.db
729 .storage_by_account_id_async_ref(address, account_id, storage_key),
730 )
731 }
732
733 #[inline]
734 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
735 block_on_runtime_result(
736 self.rt.as_ref().map(HandleOrRuntime::handle),
737 self.db.block_hash_async_ref(number),
738 )
739 }
740}
741
742impl<T: DatabaseAsync + DatabaseCommit> DatabaseCommit for AsyncDb<T> {
743 #[inline]
744 fn commit(&mut self, changes: AddressMap<Account>) {
745 self.db.commit(changes);
746 }
747
748 #[inline]
749 fn commit_iter(&mut self, changes: &mut dyn Iterator<Item = (Address, Account)>) {
750 self.db.commit_iter(changes);
751 }
752}
753
754#[derive(Debug)]
756pub struct WrapDatabaseAsync<T>(AsyncDb<T>);
757
758impl<T> WrapDatabaseAsync<T> {
759 #[inline]
763 pub fn new(db: T) -> Option<Self> {
764 AsyncDb::blocking(db).map(Self)
765 }
766
767 #[inline]
773 pub const fn with_runtime(db: T, runtime: Runtime) -> Self {
774 Self(AsyncDb::with_runtime(db, runtime))
775 }
776
777 #[inline]
784 pub const fn with_handle(db: T, handle: Handle) -> Self {
785 Self(AsyncDb::with_handle(db, handle))
786 }
787
788 #[inline]
790 pub const fn inner(&self) -> &T {
791 self.0.inner()
792 }
793
794 #[inline]
796 pub const fn inner_mut(&mut self) -> &mut T {
797 self.0.inner_mut()
798 }
799
800 #[inline]
802 pub fn into_inner(self) -> T {
803 self.0.into_inner()
804 }
805}
806
807impl<T: DatabaseAsync> Database for WrapDatabaseAsync<T> {
808 type Error = AsyncError<T::Error>;
809
810 #[inline]
811 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
812 self.0.basic(address)
813 }
814
815 #[inline]
816 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
817 self.0.code_by_hash(code_hash)
818 }
819
820 #[inline]
821 fn storage(
822 &mut self,
823 address: Address,
824 index: StorageKey,
825 ) -> Result<StorageValue, Self::Error> {
826 self.0.storage(address, index)
827 }
828
829 #[inline]
830 fn storage_by_account_id(
831 &mut self,
832 address: Address,
833 account_id: AccountId,
834 storage_key: StorageKey,
835 ) -> Result<StorageValue, Self::Error> {
836 self.0
837 .storage_by_account_id(address, account_id, storage_key)
838 }
839
840 #[inline]
841 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
842 self.0.block_hash(number)
843 }
844}
845
846impl<T: DatabaseAsyncRef> DatabaseRef for WrapDatabaseAsync<T> {
847 type Error = AsyncError<T::Error>;
848
849 #[inline]
850 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
851 self.0.basic_ref(address)
852 }
853
854 #[inline]
855 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
856 self.0.code_by_hash_ref(code_hash)
857 }
858
859 #[inline]
860 fn storage_ref(
861 &self,
862 address: Address,
863 index: StorageKey,
864 ) -> Result<StorageValue, Self::Error> {
865 self.0.storage_ref(address, index)
866 }
867
868 #[inline]
869 fn storage_by_account_id_ref(
870 &self,
871 address: Address,
872 account_id: AccountId,
873 storage_key: StorageKey,
874 ) -> Result<StorageValue, Self::Error> {
875 self.0
876 .storage_by_account_id_ref(address, account_id, storage_key)
877 }
878
879 #[inline]
880 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
881 self.0.block_hash_ref(number)
882 }
883}
884
885impl<T: DatabaseAsync + DatabaseCommit> DatabaseCommit for WrapDatabaseAsync<T> {
886 #[inline]
887 fn commit(&mut self, changes: AddressMap<Account>) {
888 self.0.commit(changes);
889 }
890
891 #[inline]
892 fn commit_iter(&mut self, changes: &mut dyn Iterator<Item = (Address, Account)>) {
893 self.0.commit_iter(changes);
894 }
895}
896
897#[derive(Debug)]
899enum HandleOrRuntime {
900 Handle(Handle),
901 Runtime(Runtime),
902}
903
904impl HandleOrRuntime {
905 #[inline]
906 fn handle(&self) -> &Handle {
907 match self {
908 Self::Handle(handle) => handle,
909 Self::Runtime(runtime) => runtime.handle(),
910 }
911 }
912}
913
914#[cfg(test)]
915mod tests {
916 use super::{block_on_current, on_fiber, AsyncDb, AsyncError, DatabaseAsync};
917 use crate::Database;
918 use core::{convert::Infallible, fmt, future::Future, pin::Pin, task::Poll};
919 use primitives::{Address, StorageKey, StorageValue, B256};
920 use state::{AccountInfo, Bytecode};
921 use std::task::{Context, Waker};
922
923 #[test]
924 fn block_on_requires_fiber() {
925 assert!(matches!(
926 block_on_current(core::future::ready(())),
927 Err(AsyncError::NotOnFiber)
928 ));
929 }
930
931 #[test]
932 fn fiber_suspends_and_resumes_pending_future() {
933 let mut state = 1;
934 let mut future = core::pin::pin!(on_fiber(|| {
935 state += block_on_current(PendingOnce { pending: true }).unwrap();
936 state
937 }));
938 let waker = Waker::noop();
939 let mut cx = Context::from_waker(waker);
940
941 assert!(matches!(future.as_mut().poll(&mut cx), Poll::Pending));
942 assert!(matches!(future.as_mut().poll(&mut cx), Poll::Ready(Ok(3))));
943 }
944
945 #[test]
946 fn fiber_reuses_stack_slot() {
947 let mut stack = super::FiberStack::default();
948 let stack_ptr = core::ptr::NonNull::from(&mut stack);
949
950 poll_ready(unsafe {
951 super::on_fiber_result_with_stack(stack_ptr, || Ok::<_, Infallible>(1))
952 })
953 .unwrap();
954 assert!(stack.stack.is_some());
955 poll_ready(unsafe {
956 super::on_fiber_result_with_stack(stack_ptr, || Ok::<_, Infallible>(2))
957 })
958 .unwrap();
959 assert!(stack.stack.is_some());
960 }
961
962 #[test]
963 fn async_database_adapts_to_database() {
964 let mut db = AsyncDb::new(TestDb);
965
966 let value = poll_ready(on_fiber(|| {
967 Database::storage(&mut db, Address::ZERO, StorageKey::from(7)).unwrap()
968 }))
969 .unwrap();
970
971 assert_eq!(value, StorageValue::from(9));
972 }
973
974 #[test]
975 fn async_database_suspends_until_ready() {
976 let mut db = AsyncDb::new(PendingDb { pending: true });
977 let mut future = core::pin::pin!(on_fiber(|| {
978 Database::storage(&mut db, Address::ZERO, StorageKey::from(7)).unwrap()
979 }));
980 let waker = Waker::noop();
981 let mut cx = Context::from_waker(waker);
982
983 assert!(matches!(future.as_mut().poll(&mut cx), Poll::Pending));
984 assert!(
985 matches!(future.as_mut().poll(&mut cx), Poll::Ready(Ok(value)) if value == StorageValue::from(9))
986 );
987 }
988
989 #[test]
990 fn async_database_returns_database_error() {
991 let mut db = AsyncDb::new(FailingDb);
992 let result = poll_ready(on_fiber(|| {
993 Database::storage(&mut db, Address::ZERO, StorageKey::from(7))
994 }));
995
996 assert!(matches!(result, Ok(Err(AsyncError::Inner(TestError)))));
997 }
998
999 #[test]
1000 fn synchronous_database_blocks_with_current_tokio_runtime() {
1001 let runtime = tokio::runtime::Runtime::new().unwrap();
1002 let _guard = runtime.enter();
1003 let mut db = AsyncDb::new(TokioDb);
1004
1005 let value = Database::storage(&mut db, Address::ZERO, StorageKey::from(7)).unwrap();
1006
1007 assert_eq!(value, StorageValue::from(9));
1008 }
1009
1010 #[test]
1011 fn blocking_constructor_uses_current_tokio_runtime() {
1012 let runtime = tokio::runtime::Runtime::new().unwrap();
1013 let _guard = runtime.enter();
1014 let mut db = AsyncDb::blocking(TokioDb).unwrap();
1015
1016 let value = Database::storage(&mut db, Address::ZERO, StorageKey::from(7)).unwrap();
1017
1018 assert_eq!(value, StorageValue::from(9));
1019 }
1020
1021 #[test]
1022 fn synchronous_database_blocks_with_stored_tokio_handle() {
1023 let runtime = tokio::runtime::Runtime::new().unwrap();
1024 let mut db = AsyncDb::with_handle(TokioDb, runtime.handle().clone());
1025
1026 let value = Database::storage(&mut db, Address::ZERO, StorageKey::from(7)).unwrap();
1027
1028 assert_eq!(value, StorageValue::from(9));
1029 }
1030
1031 #[test]
1032 fn synchronous_database_requires_runtime_handle() {
1033 let mut db = AsyncDb::new(TestDb);
1034
1035 let result = Database::storage(&mut db, Address::ZERO, StorageKey::from(7));
1036
1037 assert!(matches!(result, Err(AsyncError::Runtime)));
1038 }
1039
1040 #[test]
1041 fn dropping_fiber_cancels_blocked_future() {
1042 let mut saw_cancel = false;
1043 {
1044 let mut future = core::pin::pin!(on_fiber(|| {
1045 saw_cancel = matches!(block_on_current(PendingForever), Err(AsyncError::Cancelled));
1046 }));
1047 let waker = Waker::noop();
1048 let mut cx = Context::from_waker(waker);
1049
1050 assert!(matches!(future.as_mut().poll(&mut cx), Poll::Pending));
1051 }
1052 assert!(saw_cancel);
1053 }
1054
1055 fn poll_ready<F: Future + Send>(future: F) -> F::Output {
1056 let mut future = core::pin::pin!(future);
1057 let waker = Waker::noop();
1058 let mut cx = Context::from_waker(waker);
1059
1060 match future.as_mut().poll(&mut cx) {
1061 Poll::Ready(value) => value,
1062 Poll::Pending => panic!("future unexpectedly pending"),
1063 }
1064 }
1065
1066 struct PendingOnce {
1067 pending: bool,
1068 }
1069
1070 impl Future for PendingOnce {
1071 type Output = i32;
1072
1073 fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
1074 if self.pending {
1075 self.pending = false;
1076 Poll::Pending
1077 } else {
1078 Poll::Ready(2)
1079 }
1080 }
1081 }
1082
1083 struct PendingForever;
1084
1085 impl Future for PendingForever {
1086 type Output = ();
1087
1088 fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
1089 Poll::Pending
1090 }
1091 }
1092
1093 struct TestDb;
1094
1095 impl DatabaseAsync for TestDb {
1096 type Error = Infallible;
1097
1098 async fn basic_async(
1099 &mut self,
1100 _address: Address,
1101 ) -> Result<Option<AccountInfo>, Self::Error> {
1102 Ok(None)
1103 }
1104
1105 async fn code_by_hash_async(&mut self, _code_hash: B256) -> Result<Bytecode, Self::Error> {
1106 Ok(Bytecode::default())
1107 }
1108
1109 async fn storage_async(
1110 &mut self,
1111 _address: Address,
1112 _index: StorageKey,
1113 ) -> Result<StorageValue, Self::Error> {
1114 Ok(StorageValue::from(9))
1115 }
1116
1117 async fn block_hash_async(&mut self, _number: u64) -> Result<B256, Self::Error> {
1118 Ok(B256::ZERO)
1119 }
1120 }
1121
1122 struct PendingDb {
1123 pending: bool,
1124 }
1125
1126 impl DatabaseAsync for PendingDb {
1127 type Error = Infallible;
1128
1129 async fn basic_async(
1130 &mut self,
1131 _address: Address,
1132 ) -> Result<Option<AccountInfo>, Self::Error> {
1133 Ok(None)
1134 }
1135
1136 async fn code_by_hash_async(&mut self, _code_hash: B256) -> Result<Bytecode, Self::Error> {
1137 Ok(Bytecode::default())
1138 }
1139
1140 async fn storage_async(
1141 &mut self,
1142 _address: Address,
1143 _index: StorageKey,
1144 ) -> Result<StorageValue, Self::Error> {
1145 PendingStorage {
1146 pending: &mut self.pending,
1147 }
1148 .await;
1149 Ok(StorageValue::from(9))
1150 }
1151
1152 async fn block_hash_async(&mut self, _number: u64) -> Result<B256, Self::Error> {
1153 Ok(B256::ZERO)
1154 }
1155 }
1156
1157 struct PendingStorage<'a> {
1158 pending: &'a mut bool,
1159 }
1160
1161 impl Future for PendingStorage<'_> {
1162 type Output = ();
1163
1164 fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
1165 if *self.pending {
1166 *self.pending = false;
1167 Poll::Pending
1168 } else {
1169 Poll::Ready(())
1170 }
1171 }
1172 }
1173
1174 struct FailingDb;
1175
1176 impl DatabaseAsync for FailingDb {
1177 type Error = TestError;
1178
1179 async fn basic_async(
1180 &mut self,
1181 _address: Address,
1182 ) -> Result<Option<AccountInfo>, Self::Error> {
1183 Ok(None)
1184 }
1185
1186 async fn code_by_hash_async(&mut self, _code_hash: B256) -> Result<Bytecode, Self::Error> {
1187 Ok(Bytecode::default())
1188 }
1189
1190 async fn storage_async(
1191 &mut self,
1192 _address: Address,
1193 _index: StorageKey,
1194 ) -> Result<StorageValue, Self::Error> {
1195 Err(TestError)
1196 }
1197
1198 async fn block_hash_async(&mut self, _number: u64) -> Result<B256, Self::Error> {
1199 Ok(B256::ZERO)
1200 }
1201 }
1202
1203 struct TokioDb;
1204
1205 impl DatabaseAsync for TokioDb {
1206 type Error = Infallible;
1207
1208 async fn basic_async(
1209 &mut self,
1210 _address: Address,
1211 ) -> Result<Option<AccountInfo>, Self::Error> {
1212 tokio::task::yield_now().await;
1213 Ok(None)
1214 }
1215
1216 async fn code_by_hash_async(&mut self, _code_hash: B256) -> Result<Bytecode, Self::Error> {
1217 tokio::task::yield_now().await;
1218 Ok(Bytecode::default())
1219 }
1220
1221 async fn storage_async(
1222 &mut self,
1223 _address: Address,
1224 _index: StorageKey,
1225 ) -> Result<StorageValue, Self::Error> {
1226 tokio::task::yield_now().await;
1227 Ok(StorageValue::from(9))
1228 }
1229
1230 async fn block_hash_async(&mut self, _number: u64) -> Result<B256, Self::Error> {
1231 tokio::task::yield_now().await;
1232 Ok(B256::ZERO)
1233 }
1234 }
1235
1236 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
1237 struct TestError;
1238
1239 impl fmt::Display for TestError {
1240 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1241 f.write_str("storage read failed")
1242 }
1243 }
1244
1245 impl core::error::Error for TestError {}
1246
1247 impl crate::DBErrorMarker for TestError {}
1248}