@nomicfoundation/edr 0.2.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/.cargo/config.toml +8 -0
  2. package/.mocharc.json +4 -0
  3. package/Cargo.toml +50 -0
  4. package/LICENSE +1 -0
  5. package/artifacts/bindings-aarch64-apple-darwin/edr.darwin-arm64.node +0 -0
  6. package/artifacts/bindings-aarch64-pc-windows-msvc/edr.win32-arm64-msvc.node +0 -0
  7. package/artifacts/bindings-aarch64-unknown-linux-gnu/edr.linux-arm64-gnu.node +0 -0
  8. package/artifacts/bindings-aarch64-unknown-linux-musl/edr.linux-arm64-musl.node +0 -0
  9. package/artifacts/bindings-i686-pc-windows-msvc/edr.win32-ia32-msvc.node +0 -0
  10. package/artifacts/bindings-x86_64-apple-darwin/edr.darwin-x64.node +0 -0
  11. package/artifacts/bindings-x86_64-pc-windows-msvc/edr.win32-x64-msvc.node +0 -0
  12. package/artifacts/bindings-x86_64-unknown-linux-gnu/edr.linux-x64-gnu.node +0 -0
  13. package/artifacts/bindings-x86_64-unknown-linux-musl/edr.linux-x64-musl.node +0 -0
  14. package/build.rs +3 -0
  15. package/index.d.ts +383 -0
  16. package/index.js +264 -0
  17. package/npm/darwin-arm64/README.md +3 -0
  18. package/npm/darwin-arm64/edr.darwin-arm64.node +0 -0
  19. package/npm/darwin-arm64/package.json +22 -0
  20. package/npm/darwin-x64/README.md +3 -0
  21. package/npm/darwin-x64/edr.darwin-x64.node +0 -0
  22. package/npm/darwin-x64/package.json +22 -0
  23. package/npm/linux-arm64-gnu/README.md +3 -0
  24. package/npm/linux-arm64-gnu/edr.linux-arm64-gnu.node +0 -0
  25. package/npm/linux-arm64-gnu/package.json +25 -0
  26. package/npm/linux-arm64-musl/README.md +3 -0
  27. package/npm/linux-arm64-musl/edr.linux-arm64-musl.node +0 -0
  28. package/npm/linux-arm64-musl/package.json +25 -0
  29. package/npm/linux-x64-gnu/README.md +3 -0
  30. package/npm/linux-x64-gnu/edr.linux-x64-gnu.node +0 -0
  31. package/npm/linux-x64-gnu/package.json +25 -0
  32. package/npm/linux-x64-musl/README.md +3 -0
  33. package/npm/linux-x64-musl/edr.linux-x64-musl.node +0 -0
  34. package/npm/linux-x64-musl/package.json +25 -0
  35. package/npm/win32-arm64-msvc/README.md +3 -0
  36. package/npm/win32-arm64-msvc/edr.win32-arm64-msvc.node +0 -0
  37. package/npm/win32-arm64-msvc/package.json +22 -0
  38. package/npm/win32-ia32-msvc/README.md +3 -0
  39. package/npm/win32-ia32-msvc/edr.win32-ia32-msvc.node +0 -0
  40. package/npm/win32-ia32-msvc/package.json +22 -0
  41. package/npm/win32-x64-msvc/README.md +3 -0
  42. package/npm/win32-x64-msvc/edr.win32-x64-msvc.node +0 -0
  43. package/npm/win32-x64-msvc/package.json +22 -0
  44. package/package.json +61 -0
  45. package/src/account.rs +28 -0
  46. package/src/block.rs +110 -0
  47. package/src/cast.rs +119 -0
  48. package/src/config.rs +70 -0
  49. package/src/context.rs +74 -0
  50. package/src/debug_trace.rs +38 -0
  51. package/src/lib.rs +18 -0
  52. package/src/log.rs +41 -0
  53. package/src/logger.rs +1277 -0
  54. package/src/provider/config.rs +271 -0
  55. package/src/provider.rs +185 -0
  56. package/src/result.rs +254 -0
  57. package/src/subscribe.rs +60 -0
  58. package/src/sync.rs +85 -0
  59. package/src/threadsafe_function.rs +305 -0
  60. package/src/trace.rs +168 -0
  61. package/test/provider.ts +104 -0
  62. package/tsconfig.json +17 -0
package/src/block.rs ADDED
@@ -0,0 +1,110 @@
1
+ use edr_eth::{Address, Bytes, B256, B64};
2
+ use napi::bindgen_prelude::{BigInt, Buffer};
3
+ use napi_derive::napi;
4
+
5
+ use crate::cast::TryCast;
6
+
7
+ #[napi(object)]
8
+ pub struct BlockOptions {
9
+ /// The parent block's hash
10
+ pub parent_hash: Option<Buffer>,
11
+ /// The block's beneficiary
12
+ pub beneficiary: Option<Buffer>,
13
+ /// The state's root hash
14
+ pub state_root: Option<Buffer>,
15
+ /// The block's difficulty
16
+ pub difficulty: Option<BigInt>,
17
+ /// The block's number
18
+ pub number: Option<BigInt>,
19
+ /// The block's gas limit
20
+ pub gas_limit: Option<BigInt>,
21
+ /// The block's timestamp
22
+ pub timestamp: Option<BigInt>,
23
+ /// The block's extra data
24
+ pub extra_data: Option<Buffer>,
25
+ /// The block's mix hash (or prevrandao)
26
+ pub mix_hash: Option<Buffer>,
27
+ /// The block's nonce
28
+ pub nonce: Option<Buffer>,
29
+ /// The block's base gas fee
30
+ pub base_fee: Option<BigInt>,
31
+ /// The block's withdrawals root
32
+ pub withdrawals_root: Option<Buffer>,
33
+ /// The hash tree root of the parent beacon block for the given execution
34
+ /// block (EIP-4788).
35
+ pub parent_beacon_block_root: Option<Buffer>,
36
+ }
37
+
38
+ impl TryFrom<BlockOptions> for edr_eth::block::BlockOptions {
39
+ type Error = napi::Error;
40
+
41
+ #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
42
+ fn try_from(value: BlockOptions) -> Result<Self, Self::Error> {
43
+ Ok(Self {
44
+ parent_hash: value
45
+ .parent_hash
46
+ .map(TryCast::<B256>::try_cast)
47
+ .transpose()?,
48
+ beneficiary: value
49
+ .beneficiary
50
+ .map(TryCast::<Address>::try_cast)
51
+ .transpose()?,
52
+ state_root: value
53
+ .state_root
54
+ .map(TryCast::<B256>::try_cast)
55
+ .transpose()?,
56
+ difficulty: value
57
+ .difficulty
58
+ .map_or(Ok(None), |difficulty| difficulty.try_cast().map(Some))?,
59
+ number: value
60
+ .number
61
+ .map_or(Ok(None), |number| number.try_cast().map(Some))?,
62
+ gas_limit: value
63
+ .gas_limit
64
+ .map_or(Ok(None), |gas_limit| gas_limit.try_cast().map(Some))?,
65
+ timestamp: value
66
+ .timestamp
67
+ .map_or(Ok(None), |timestamp| timestamp.try_cast().map(Some))?,
68
+ extra_data: value
69
+ .extra_data
70
+ .map(|extra_data| Bytes::copy_from_slice(&extra_data)),
71
+ mix_hash: value.mix_hash.map(TryCast::<B256>::try_cast).transpose()?,
72
+ nonce: value.nonce.map(TryCast::<B64>::try_cast).transpose()?,
73
+ base_fee: value
74
+ .base_fee
75
+ .map_or(Ok(None), |basefee| basefee.try_cast().map(Some))?,
76
+ withdrawals_root: value
77
+ .withdrawals_root
78
+ .map(TryCast::<B256>::try_cast)
79
+ .transpose()?,
80
+ parent_beacon_block_root: value
81
+ .parent_beacon_block_root
82
+ .map(TryCast::<B256>::try_cast)
83
+ .transpose()?,
84
+ })
85
+ }
86
+ }
87
+
88
+ /// Information about the blob gas used in a block.
89
+ #[napi(object)]
90
+ pub struct BlobGas {
91
+ /// The total amount of blob gas consumed by the transactions within the
92
+ /// block.
93
+ pub gas_used: BigInt,
94
+ /// The running total of blob gas consumed in excess of the target, prior to
95
+ /// the block. Blocks with above-target blob gas consumption increase this
96
+ /// value, blocks with below-target blob gas consumption decrease it
97
+ /// (bounded at 0).
98
+ pub excess_gas: BigInt,
99
+ }
100
+
101
+ impl TryFrom<BlobGas> for edr_eth::block::BlobGas {
102
+ type Error = napi::Error;
103
+
104
+ fn try_from(value: BlobGas) -> Result<Self, Self::Error> {
105
+ Ok(Self {
106
+ gas_used: BigInt::try_cast(value.gas_used)?,
107
+ excess_gas: BigInt::try_cast(value.excess_gas)?,
108
+ })
109
+ }
110
+ }
package/src/cast.rs ADDED
@@ -0,0 +1,119 @@
1
+ use edr_eth::{Address, B256, B64, U256};
2
+ use napi::{
3
+ bindgen_prelude::{BigInt, Buffer},
4
+ Status,
5
+ };
6
+
7
+ /// An attempted conversion that consumes `self`, which may or may not be
8
+ /// expensive. It is identical to [`TryInto`], but it allows us to implement
9
+ /// the trait for external types.
10
+ pub trait TryCast<T>: Sized {
11
+ /// The type returned in the event of a conversion error.
12
+ type Error;
13
+
14
+ /// Performs the conversion.
15
+ fn try_cast(self) -> Result<T, Self::Error>;
16
+ }
17
+
18
+ impl TryCast<Address> for Buffer {
19
+ type Error = napi::Error;
20
+
21
+ fn try_cast(self) -> std::result::Result<Address, Self::Error> {
22
+ if self.len() != 20 {
23
+ return Err(napi::Error::new(
24
+ Status::InvalidArg,
25
+ "Buffer was expected to be 20 bytes.".to_string(),
26
+ ));
27
+ }
28
+ Ok(Address::from_slice(&self))
29
+ }
30
+ }
31
+
32
+ impl TryCast<B64> for Buffer {
33
+ type Error = napi::Error;
34
+
35
+ fn try_cast(self) -> std::result::Result<B64, Self::Error> {
36
+ if self.len() != 8 {
37
+ return Err(napi::Error::new(
38
+ Status::InvalidArg,
39
+ "Buffer was expected to be 8 bytes.".to_string(),
40
+ ));
41
+ }
42
+ Ok(B64::from_slice(&self))
43
+ }
44
+ }
45
+
46
+ impl TryCast<B256> for Buffer {
47
+ type Error = napi::Error;
48
+
49
+ fn try_cast(self) -> std::result::Result<B256, Self::Error> {
50
+ if self.len() != 32 {
51
+ return Err(napi::Error::new(
52
+ Status::InvalidArg,
53
+ "Buffer was expected to be 32 bytes.".to_string(),
54
+ ));
55
+ }
56
+ Ok(B256::from_slice(&self))
57
+ }
58
+ }
59
+
60
+ impl TryCast<u64> for BigInt {
61
+ type Error = napi::Error;
62
+
63
+ fn try_cast(self) -> std::result::Result<u64, Self::Error> {
64
+ let (signed, value, lossless) = self.get_u64();
65
+
66
+ if signed {
67
+ return Err(napi::Error::new(
68
+ Status::InvalidArg,
69
+ "BigInt was expected to be unsigned.".to_string(),
70
+ ));
71
+ }
72
+
73
+ if !lossless {
74
+ return Err(napi::Error::new(
75
+ Status::InvalidArg,
76
+ "BigInt was expected to fit within 64 bits.".to_string(),
77
+ ));
78
+ }
79
+
80
+ Ok(value)
81
+ }
82
+ }
83
+
84
+ impl TryCast<usize> for BigInt {
85
+ type Error = napi::Error;
86
+
87
+ fn try_cast(self) -> std::result::Result<usize, Self::Error> {
88
+ let size: u64 = BigInt::try_cast(self)?;
89
+ usize::try_from(size).map_err(|e| napi::Error::new(Status::InvalidArg, e.to_string()))
90
+ }
91
+ }
92
+
93
+ impl TryCast<U256> for BigInt {
94
+ type Error = napi::Error;
95
+
96
+ fn try_cast(mut self) -> std::result::Result<U256, Self::Error> {
97
+ let num_words = self.words.len();
98
+ match num_words.cmp(&4) {
99
+ std::cmp::Ordering::Less => self.words.append(&mut vec![0u64; 4 - num_words]),
100
+ std::cmp::Ordering::Equal => (),
101
+ std::cmp::Ordering::Greater => {
102
+ return Err(napi::Error::new(
103
+ Status::InvalidArg,
104
+ "BigInt cannot have more than 4 words.".to_owned(),
105
+ ));
106
+ }
107
+ }
108
+
109
+ Ok(U256::from_limbs(self.words.try_into().unwrap()))
110
+ }
111
+ }
112
+
113
+ impl<T> TryCast<T> for T {
114
+ type Error = napi::Error;
115
+
116
+ fn try_cast(self) -> std::result::Result<T, Self::Error> {
117
+ Ok(self)
118
+ }
119
+ }
package/src/config.rs ADDED
@@ -0,0 +1,70 @@
1
+ use napi_derive::napi;
2
+
3
+ /// Identifier for the Ethereum spec.
4
+ #[napi]
5
+ pub enum SpecId {
6
+ /// Frontier
7
+ Frontier = 0,
8
+ /// Frontier Thawing
9
+ FrontierThawing = 1,
10
+ /// Homestead
11
+ Homestead = 2,
12
+ /// DAO Fork
13
+ DaoFork = 3,
14
+ /// Tangerine
15
+ Tangerine = 4,
16
+ /// Spurious Dragon
17
+ SpuriousDragon = 5,
18
+ /// Byzantium
19
+ Byzantium = 6,
20
+ /// Constantinople
21
+ Constantinople = 7,
22
+ /// Petersburg
23
+ Petersburg = 8,
24
+ /// Istanbul
25
+ Istanbul = 9,
26
+ /// Muir Glacier
27
+ MuirGlacier = 10,
28
+ /// Berlin
29
+ Berlin = 11,
30
+ /// London
31
+ London = 12,
32
+ /// Arrow Glacier
33
+ ArrowGlacier = 13,
34
+ /// Gray Glacier
35
+ GrayGlacier = 14,
36
+ /// Merge
37
+ Merge = 15,
38
+ /// Shanghai
39
+ Shanghai = 16,
40
+ /// Cancun
41
+ Cancun = 17,
42
+ /// Latest
43
+ Latest = 18,
44
+ }
45
+
46
+ impl From<SpecId> for edr_evm::SpecId {
47
+ fn from(value: SpecId) -> Self {
48
+ match value {
49
+ SpecId::Frontier => edr_evm::SpecId::FRONTIER,
50
+ SpecId::FrontierThawing => edr_evm::SpecId::FRONTIER_THAWING,
51
+ SpecId::Homestead => edr_evm::SpecId::HOMESTEAD,
52
+ SpecId::DaoFork => edr_evm::SpecId::DAO_FORK,
53
+ SpecId::Tangerine => edr_evm::SpecId::TANGERINE,
54
+ SpecId::SpuriousDragon => edr_evm::SpecId::SPURIOUS_DRAGON,
55
+ SpecId::Byzantium => edr_evm::SpecId::BYZANTIUM,
56
+ SpecId::Constantinople => edr_evm::SpecId::CONSTANTINOPLE,
57
+ SpecId::Petersburg => edr_evm::SpecId::PETERSBURG,
58
+ SpecId::Istanbul => edr_evm::SpecId::ISTANBUL,
59
+ SpecId::MuirGlacier => edr_evm::SpecId::MUIR_GLACIER,
60
+ SpecId::Berlin => edr_evm::SpecId::BERLIN,
61
+ SpecId::London => edr_evm::SpecId::LONDON,
62
+ SpecId::ArrowGlacier => edr_evm::SpecId::ARROW_GLACIER,
63
+ SpecId::GrayGlacier => edr_evm::SpecId::GRAY_GLACIER,
64
+ SpecId::Merge => edr_evm::SpecId::MERGE,
65
+ SpecId::Shanghai => edr_evm::SpecId::SHANGHAI,
66
+ SpecId::Cancun => edr_evm::SpecId::CANCUN,
67
+ SpecId::Latest => edr_evm::SpecId::LATEST,
68
+ }
69
+ }
70
+ }
package/src/context.rs ADDED
@@ -0,0 +1,74 @@
1
+ use std::{io, ops::Deref, sync::Arc};
2
+
3
+ use napi::Status;
4
+ use napi_derive::napi;
5
+ use tracing_subscriber::{prelude::*, EnvFilter, Registry};
6
+
7
+ #[napi]
8
+ #[derive(Debug)]
9
+ pub struct EdrContext {
10
+ inner: Arc<Context>,
11
+ }
12
+
13
+ impl Deref for EdrContext {
14
+ type Target = Arc<Context>;
15
+
16
+ fn deref(&self) -> &Self::Target {
17
+ &self.inner
18
+ }
19
+ }
20
+
21
+ #[napi]
22
+ impl EdrContext {
23
+ #[doc = "Creates a new [`EdrContext`] instance. Should only be called once!"]
24
+ #[napi(constructor)]
25
+ pub fn new() -> napi::Result<Self> {
26
+ let context =
27
+ Context::new().map_err(|e| napi::Error::new(Status::GenericFailure, e.to_string()))?;
28
+
29
+ Ok(Self {
30
+ inner: Arc::new(context),
31
+ })
32
+ }
33
+ }
34
+
35
+ #[derive(Debug)]
36
+ pub struct Context {
37
+ #[cfg(feature = "tracing")]
38
+ _tracing_write_guard: tracing_flame::FlushGuard<std::io::BufWriter<std::fs::File>>,
39
+ }
40
+
41
+ impl Context {
42
+ /// Creates a new [`Context`] instance. Should only be called once!
43
+ pub fn new() -> io::Result<Self> {
44
+ let fmt_layer = tracing_subscriber::fmt::layer()
45
+ .with_file(true)
46
+ .with_line_number(true)
47
+ .with_thread_ids(true)
48
+ .with_target(false)
49
+ .with_level(true)
50
+ .with_filter(EnvFilter::from_default_env());
51
+
52
+ let subscriber = Registry::default().with(fmt_layer);
53
+
54
+ #[cfg(feature = "tracing")]
55
+ let (flame_layer, guard) = {
56
+ let (flame_layer, guard) =
57
+ tracing_flame::FlameLayer::with_file("tracing.folded").unwrap();
58
+
59
+ let flame_layer = flame_layer.with_empty_samples(false);
60
+ (flame_layer, guard)
61
+ };
62
+
63
+ #[cfg(feature = "tracing")]
64
+ let subscriber = subscriber.with(flame_layer);
65
+
66
+ tracing::subscriber::set_global_default(subscriber)
67
+ .expect("Could not set global default tracing subscriber");
68
+
69
+ Ok(Self {
70
+ #[cfg(feature = "tracing")]
71
+ _tracing_write_guard: guard,
72
+ })
73
+ }
74
+ }
@@ -0,0 +1,38 @@
1
+ use std::collections::HashMap;
2
+
3
+ use napi::bindgen_prelude::{BigInt, Buffer};
4
+ use napi_derive::napi;
5
+
6
+ #[napi(object)]
7
+ pub struct DebugTraceResult {
8
+ pub pass: bool,
9
+ pub gas_used: BigInt,
10
+ pub output: Option<Buffer>,
11
+ pub struct_logs: Vec<DebugTraceLogItem>,
12
+ }
13
+
14
+ #[napi(object)]
15
+ pub struct DebugTraceLogItem {
16
+ /// Program Counter
17
+ pub pc: BigInt,
18
+ // Op code
19
+ pub op: u8,
20
+ /// Gas left before executing this operation as hex number.
21
+ pub gas: String,
22
+ /// Gas cost of this operation as hex number.
23
+ pub gas_cost: String,
24
+ /// Array of all values (hex numbers) on the stack
25
+ pub stack: Option<Vec<String>>,
26
+ /// Depth of the call stack
27
+ pub depth: BigInt,
28
+ /// Size of memory array
29
+ pub mem_size: BigInt,
30
+ /// Name of the operation
31
+ pub op_name: String,
32
+ /// Description of an error as a hex string.
33
+ pub error: Option<String>,
34
+ /// Array of all allocated values as hex strings.
35
+ pub memory: Option<Vec<String>>,
36
+ /// Map of all stored values with keys and values encoded as hex strings.
37
+ pub storage: Option<HashMap<String, String>>,
38
+ }
package/src/lib.rs ADDED
@@ -0,0 +1,18 @@
1
+ #![warn(missing_docs)]
2
+
3
+ //! NAPI bindings for the EDR EVM
4
+
5
+ mod account;
6
+ mod block;
7
+ mod cast;
8
+ mod config;
9
+ mod context;
10
+ mod debug_trace;
11
+ mod log;
12
+ mod logger;
13
+ mod provider;
14
+ mod result;
15
+ mod subscribe;
16
+ mod sync;
17
+ mod threadsafe_function;
18
+ mod trace;
package/src/log.rs ADDED
@@ -0,0 +1,41 @@
1
+ use std::mem;
2
+
3
+ use napi::{bindgen_prelude::Buffer, Env, JsBuffer, JsBufferValue};
4
+ use napi_derive::napi;
5
+
6
+ /// Ethereum execution log.
7
+ #[napi(object)]
8
+ pub struct ExecutionLog {
9
+ pub address: Buffer,
10
+ pub topics: Vec<Buffer>,
11
+ pub data: JsBuffer,
12
+ }
13
+
14
+ impl ExecutionLog {
15
+ pub fn new(env: &Env, log: &edr_evm::Log) -> napi::Result<Self> {
16
+ let topics = log
17
+ .topics
18
+ .iter()
19
+ .map(|topic| Buffer::from(topic.as_slice()))
20
+ .collect();
21
+
22
+ let data = log.data.clone();
23
+ let data = unsafe {
24
+ env.create_buffer_with_borrowed_data(
25
+ data.as_ptr(),
26
+ data.len(),
27
+ data,
28
+ |data: edr_eth::Bytes, _env| {
29
+ mem::drop(data);
30
+ },
31
+ )
32
+ }
33
+ .map(JsBufferValue::into_raw)?;
34
+
35
+ Ok(Self {
36
+ address: Buffer::from(log.address.as_slice()),
37
+ topics,
38
+ data,
39
+ })
40
+ }
41
+ }