mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: add transaction validation task (#3358)
This commit is contained in:
369
Cargo.lock
generated
369
Cargo.lock
generated
@ -324,12 +324,6 @@ dependencies = [
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base16ct"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce"
|
||||
|
||||
[[package]]
|
||||
name = "base16ct"
|
||||
version = "0.2.0"
|
||||
@ -437,9 +431,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.3.1"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6776fc96284a0bb647b615056fc496d1fe1644a7ab01829818a6d91cae888b84"
|
||||
checksum = "6dbe3c979c178231552ecba20214a8272df4e09f232a87aef4320cf06539aded"
|
||||
|
||||
[[package]]
|
||||
name = "bitvec"
|
||||
@ -494,9 +488,9 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "boa_ast"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/boa-dev/boa#da4a3315d75680e63ce2a2dba66000ef2e0e50b9"
|
||||
source = "git+https://github.com/boa-dev/boa#0e1b32a232109fc0e192c1297a7274091af2ac61"
|
||||
dependencies = [
|
||||
"bitflags 2.3.1",
|
||||
"bitflags 2.3.2",
|
||||
"boa_interner",
|
||||
"boa_macros",
|
||||
"indexmap",
|
||||
@ -507,9 +501,9 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "boa_engine"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/boa-dev/boa#da4a3315d75680e63ce2a2dba66000ef2e0e50b9"
|
||||
source = "git+https://github.com/boa-dev/boa#0e1b32a232109fc0e192c1297a7274091af2ac61"
|
||||
dependencies = [
|
||||
"bitflags 2.3.1",
|
||||
"bitflags 2.3.2",
|
||||
"boa_ast",
|
||||
"boa_gc",
|
||||
"boa_icu_provider",
|
||||
@ -545,7 +539,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "boa_gc"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/boa-dev/boa#da4a3315d75680e63ce2a2dba66000ef2e0e50b9"
|
||||
source = "git+https://github.com/boa-dev/boa#0e1b32a232109fc0e192c1297a7274091af2ac61"
|
||||
dependencies = [
|
||||
"boa_macros",
|
||||
"boa_profiler",
|
||||
@ -555,7 +549,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "boa_icu_provider"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/boa-dev/boa#da4a3315d75680e63ce2a2dba66000ef2e0e50b9"
|
||||
source = "git+https://github.com/boa-dev/boa#0e1b32a232109fc0e192c1297a7274091af2ac61"
|
||||
dependencies = [
|
||||
"icu_collections",
|
||||
"icu_normalizer",
|
||||
@ -568,7 +562,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "boa_interner"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/boa-dev/boa#da4a3315d75680e63ce2a2dba66000ef2e0e50b9"
|
||||
source = "git+https://github.com/boa-dev/boa#0e1b32a232109fc0e192c1297a7274091af2ac61"
|
||||
dependencies = [
|
||||
"boa_gc",
|
||||
"boa_macros",
|
||||
@ -583,7 +577,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "boa_macros"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/boa-dev/boa#da4a3315d75680e63ce2a2dba66000ef2e0e50b9"
|
||||
source = "git+https://github.com/boa-dev/boa#0e1b32a232109fc0e192c1297a7274091af2ac61"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.60",
|
||||
"quote 1.0.28",
|
||||
@ -594,9 +588,9 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "boa_parser"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/boa-dev/boa#da4a3315d75680e63ce2a2dba66000ef2e0e50b9"
|
||||
source = "git+https://github.com/boa-dev/boa#0e1b32a232109fc0e192c1297a7274091af2ac61"
|
||||
dependencies = [
|
||||
"bitflags 2.3.1",
|
||||
"bitflags 2.3.2",
|
||||
"boa_ast",
|
||||
"boa_icu_provider",
|
||||
"boa_interner",
|
||||
@ -614,7 +608,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "boa_profiler"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/boa-dev/boa#da4a3315d75680e63ce2a2dba66000ef2e0e50b9"
|
||||
source = "git+https://github.com/boa-dev/boa#0e1b32a232109fc0e192c1297a7274091af2ac61"
|
||||
|
||||
[[package]]
|
||||
name = "brotli"
|
||||
@ -936,7 +930,7 @@ dependencies = [
|
||||
"digest 0.10.6",
|
||||
"getrandom 0.2.9",
|
||||
"hmac",
|
||||
"k256 0.13.1",
|
||||
"k256",
|
||||
"lazy_static",
|
||||
"serde",
|
||||
"sha2 0.10.6",
|
||||
@ -1212,18 +1206,6 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-bigint"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-bigint"
|
||||
version = "0.5.1"
|
||||
@ -1276,13 +1258,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "curve25519-dalek"
|
||||
version = "3.2.0"
|
||||
version = "4.0.0-rc.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61"
|
||||
checksum = "03d928d978dbec61a1167414f5ec534f24bea0d7a0d24dd9b6233d3d8223e585"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"digest 0.9.0",
|
||||
"rand_core 0.5.1",
|
||||
"cfg-if",
|
||||
"digest 0.10.6",
|
||||
"fiat-crypto",
|
||||
"packed_simd_2",
|
||||
"platforms",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
@ -1471,17 +1455,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4355c25cbf99edcb6b4a0e906f6bdc6956eda149e84455bea49696429b2f8e8"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"tokio-util 0.7.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "der"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"zeroize",
|
||||
"tokio-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1628,14 +1602,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "discv5"
|
||||
version = "0.2.2"
|
||||
source = "git+https://github.com/sigp/discv5#d86707d79c1183b14b8cf31ef62a8a74ef9cd3e4"
|
||||
version = "0.3.0"
|
||||
source = "git+https://github.com/sigp/discv5#47844ca54e8d22f4fd3db4594645e65afb288bb6"
|
||||
dependencies = [
|
||||
"aes 0.7.5",
|
||||
"aes-gcm",
|
||||
"arrayvec",
|
||||
"delay_map",
|
||||
"enr 0.7.0",
|
||||
"enr",
|
||||
"fnv",
|
||||
"futures",
|
||||
"hashlink",
|
||||
@ -1650,8 +1624,6 @@ dependencies = [
|
||||
"smallvec",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util 0.6.10",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"uint",
|
||||
@ -1699,51 +1671,40 @@ version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30"
|
||||
|
||||
[[package]]
|
||||
name = "ecdsa"
|
||||
version = "0.14.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c"
|
||||
dependencies = [
|
||||
"der 0.6.1",
|
||||
"elliptic-curve 0.12.3",
|
||||
"rfc6979 0.3.1",
|
||||
"signature 1.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ecdsa"
|
||||
version = "0.16.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a48e5d537b8a30c0b023116d981b16334be1485af7ca68db3a2b7024cbc957fd"
|
||||
dependencies = [
|
||||
"der 0.7.3",
|
||||
"der",
|
||||
"digest 0.10.6",
|
||||
"elliptic-curve 0.13.4",
|
||||
"rfc6979 0.4.0",
|
||||
"signature 2.1.0",
|
||||
"elliptic-curve",
|
||||
"rfc6979",
|
||||
"signature",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ed25519"
|
||||
version = "1.5.3"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7"
|
||||
checksum = "5fb04eee5d9d907f29e80ee6b0e78f7e2c82342c63e3580d8c4f69d9d5aad963"
|
||||
dependencies = [
|
||||
"signature 1.6.4",
|
||||
"pkcs8",
|
||||
"signature",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ed25519-dalek"
|
||||
version = "1.0.1"
|
||||
version = "2.0.0-rc.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d"
|
||||
checksum = "798f704d128510932661a3489b08e3f4c934a01d61c5def59ae7b8e48f19665a"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"ed25519",
|
||||
"rand 0.7.3",
|
||||
"rand_core 0.6.4",
|
||||
"serde",
|
||||
"sha2 0.9.9",
|
||||
"sha2 0.10.6",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
@ -1784,41 +1745,21 @@ version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
||||
|
||||
[[package]]
|
||||
name = "elliptic-curve"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3"
|
||||
dependencies = [
|
||||
"base16ct 0.1.1",
|
||||
"crypto-bigint 0.4.9",
|
||||
"der 0.6.1",
|
||||
"digest 0.10.6",
|
||||
"ff 0.12.1",
|
||||
"generic-array",
|
||||
"group 0.12.1",
|
||||
"pkcs8 0.9.0",
|
||||
"rand_core 0.6.4",
|
||||
"sec1 0.3.0",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "elliptic-curve"
|
||||
version = "0.13.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75c71eaa367f2e5d556414a8eea812bc62985c879748d6403edabd9cb03f16e7"
|
||||
dependencies = [
|
||||
"base16ct 0.2.0",
|
||||
"crypto-bigint 0.5.1",
|
||||
"base16ct",
|
||||
"crypto-bigint",
|
||||
"digest 0.10.6",
|
||||
"ff 0.13.0",
|
||||
"ff",
|
||||
"generic-array",
|
||||
"group 0.13.0",
|
||||
"pkcs8 0.10.2",
|
||||
"group",
|
||||
"pkcs8",
|
||||
"rand_core 0.6.4",
|
||||
"sec1 0.7.2",
|
||||
"sec1",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
@ -1844,26 +1785,6 @@ version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
|
||||
|
||||
[[package]]
|
||||
name = "enr"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "492a7e5fc2504d5fdce8e124d3e263b244a68b283cac67a69eda0cd43e0aebad"
|
||||
dependencies = [
|
||||
"base64 0.13.1",
|
||||
"bs58",
|
||||
"bytes",
|
||||
"ed25519-dalek",
|
||||
"hex",
|
||||
"k256 0.11.6",
|
||||
"log",
|
||||
"rand 0.8.5",
|
||||
"rlp",
|
||||
"serde",
|
||||
"sha3",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enr"
|
||||
version = "0.8.1"
|
||||
@ -1872,8 +1793,9 @@ checksum = "cf56acd72bb22d2824e66ae8e9e5ada4d0de17a69c7fd35569dde2ada8ec9116"
|
||||
dependencies = [
|
||||
"base64 0.13.1",
|
||||
"bytes",
|
||||
"ed25519-dalek",
|
||||
"hex",
|
||||
"k256 0.13.1",
|
||||
"k256",
|
||||
"log",
|
||||
"rand 0.8.5",
|
||||
"rlp",
|
||||
@ -2101,11 +2023,11 @@ dependencies = [
|
||||
"bytes",
|
||||
"cargo_metadata",
|
||||
"chrono",
|
||||
"elliptic-curve 0.13.4",
|
||||
"elliptic-curve",
|
||||
"ethabi",
|
||||
"generic-array",
|
||||
"hex",
|
||||
"k256 0.13.1",
|
||||
"k256",
|
||||
"num_enum",
|
||||
"once_cell",
|
||||
"open-fastrlp",
|
||||
@ -2173,7 +2095,7 @@ dependencies = [
|
||||
"auto_impl",
|
||||
"base64 0.21.0",
|
||||
"bytes",
|
||||
"enr 0.8.1",
|
||||
"enr",
|
||||
"ethers-core",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@ -2209,7 +2131,7 @@ dependencies = [
|
||||
"async-trait",
|
||||
"coins-bip32",
|
||||
"coins-bip39",
|
||||
"elliptic-curve 0.13.4",
|
||||
"elliptic-curve",
|
||||
"eth-keystore",
|
||||
"ethers-core",
|
||||
"hex",
|
||||
@ -2265,16 +2187,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ff"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160"
|
||||
dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ff"
|
||||
version = "0.13.0"
|
||||
@ -2285,6 +2197,12 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fiat-crypto"
|
||||
version = "0.1.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77"
|
||||
|
||||
[[package]]
|
||||
name = "findshlibs"
|
||||
version = "0.10.2"
|
||||
@ -2588,24 +2506,13 @@ dependencies = [
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "group"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7"
|
||||
dependencies = [
|
||||
"ff 0.12.1",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "group"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
|
||||
dependencies = [
|
||||
"ff 0.13.0",
|
||||
"ff",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
]
|
||||
@ -2625,7 +2532,7 @@ dependencies = [
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util 0.7.7",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
@ -3322,7 +3229,7 @@ dependencies = [
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tokio-util 0.7.7",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
"webpki-roots",
|
||||
]
|
||||
@ -3402,7 +3309,7 @@ dependencies = [
|
||||
"soketto",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util 0.7.7",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
"tracing",
|
||||
]
|
||||
@ -3458,18 +3365,6 @@ dependencies = [
|
||||
"simple_asn1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "k256"
|
||||
version = "0.11.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"ecdsa 0.14.8",
|
||||
"elliptic-curve 0.12.3",
|
||||
"sha2 0.10.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "k256"
|
||||
version = "0.13.1"
|
||||
@ -3477,11 +3372,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"ecdsa 0.16.6",
|
||||
"elliptic-curve 0.13.4",
|
||||
"ecdsa",
|
||||
"elliptic-curve",
|
||||
"once_cell",
|
||||
"sha2 0.10.6",
|
||||
"signature 2.1.0",
|
||||
"signature",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3524,6 +3419,12 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.6"
|
||||
@ -3981,7 +3882,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"libm",
|
||||
"libm 0.2.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4107,6 +4008,16 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "packed_simd_2"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libm 0.1.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "page_size"
|
||||
version = "0.4.2"
|
||||
@ -4336,24 +4247,14 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkcs8"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba"
|
||||
dependencies = [
|
||||
"der 0.6.1",
|
||||
"spki 0.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkcs8"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
|
||||
dependencies = [
|
||||
"der 0.7.3",
|
||||
"spki 0.7.1",
|
||||
"der",
|
||||
"spki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4371,6 +4272,12 @@ dependencies = [
|
||||
"crunchy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "platforms"
|
||||
version = "3.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630"
|
||||
|
||||
[[package]]
|
||||
name = "plotters"
|
||||
version = "0.3.4"
|
||||
@ -5164,7 +5071,7 @@ name = "reth-discv4"
|
||||
version = "0.1.0-alpha.1"
|
||||
dependencies = [
|
||||
"discv5",
|
||||
"enr 0.8.1",
|
||||
"enr",
|
||||
"generic-array",
|
||||
"hex",
|
||||
"rand 0.8.5",
|
||||
@ -5188,7 +5095,7 @@ version = "0.1.0-alpha.1"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"data-encoding",
|
||||
"enr 0.8.1",
|
||||
"enr",
|
||||
"linked_hash_set",
|
||||
"parking_lot 0.12.1",
|
||||
"reth-net-common",
|
||||
@ -5227,7 +5134,7 @@ dependencies = [
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util 0.7.7",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
@ -5257,7 +5164,7 @@ dependencies = [
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util 0.7.7",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
"typenum",
|
||||
]
|
||||
@ -5291,7 +5198,7 @@ dependencies = [
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util 0.7.7",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
@ -5336,7 +5243,7 @@ dependencies = [
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util 0.7.7",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
"tracing",
|
||||
"tracing-test",
|
||||
@ -5425,7 +5332,7 @@ dependencies = [
|
||||
"aquamarine",
|
||||
"async-trait",
|
||||
"auto_impl",
|
||||
"enr 0.8.1",
|
||||
"enr",
|
||||
"ethers-core",
|
||||
"ethers-middleware",
|
||||
"ethers-providers",
|
||||
@ -5464,7 +5371,7 @@ dependencies = [
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util 0.7.7",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
@ -5670,7 +5577,7 @@ dependencies = [
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util 0.7.7",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
"tracing",
|
||||
"tracing-futures",
|
||||
@ -5775,7 +5682,7 @@ dependencies = [
|
||||
"assert_matches",
|
||||
"async-trait",
|
||||
"confy",
|
||||
"enr 0.8.1",
|
||||
"enr",
|
||||
"ethers-core",
|
||||
"ethers-middleware",
|
||||
"ethers-providers",
|
||||
@ -5882,9 +5789,11 @@ dependencies = [
|
||||
"reth-primitives",
|
||||
"reth-provider",
|
||||
"reth-rlp",
|
||||
"reth-tasks",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
@ -5934,7 +5843,7 @@ name = "revm-precompile"
|
||||
version = "2.0.3"
|
||||
source = "git+https://github.com/bluealloy/revm/?branch=release/v25#88337924f4d16ed1f5e4cde12a03d0cb755cd658"
|
||||
dependencies = [
|
||||
"k256 0.13.1",
|
||||
"k256",
|
||||
"num",
|
||||
"once_cell",
|
||||
"revm-primitives",
|
||||
@ -5969,17 +5878,6 @@ dependencies = [
|
||||
"sha3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rfc6979"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb"
|
||||
dependencies = [
|
||||
"crypto-bigint 0.4.9",
|
||||
"hmac",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rfc6979"
|
||||
version = "0.4.0"
|
||||
@ -6290,30 +6188,16 @@ dependencies = [
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sec1"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928"
|
||||
dependencies = [
|
||||
"base16ct 0.1.1",
|
||||
"der 0.6.1",
|
||||
"generic-array",
|
||||
"pkcs8 0.9.0",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sec1"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0aec48e813d6b90b15f0b8948af3c63483992dee44c03e9930b3eebdabe046e"
|
||||
dependencies = [
|
||||
"base16ct 0.2.0",
|
||||
"der 0.7.3",
|
||||
"base16ct",
|
||||
"der",
|
||||
"generic-array",
|
||||
"pkcs8 0.10.2",
|
||||
"pkcs8",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
@ -6619,16 +6503,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signature"
|
||||
version = "1.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
|
||||
dependencies = [
|
||||
"digest 0.10.6",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signature"
|
||||
version = "2.1.0"
|
||||
@ -6754,16 +6628,6 @@ dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spki"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"der 0.6.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spki"
|
||||
version = "0.7.1"
|
||||
@ -6771,7 +6635,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37a5be806ab6f127c3da44b7378837ebf01dadca8510a0e572460216b228bd0e"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"der 0.7.3",
|
||||
"der",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -7203,7 +7067,7 @@ dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tokio-util 0.7.7",
|
||||
"tokio-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -7218,21 +7082,6 @@ dependencies = [
|
||||
"tungstenite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.6.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"slab",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.7"
|
||||
@ -7320,7 +7169,7 @@ dependencies = [
|
||||
"rand 0.8.5",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util 0.7.7",
|
||||
"tokio-util",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
@ -7348,7 +7197,7 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tokio-util 0.7.7",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
@ -7682,9 +7531,9 @@ checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.8"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
|
||||
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
|
||||
@ -114,10 +114,10 @@ tokio = { version = "1.21", default-features = false }
|
||||
tokio-util = { version = "0.7.4", features = ["codec"] }
|
||||
|
||||
## async
|
||||
async-trait = "0.1.58"
|
||||
async-trait = "0.1.68"
|
||||
futures = "0.3.26"
|
||||
pin-project = "1.0.12"
|
||||
futures-util = "0.3.25"
|
||||
|
||||
## crypto
|
||||
secp256k1 = { version = "0.27.0", default-features = false, features = ["global-context", "rand-std", "recovery"] }
|
||||
secp256k1 = { version = "0.27.0", default-features = false, features = ["global-context", "rand-std", "recovery"] }
|
||||
|
||||
@ -206,7 +206,12 @@ impl Command {
|
||||
let blockchain_db = BlockchainProvider::new(factory, blockchain_tree.clone())?;
|
||||
|
||||
let transaction_pool = reth_transaction_pool::Pool::eth_pool(
|
||||
EthTransactionValidator::new(blockchain_db.clone(), Arc::clone(&self.chain)),
|
||||
EthTransactionValidator::new(
|
||||
blockchain_db.clone(),
|
||||
Arc::clone(&self.chain),
|
||||
ctx.task_executor.clone(),
|
||||
1,
|
||||
),
|
||||
Default::default(),
|
||||
);
|
||||
info!(target: "reth::cli", "Transaction pool initialized");
|
||||
@ -218,14 +223,11 @@ impl Command {
|
||||
let client = blockchain_db.clone();
|
||||
ctx.task_executor.spawn_critical(
|
||||
"txpool maintenance task",
|
||||
Box::pin(async move {
|
||||
reth_transaction_pool::maintain::maintain_transaction_pool(
|
||||
client,
|
||||
pool,
|
||||
chain_events,
|
||||
)
|
||||
.await
|
||||
}),
|
||||
reth_transaction_pool::maintain::maintain_transaction_pool_future(
|
||||
client,
|
||||
pool,
|
||||
chain_events,
|
||||
),
|
||||
);
|
||||
debug!(target: "reth::cli", "Spawned txpool maintenance task");
|
||||
}
|
||||
|
||||
@ -23,12 +23,14 @@ reth-provider = { workspace = true }
|
||||
reth-interfaces = { workspace = true }
|
||||
reth-rlp = { workspace = true }
|
||||
reth-metrics = { workspace = true }
|
||||
reth-tasks = { workspace = true }
|
||||
|
||||
# async/futures
|
||||
async-trait = { workspace = true}
|
||||
futures-util = { workspace = true }
|
||||
parking_lot = "0.12"
|
||||
tokio = { workspace = true, default-features = false, features = ["sync"] }
|
||||
tokio-stream.workspace = true
|
||||
|
||||
# misc
|
||||
aquamarine = "0.3.0"
|
||||
|
||||
@ -116,7 +116,7 @@ pub mod metrics;
|
||||
mod ordering;
|
||||
pub mod pool;
|
||||
mod traits;
|
||||
mod validate;
|
||||
pub mod validate;
|
||||
|
||||
#[cfg(any(test, feature = "test-utils"))]
|
||||
/// Common test helpers for mocking A pool
|
||||
@ -222,7 +222,7 @@ where
|
||||
impl<Client>
|
||||
Pool<EthTransactionValidator<Client, PooledTransaction>, CostOrdering<PooledTransaction>>
|
||||
where
|
||||
Client: StateProviderFactory,
|
||||
Client: StateProviderFactory + Clone + 'static,
|
||||
{
|
||||
/// Returns a new [Pool] that uses the default [EthTransactionValidator] when validating
|
||||
/// [PooledTransaction]s and ords via [CostOrdering]
|
||||
|
||||
@ -4,7 +4,7 @@ use crate::{
|
||||
traits::{CanonicalStateUpdate, ChangedAccount},
|
||||
BlockInfo, Pool, TransactionOrdering, TransactionPool, TransactionValidator,
|
||||
};
|
||||
use futures_util::{Stream, StreamExt};
|
||||
use futures_util::{future::BoxFuture, FutureExt, Stream, StreamExt};
|
||||
use reth_primitives::{Address, BlockHash, BlockNumberOrTag, FromRecoveredTransaction};
|
||||
use reth_provider::{BlockProviderIdExt, CanonStateNotification, PostState, StateProviderFactory};
|
||||
use std::{
|
||||
@ -18,6 +18,24 @@ use tracing::debug;
|
||||
/// last_seen.number`
|
||||
const MAX_UPDATE_DEPTH: u64 = 64;
|
||||
|
||||
/// Returns a spawnable future for maintaining the state of the transaction pool.
|
||||
pub fn maintain_transaction_pool_future<Client, V, T, St>(
|
||||
client: Client,
|
||||
pool: Pool<V, T>,
|
||||
events: St,
|
||||
) -> BoxFuture<'static, ()>
|
||||
where
|
||||
Client: StateProviderFactory + BlockProviderIdExt + Send + 'static,
|
||||
V: TransactionValidator + Send + 'static,
|
||||
T: TransactionOrdering<Transaction = <V as TransactionValidator>::Transaction> + Send + 'static,
|
||||
St: Stream<Item = CanonStateNotification> + Send + Unpin + 'static,
|
||||
{
|
||||
async move {
|
||||
maintain_transaction_pool(client, pool, events).await;
|
||||
}
|
||||
.boxed()
|
||||
}
|
||||
|
||||
/// Maintains the state of the transaction pool by handling new blocks and reorgs.
|
||||
///
|
||||
/// This listens for any new blocks and reorgs and updates the transaction pool's state accordingly
|
||||
@ -27,10 +45,10 @@ pub async fn maintain_transaction_pool<Client, V, T, St>(
|
||||
pool: Pool<V, T>,
|
||||
mut events: St,
|
||||
) where
|
||||
Client: StateProviderFactory + BlockProviderIdExt,
|
||||
V: TransactionValidator,
|
||||
T: TransactionOrdering<Transaction = <V as TransactionValidator>::Transaction>,
|
||||
St: Stream<Item = CanonStateNotification> + Unpin,
|
||||
Client: StateProviderFactory + BlockProviderIdExt + Send + 'static,
|
||||
V: TransactionValidator + Send + 'static,
|
||||
T: TransactionOrdering<Transaction = <V as TransactionValidator>::Transaction> + Send + 'static,
|
||||
St: Stream<Item = CanonStateNotification> + Send + Unpin + 'static,
|
||||
{
|
||||
// ensure the pool points to latest state
|
||||
if let Ok(Some(latest)) = client.block_by_number_or_tag(BlockNumberOrTag::Latest) {
|
||||
|
||||
@ -285,10 +285,10 @@ where
|
||||
listener.discarded(tx.hash());
|
||||
Err(PoolError::InvalidTransaction(*tx.hash(), err))
|
||||
}
|
||||
TransactionValidationOutcome::Error(tx, err) => {
|
||||
TransactionValidationOutcome::Error(tx_hash, err) => {
|
||||
let mut listener = self.event_listener.write();
|
||||
listener.discarded(tx.hash());
|
||||
Err(PoolError::Other(*tx.hash(), err))
|
||||
listener.discarded(&tx_hash);
|
||||
Err(PoolError::Other(tx_hash, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,411 +0,0 @@
|
||||
//! Transaction validation abstractions.
|
||||
|
||||
use crate::{
|
||||
error::InvalidPoolTransactionError,
|
||||
identifier::{SenderId, TransactionId},
|
||||
traits::{PoolTransaction, TransactionOrigin},
|
||||
MAX_INIT_CODE_SIZE, TX_MAX_SIZE,
|
||||
};
|
||||
use reth_primitives::{
|
||||
constants::ETHEREUM_BLOCK_GAS_LIMIT, Address, ChainSpec, IntoRecoveredTransaction,
|
||||
InvalidTransactionError, TransactionKind, TransactionSignedEcRecovered, TxHash,
|
||||
EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, LEGACY_TX_TYPE_ID, U256,
|
||||
};
|
||||
use reth_provider::{AccountReader, StateProviderFactory};
|
||||
use std::{fmt, marker::PhantomData, sync::Arc, time::Instant};
|
||||
|
||||
/// A Result type returned after checking a transaction's validity.
|
||||
#[derive(Debug)]
|
||||
pub enum TransactionValidationOutcome<T: PoolTransaction> {
|
||||
/// The transaction is considered _currently_ valid and can be inserted into the pool.
|
||||
Valid {
|
||||
/// Balance of the sender at the current point.
|
||||
balance: U256,
|
||||
/// Current nonce of the sender.
|
||||
state_nonce: u64,
|
||||
/// Validated transaction.
|
||||
transaction: T,
|
||||
},
|
||||
/// The transaction is considered invalid indefinitely: It violates constraints that prevent
|
||||
/// this transaction from ever becoming valid.
|
||||
Invalid(T, InvalidPoolTransactionError),
|
||||
/// An error occurred while trying to validate the transaction
|
||||
Error(T, Box<dyn std::error::Error + Send + Sync>),
|
||||
}
|
||||
|
||||
impl<T: PoolTransaction> TransactionValidationOutcome<T> {
|
||||
/// Returns the transaction that was validated.
|
||||
pub fn transaction(&self) -> &T {
|
||||
match self {
|
||||
Self::Valid { transaction, .. } => transaction,
|
||||
Self::Invalid(transaction, ..) => transaction,
|
||||
Self::Error(transaction, ..) => transaction,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the hash of the transactions
|
||||
pub fn tx_hash(&self) -> TxHash {
|
||||
*self.transaction().hash()
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides support for validating transaction at any given state of the chain
|
||||
#[async_trait::async_trait]
|
||||
pub trait TransactionValidator: Send + Sync {
|
||||
/// The transaction type to validate.
|
||||
type Transaction: PoolTransaction;
|
||||
|
||||
/// Validates the transaction and returns a [`TransactionValidationOutcome`] describing the
|
||||
/// validity of the given transaction.
|
||||
///
|
||||
/// This will be used by the transaction-pool to check whether the transaction should be
|
||||
/// inserted into the pool or discarded right away.
|
||||
///
|
||||
/// Implementers of this trait must ensure that the transaction is well-formed, i.e. that it
|
||||
/// complies at least all static constraints, which includes checking for:
|
||||
///
|
||||
/// * chain id
|
||||
/// * gas limit
|
||||
/// * max cost
|
||||
/// * nonce >= next nonce of the sender
|
||||
/// * ...
|
||||
///
|
||||
/// See [InvalidTransactionError](InvalidTransactionError) for common errors variants.
|
||||
///
|
||||
/// The transaction pool makes no additional assumptions about the validity of the transaction
|
||||
/// at the time of this call before it inserts it into the pool. However, the validity of
|
||||
/// this transaction is still subject to future (dynamic) changes enforced by the pool, for
|
||||
/// example nonce or balance changes. Hence, any validation checks must be applied in this
|
||||
/// function.
|
||||
///
|
||||
/// See [EthTransactionValidator] for a reference implementation.
|
||||
async fn validate_transaction(
|
||||
&self,
|
||||
origin: TransactionOrigin,
|
||||
transaction: Self::Transaction,
|
||||
) -> TransactionValidationOutcome<Self::Transaction>;
|
||||
|
||||
/// Ensure that the code size is not greater than `max_init_code_size`.
|
||||
/// `max_init_code_size` should be configurable so this will take it as an argument.
|
||||
fn ensure_max_init_code_size(
|
||||
&self,
|
||||
transaction: &Self::Transaction,
|
||||
max_init_code_size: usize,
|
||||
) -> Result<(), InvalidPoolTransactionError> {
|
||||
if *transaction.kind() == TransactionKind::Create && transaction.size() > max_init_code_size
|
||||
{
|
||||
Err(InvalidPoolTransactionError::ExceedsMaxInitCodeSize(
|
||||
transaction.size(),
|
||||
max_init_code_size,
|
||||
))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A [TransactionValidator] implementation that validates ethereum transaction.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EthTransactionValidator<Client, T> {
|
||||
/// Spec of the chain
|
||||
chain_spec: Arc<ChainSpec>,
|
||||
/// This type fetches account info from the db
|
||||
client: Client,
|
||||
/// Fork indicator whether we are in the Shanghai stage.
|
||||
shanghai: bool,
|
||||
/// Fork indicator whether we are using EIP-2718 type transactions.
|
||||
eip2718: bool,
|
||||
/// Fork indicator whether we are using EIP-1559 type transactions.
|
||||
eip1559: bool,
|
||||
/// The current max gas limit
|
||||
block_gas_limit: u64,
|
||||
/// Minimum priority fee to enforce for acceptance into the pool.
|
||||
minimum_priority_fee: Option<u128>,
|
||||
/// Marker for the transaction type
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
// === impl EthTransactionValidator ===
|
||||
|
||||
impl<Client, Tx> EthTransactionValidator<Client, Tx> {
|
||||
/// Creates a new instance for the given [ChainSpec]
|
||||
pub fn new(client: Client, chain_spec: Arc<ChainSpec>) -> Self {
|
||||
// TODO(mattsse): improve these settings by checking against hardfork
|
||||
// See [reth_consensus::validation::validate_transaction_regarding_header]
|
||||
Self {
|
||||
chain_spec,
|
||||
client,
|
||||
shanghai: true,
|
||||
eip2718: true,
|
||||
eip1559: true,
|
||||
block_gas_limit: ETHEREUM_BLOCK_GAS_LIMIT,
|
||||
minimum_priority_fee: None,
|
||||
_marker: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the configured chain id
|
||||
pub fn chain_id(&self) -> u64 {
|
||||
self.chain_spec.chain().id()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<Client, Tx> TransactionValidator for EthTransactionValidator<Client, Tx>
|
||||
where
|
||||
Client: StateProviderFactory,
|
||||
Tx: PoolTransaction,
|
||||
{
|
||||
type Transaction = Tx;
|
||||
|
||||
async fn validate_transaction(
|
||||
&self,
|
||||
origin: TransactionOrigin,
|
||||
transaction: Self::Transaction,
|
||||
) -> TransactionValidationOutcome<Self::Transaction> {
|
||||
// Checks for tx_type
|
||||
match transaction.tx_type() {
|
||||
LEGACY_TX_TYPE_ID => {
|
||||
// Accept legacy transactions
|
||||
}
|
||||
EIP2930_TX_TYPE_ID => {
|
||||
// Accept only legacy transactions until EIP-2718/2930 activates
|
||||
if !self.eip2718 {
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidTransactionError::Eip1559Disabled.into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
EIP1559_TX_TYPE_ID => {
|
||||
// Reject dynamic fee transactions until EIP-1559 activates.
|
||||
if !self.eip1559 {
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidTransactionError::Eip1559Disabled.into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidTransactionError::TxTypeNotSupported.into(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
// Reject transactions over defined size to prevent DOS attacks
|
||||
if transaction.size() > TX_MAX_SIZE {
|
||||
let size = transaction.size();
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidPoolTransactionError::OversizedData(size, TX_MAX_SIZE),
|
||||
)
|
||||
}
|
||||
|
||||
// Check whether the init code size has been exceeded.
|
||||
if self.shanghai {
|
||||
if let Err(err) = self.ensure_max_init_code_size(&transaction, MAX_INIT_CODE_SIZE) {
|
||||
return TransactionValidationOutcome::Invalid(transaction, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Checks for gas limit
|
||||
if transaction.gas_limit() > self.block_gas_limit {
|
||||
let gas_limit = transaction.gas_limit();
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidPoolTransactionError::ExceedsGasLimit(gas_limit, self.block_gas_limit),
|
||||
)
|
||||
}
|
||||
|
||||
// Ensure max_priority_fee_per_gas (if EIP1559) is less than max_fee_per_gas if any.
|
||||
if transaction.max_priority_fee_per_gas() > Some(transaction.max_fee_per_gas()) {
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidTransactionError::TipAboveFeeCap.into(),
|
||||
)
|
||||
}
|
||||
|
||||
// Drop non-local transactions with a fee lower than the configured fee for acceptance into
|
||||
// the pool.
|
||||
if !origin.is_local() &&
|
||||
transaction.is_eip1559() &&
|
||||
transaction.max_priority_fee_per_gas() < self.minimum_priority_fee
|
||||
{
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidPoolTransactionError::Underpriced,
|
||||
)
|
||||
}
|
||||
|
||||
// Checks for chainid
|
||||
if let Some(chain_id) = transaction.chain_id() {
|
||||
if chain_id != self.chain_id() {
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidTransactionError::ChainIdMismatch.into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
let account = match self
|
||||
.client
|
||||
.latest()
|
||||
.and_then(|state| state.basic_account(transaction.sender()))
|
||||
{
|
||||
Ok(account) => account.unwrap_or_default(),
|
||||
Err(err) => return TransactionValidationOutcome::Error(transaction, Box::new(err)),
|
||||
};
|
||||
|
||||
// Signer account shouldn't have bytecode. Presence of bytecode means this is a
|
||||
// smartcontract.
|
||||
if account.has_bytecode() {
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidTransactionError::SignerAccountHasBytecode.into(),
|
||||
)
|
||||
}
|
||||
|
||||
// Checks for nonce
|
||||
if transaction.nonce() < account.nonce {
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidTransactionError::NonceNotConsistent.into(),
|
||||
)
|
||||
}
|
||||
|
||||
// Checks for max cost
|
||||
if transaction.cost() > account.balance {
|
||||
let cost = transaction.cost();
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidTransactionError::InsufficientFunds {
|
||||
cost,
|
||||
available_funds: account.balance,
|
||||
}
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
||||
// Return the valid transaction
|
||||
TransactionValidationOutcome::Valid {
|
||||
balance: account.balance,
|
||||
state_nonce: account.nonce,
|
||||
transaction,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A valid transaction in the pool.
|
||||
pub struct ValidPoolTransaction<T: PoolTransaction> {
|
||||
/// The transaction
|
||||
pub transaction: T,
|
||||
/// The identifier for this transaction.
|
||||
pub transaction_id: TransactionId,
|
||||
/// Whether to propagate the transaction.
|
||||
pub propagate: bool,
|
||||
/// Total cost of the transaction: `feeCap x gasLimit + transferredValue`.
|
||||
pub cost: U256,
|
||||
/// Timestamp when this was added to the pool.
|
||||
pub timestamp: Instant,
|
||||
/// Where this transaction originated from.
|
||||
pub origin: TransactionOrigin,
|
||||
/// The length of the rlp encoded transaction (cached)
|
||||
pub encoded_length: usize,
|
||||
}
|
||||
|
||||
// === impl ValidPoolTransaction ===
|
||||
|
||||
impl<T: PoolTransaction> ValidPoolTransaction<T> {
|
||||
/// Returns the hash of the transaction.
|
||||
pub fn hash(&self) -> &TxHash {
|
||||
self.transaction.hash()
|
||||
}
|
||||
|
||||
/// Returns the type identifier of the transaction
|
||||
pub fn tx_type(&self) -> u8 {
|
||||
self.transaction.tx_type()
|
||||
}
|
||||
|
||||
/// Returns the address of the sender
|
||||
pub fn sender(&self) -> Address {
|
||||
self.transaction.sender()
|
||||
}
|
||||
|
||||
/// Returns the internal identifier for the sender of this transaction
|
||||
pub(crate) fn sender_id(&self) -> SenderId {
|
||||
self.transaction_id.sender
|
||||
}
|
||||
|
||||
/// Returns the internal identifier for this transaction.
|
||||
pub(crate) fn id(&self) -> &TransactionId {
|
||||
&self.transaction_id
|
||||
}
|
||||
|
||||
/// Returns the nonce set for this transaction.
|
||||
pub fn nonce(&self) -> u64 {
|
||||
self.transaction.nonce()
|
||||
}
|
||||
|
||||
/// Returns the EIP-1559 Max base fee the caller is willing to pay.
|
||||
///
|
||||
/// For legacy transactions this is gas_price.
|
||||
pub fn max_fee_per_gas(&self) -> u128 {
|
||||
self.transaction.max_fee_per_gas()
|
||||
}
|
||||
|
||||
/// Returns the EIP-1559 Max base fee the caller is willing to pay.
|
||||
pub fn effective_gas_price(&self) -> u128 {
|
||||
self.transaction.effective_gas_price()
|
||||
}
|
||||
|
||||
/// Amount of gas that should be used in executing this transaction. This is paid up-front.
|
||||
pub fn gas_limit(&self) -> u64 {
|
||||
self.transaction.gas_limit()
|
||||
}
|
||||
|
||||
/// Whether the transaction originated locally.
|
||||
pub fn is_local(&self) -> bool {
|
||||
self.origin.is_local()
|
||||
}
|
||||
|
||||
/// The heap allocated size of this transaction.
|
||||
pub(crate) fn size(&self) -> usize {
|
||||
self.transaction.size()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PoolTransaction> IntoRecoveredTransaction for ValidPoolTransaction<T> {
|
||||
fn to_recovered_transaction(&self) -> TransactionSignedEcRecovered {
|
||||
self.transaction.to_recovered_transaction()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl<T: PoolTransaction + Clone> Clone for ValidPoolTransaction<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
transaction: self.transaction.clone(),
|
||||
transaction_id: self.transaction_id,
|
||||
propagate: self.propagate,
|
||||
cost: self.cost,
|
||||
timestamp: self.timestamp,
|
||||
origin: self.origin,
|
||||
encoded_length: self.encoded_length,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PoolTransaction> fmt::Debug for ValidPoolTransaction<T> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(fmt, "Transaction {{ ")?;
|
||||
write!(fmt, "hash: {:?}, ", &self.transaction.hash())?;
|
||||
write!(fmt, "provides: {:?}, ", &self.transaction_id)?;
|
||||
write!(fmt, "raw tx: {:?}", &self.transaction)?;
|
||||
write!(fmt, "}}")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
306
crates/transaction-pool/src/validate/eth.rs
Normal file
306
crates/transaction-pool/src/validate/eth.rs
Normal file
@ -0,0 +1,306 @@
|
||||
//! Ethereum transaction validator.
|
||||
|
||||
use crate::{
|
||||
error::InvalidPoolTransactionError,
|
||||
traits::{PoolTransaction, TransactionOrigin},
|
||||
validate::{task::ValidationJobSender, TransactionValidatorError, ValidationTask},
|
||||
TransactionValidationOutcome, TransactionValidator, MAX_INIT_CODE_SIZE, TX_MAX_SIZE,
|
||||
};
|
||||
use reth_primitives::{
|
||||
constants::ETHEREUM_BLOCK_GAS_LIMIT, ChainSpec, InvalidTransactionError, EIP1559_TX_TYPE_ID,
|
||||
EIP2930_TX_TYPE_ID, LEGACY_TX_TYPE_ID,
|
||||
};
|
||||
use reth_provider::{AccountReader, StateProviderFactory};
|
||||
use reth_tasks::TaskSpawner;
|
||||
use std::{marker::PhantomData, sync::Arc};
|
||||
use tokio::sync::{oneshot, Mutex};
|
||||
|
||||
/// A [TransactionValidator] implementation that validates ethereum transaction.
|
||||
///
|
||||
/// This validator is non-blocking, all validation work is done in a separate task.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EthTransactionValidator<Client, T> {
|
||||
/// The type that performs the actual validation.
|
||||
inner: Arc<EthTransactionValidatorInner<Client, T>>,
|
||||
/// The sender half to validation tasks that perform the actual validation.
|
||||
to_validation_task: Arc<Mutex<ValidationJobSender>>,
|
||||
}
|
||||
|
||||
// === impl EthTransactionValidator ===
|
||||
|
||||
impl<Client, Tx> EthTransactionValidator<Client, Tx> {
|
||||
/// Creates a new instance for the given [ChainSpec]
|
||||
///
|
||||
/// This will always spawn a validation tasks that perform the actual validation. A will spawn
|
||||
/// `num_additional_tasks` additional tasks.
|
||||
pub fn new<T>(
|
||||
client: Client,
|
||||
chain_spec: Arc<ChainSpec>,
|
||||
tasks: T,
|
||||
num_additional_tasks: usize,
|
||||
) -> Self
|
||||
where
|
||||
T: TaskSpawner,
|
||||
{
|
||||
let inner = EthTransactionValidatorInner {
|
||||
chain_spec,
|
||||
client,
|
||||
shanghai: true,
|
||||
eip2718: true,
|
||||
eip1559: true,
|
||||
block_gas_limit: ETHEREUM_BLOCK_GAS_LIMIT,
|
||||
minimum_priority_fee: None,
|
||||
_marker: Default::default(),
|
||||
};
|
||||
|
||||
let (tx, task) = ValidationTask::new();
|
||||
|
||||
// Spawn validation tasks, they are blocking because they perform db lookups
|
||||
for _ in 0..num_additional_tasks {
|
||||
let task = task.clone();
|
||||
tasks.spawn_blocking(Box::pin(async move {
|
||||
task.run().await;
|
||||
}));
|
||||
}
|
||||
|
||||
tasks.spawn_critical_blocking(
|
||||
"transaction-validation-service",
|
||||
Box::pin(async move {
|
||||
task.run().await;
|
||||
}),
|
||||
);
|
||||
|
||||
let to_validation_task = Arc::new(Mutex::new(tx));
|
||||
|
||||
Self { inner: Arc::new(inner), to_validation_task }
|
||||
}
|
||||
|
||||
/// Returns the configured chain id
|
||||
pub fn chain_id(&self) -> u64 {
|
||||
self.inner.chain_id()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<Client, Tx> TransactionValidator for EthTransactionValidator<Client, Tx>
|
||||
where
|
||||
Client: StateProviderFactory + Clone + 'static,
|
||||
Tx: PoolTransaction + 'static,
|
||||
{
|
||||
type Transaction = Tx;
|
||||
|
||||
async fn validate_transaction(
|
||||
&self,
|
||||
origin: TransactionOrigin,
|
||||
transaction: Self::Transaction,
|
||||
) -> TransactionValidationOutcome<Self::Transaction> {
|
||||
let hash = *transaction.hash();
|
||||
let (tx, rx) = oneshot::channel();
|
||||
{
|
||||
let to_validation_task = self.to_validation_task.clone();
|
||||
let to_validation_task = to_validation_task.lock().await;
|
||||
let validator = Arc::clone(&self.inner);
|
||||
let res = to_validation_task
|
||||
.send(Box::pin(async move {
|
||||
let res = validator.validate_transaction(origin, transaction).await;
|
||||
let _ = tx.send(res);
|
||||
}))
|
||||
.await;
|
||||
if res.is_err() {
|
||||
return TransactionValidationOutcome::Error(
|
||||
hash,
|
||||
Box::new(TransactionValidatorError::ValidationServiceUnreachable),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
match rx.await {
|
||||
Ok(res) => res,
|
||||
Err(_) => TransactionValidationOutcome::Error(
|
||||
hash,
|
||||
Box::new(TransactionValidatorError::ValidationServiceUnreachable),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A [TransactionValidator] implementation that validates ethereum transaction.
|
||||
#[derive(Debug, Clone)]
|
||||
struct EthTransactionValidatorInner<Client, T> {
|
||||
/// Spec of the chain
|
||||
chain_spec: Arc<ChainSpec>,
|
||||
/// This type fetches account info from the db
|
||||
client: Client,
|
||||
/// Fork indicator whether we are in the Shanghai stage.
|
||||
shanghai: bool,
|
||||
/// Fork indicator whether we are using EIP-2718 type transactions.
|
||||
eip2718: bool,
|
||||
/// Fork indicator whether we are using EIP-1559 type transactions.
|
||||
eip1559: bool,
|
||||
/// The current max gas limit
|
||||
block_gas_limit: u64,
|
||||
/// Minimum priority fee to enforce for acceptance into the pool.
|
||||
minimum_priority_fee: Option<u128>,
|
||||
/// Marker for the transaction type
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
// === impl EthTransactionValidatorInner ===
|
||||
|
||||
impl<Client, Tx> EthTransactionValidatorInner<Client, Tx> {
|
||||
/// Returns the configured chain id
|
||||
fn chain_id(&self) -> u64 {
|
||||
self.chain_spec.chain().id()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<Client, Tx> TransactionValidator for EthTransactionValidatorInner<Client, Tx>
|
||||
where
|
||||
Client: StateProviderFactory,
|
||||
Tx: PoolTransaction,
|
||||
{
|
||||
type Transaction = Tx;
|
||||
|
||||
async fn validate_transaction(
|
||||
&self,
|
||||
origin: TransactionOrigin,
|
||||
transaction: Self::Transaction,
|
||||
) -> TransactionValidationOutcome<Self::Transaction> {
|
||||
// Checks for tx_type
|
||||
match transaction.tx_type() {
|
||||
LEGACY_TX_TYPE_ID => {
|
||||
// Accept legacy transactions
|
||||
}
|
||||
EIP2930_TX_TYPE_ID => {
|
||||
// Accept only legacy transactions until EIP-2718/2930 activates
|
||||
if !self.eip2718 {
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidTransactionError::Eip1559Disabled.into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
EIP1559_TX_TYPE_ID => {
|
||||
// Reject dynamic fee transactions until EIP-1559 activates.
|
||||
if !self.eip1559 {
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidTransactionError::Eip1559Disabled.into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidTransactionError::TxTypeNotSupported.into(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
// Reject transactions over defined size to prevent DOS attacks
|
||||
if transaction.size() > TX_MAX_SIZE {
|
||||
let size = transaction.size();
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidPoolTransactionError::OversizedData(size, TX_MAX_SIZE),
|
||||
)
|
||||
}
|
||||
|
||||
// Check whether the init code size has been exceeded.
|
||||
if self.shanghai {
|
||||
if let Err(err) = self.ensure_max_init_code_size(&transaction, MAX_INIT_CODE_SIZE) {
|
||||
return TransactionValidationOutcome::Invalid(transaction, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Checks for gas limit
|
||||
if transaction.gas_limit() > self.block_gas_limit {
|
||||
let gas_limit = transaction.gas_limit();
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidPoolTransactionError::ExceedsGasLimit(gas_limit, self.block_gas_limit),
|
||||
)
|
||||
}
|
||||
|
||||
// Ensure max_priority_fee_per_gas (if EIP1559) is less than max_fee_per_gas if any.
|
||||
if transaction.max_priority_fee_per_gas() > Some(transaction.max_fee_per_gas()) {
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidTransactionError::TipAboveFeeCap.into(),
|
||||
)
|
||||
}
|
||||
|
||||
// Drop non-local transactions with a fee lower than the configured fee for acceptance into
|
||||
// the pool.
|
||||
if !origin.is_local() &&
|
||||
transaction.is_eip1559() &&
|
||||
transaction.max_priority_fee_per_gas() < self.minimum_priority_fee
|
||||
{
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidPoolTransactionError::Underpriced,
|
||||
)
|
||||
}
|
||||
|
||||
// Checks for chainid
|
||||
if let Some(chain_id) = transaction.chain_id() {
|
||||
if chain_id != self.chain_id() {
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidTransactionError::ChainIdMismatch.into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
let account = match self
|
||||
.client
|
||||
.latest()
|
||||
.and_then(|state| state.basic_account(transaction.sender()))
|
||||
{
|
||||
Ok(account) => account.unwrap_or_default(),
|
||||
Err(err) => {
|
||||
return TransactionValidationOutcome::Error(*transaction.hash(), Box::new(err))
|
||||
}
|
||||
};
|
||||
|
||||
// Signer account shouldn't have bytecode. Presence of bytecode means this is a
|
||||
// smartcontract.
|
||||
if account.has_bytecode() {
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidTransactionError::SignerAccountHasBytecode.into(),
|
||||
)
|
||||
}
|
||||
|
||||
// Checks for nonce
|
||||
if transaction.nonce() < account.nonce {
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidTransactionError::NonceNotConsistent.into(),
|
||||
)
|
||||
}
|
||||
|
||||
// Checks for max cost
|
||||
if transaction.cost() > account.balance {
|
||||
let cost = transaction.cost();
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidTransactionError::InsufficientFunds {
|
||||
cost,
|
||||
available_funds: account.balance,
|
||||
}
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
||||
// Return the valid transaction
|
||||
TransactionValidationOutcome::Valid {
|
||||
balance: account.balance,
|
||||
state_nonce: account.nonce,
|
||||
transaction,
|
||||
}
|
||||
}
|
||||
}
|
||||
225
crates/transaction-pool/src/validate/mod.rs
Normal file
225
crates/transaction-pool/src/validate/mod.rs
Normal file
@ -0,0 +1,225 @@
|
||||
//! Transaction validation abstractions.
|
||||
|
||||
use crate::{
|
||||
error::InvalidPoolTransactionError,
|
||||
identifier::{SenderId, TransactionId},
|
||||
traits::{PoolTransaction, TransactionOrigin},
|
||||
};
|
||||
use reth_primitives::{
|
||||
Address, IntoRecoveredTransaction, TransactionKind, TransactionSignedEcRecovered, TxHash, U256,
|
||||
};
|
||||
use std::{fmt, time::Instant};
|
||||
|
||||
mod eth;
|
||||
mod task;
|
||||
|
||||
/// A [TransactionValidator] implementation that validates ethereum transaction.
|
||||
pub use eth::EthTransactionValidator;
|
||||
|
||||
/// A spawnable task that performs transaction validation.
|
||||
pub use task::ValidationTask;
|
||||
|
||||
/// A Result type returned after checking a transaction's validity.
|
||||
#[derive(Debug)]
|
||||
pub enum TransactionValidationOutcome<T: PoolTransaction> {
|
||||
/// The transaction is considered _currently_ valid and can be inserted into the pool.
|
||||
Valid {
|
||||
/// Balance of the sender at the current point.
|
||||
balance: U256,
|
||||
/// Current nonce of the sender.
|
||||
state_nonce: u64,
|
||||
/// Validated transaction.
|
||||
transaction: T,
|
||||
},
|
||||
/// The transaction is considered invalid indefinitely: It violates constraints that prevent
|
||||
/// this transaction from ever becoming valid.
|
||||
Invalid(T, InvalidPoolTransactionError),
|
||||
/// An error occurred while trying to validate the transaction
|
||||
Error(TxHash, Box<dyn std::error::Error + Send + Sync>),
|
||||
}
|
||||
|
||||
impl<T: PoolTransaction> TransactionValidationOutcome<T> {
|
||||
/// Returns the hash of the transactions
|
||||
pub fn tx_hash(&self) -> TxHash {
|
||||
match self {
|
||||
Self::Valid { transaction, .. } => *transaction.hash(),
|
||||
Self::Invalid(transaction, ..) => *transaction.hash(),
|
||||
Self::Error(hash, ..) => *hash,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides support for validating transaction at any given state of the chain
|
||||
#[async_trait::async_trait]
|
||||
pub trait TransactionValidator: Send + Sync {
|
||||
/// The transaction type to validate.
|
||||
type Transaction: PoolTransaction;
|
||||
|
||||
/// Validates the transaction and returns a [`TransactionValidationOutcome`] describing the
|
||||
/// validity of the given transaction.
|
||||
///
|
||||
/// This will be used by the transaction-pool to check whether the transaction should be
|
||||
/// inserted into the pool or discarded right away.
|
||||
///
|
||||
/// Implementers of this trait must ensure that the transaction is well-formed, i.e. that it
|
||||
/// complies at least all static constraints, which includes checking for:
|
||||
///
|
||||
/// * chain id
|
||||
/// * gas limit
|
||||
/// * max cost
|
||||
/// * nonce >= next nonce of the sender
|
||||
/// * ...
|
||||
///
|
||||
/// See [InvalidTransactionError](reth_primitives::InvalidTransactionError) for common errors
|
||||
/// variants.
|
||||
///
|
||||
/// The transaction pool makes no additional assumptions about the validity of the transaction
|
||||
/// at the time of this call before it inserts it into the pool. However, the validity of
|
||||
/// this transaction is still subject to future (dynamic) changes enforced by the pool, for
|
||||
/// example nonce or balance changes. Hence, any validation checks must be applied in this
|
||||
/// function.
|
||||
///
|
||||
/// See [EthTransactionValidator] for a reference implementation.
|
||||
async fn validate_transaction(
|
||||
&self,
|
||||
origin: TransactionOrigin,
|
||||
transaction: Self::Transaction,
|
||||
) -> TransactionValidationOutcome<Self::Transaction>;
|
||||
|
||||
/// Ensure that the code size is not greater than `max_init_code_size`.
|
||||
/// `max_init_code_size` should be configurable so this will take it as an argument.
|
||||
fn ensure_max_init_code_size(
|
||||
&self,
|
||||
transaction: &Self::Transaction,
|
||||
max_init_code_size: usize,
|
||||
) -> Result<(), InvalidPoolTransactionError> {
|
||||
if *transaction.kind() == TransactionKind::Create && transaction.size() > max_init_code_size
|
||||
{
|
||||
Err(InvalidPoolTransactionError::ExceedsMaxInitCodeSize(
|
||||
transaction.size(),
|
||||
max_init_code_size,
|
||||
))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A valid transaction in the pool.
|
||||
pub struct ValidPoolTransaction<T: PoolTransaction> {
|
||||
/// The transaction
|
||||
pub transaction: T,
|
||||
/// The identifier for this transaction.
|
||||
pub transaction_id: TransactionId,
|
||||
/// Whether to propagate the transaction.
|
||||
pub propagate: bool,
|
||||
/// Total cost of the transaction: `feeCap x gasLimit + transferredValue`.
|
||||
pub cost: U256,
|
||||
/// Timestamp when this was added to the pool.
|
||||
pub timestamp: Instant,
|
||||
/// Where this transaction originated from.
|
||||
pub origin: TransactionOrigin,
|
||||
/// The length of the rlp encoded transaction (cached)
|
||||
pub encoded_length: usize,
|
||||
}
|
||||
|
||||
// === impl ValidPoolTransaction ===
|
||||
|
||||
impl<T: PoolTransaction> ValidPoolTransaction<T> {
|
||||
/// Returns the hash of the transaction.
|
||||
pub fn hash(&self) -> &TxHash {
|
||||
self.transaction.hash()
|
||||
}
|
||||
|
||||
/// Returns the type identifier of the transaction
|
||||
pub fn tx_type(&self) -> u8 {
|
||||
self.transaction.tx_type()
|
||||
}
|
||||
|
||||
/// Returns the address of the sender
|
||||
pub fn sender(&self) -> Address {
|
||||
self.transaction.sender()
|
||||
}
|
||||
|
||||
/// Returns the internal identifier for the sender of this transaction
|
||||
pub(crate) fn sender_id(&self) -> SenderId {
|
||||
self.transaction_id.sender
|
||||
}
|
||||
|
||||
/// Returns the internal identifier for this transaction.
|
||||
pub(crate) fn id(&self) -> &TransactionId {
|
||||
&self.transaction_id
|
||||
}
|
||||
|
||||
/// Returns the nonce set for this transaction.
|
||||
pub fn nonce(&self) -> u64 {
|
||||
self.transaction.nonce()
|
||||
}
|
||||
|
||||
/// Returns the EIP-1559 Max base fee the caller is willing to pay.
|
||||
///
|
||||
/// For legacy transactions this is gas_price.
|
||||
pub fn max_fee_per_gas(&self) -> u128 {
|
||||
self.transaction.max_fee_per_gas()
|
||||
}
|
||||
|
||||
/// Returns the EIP-1559 Max base fee the caller is willing to pay.
|
||||
pub fn effective_gas_price(&self) -> u128 {
|
||||
self.transaction.effective_gas_price()
|
||||
}
|
||||
|
||||
/// Amount of gas that should be used in executing this transaction. This is paid up-front.
|
||||
pub fn gas_limit(&self) -> u64 {
|
||||
self.transaction.gas_limit()
|
||||
}
|
||||
|
||||
/// Whether the transaction originated locally.
|
||||
pub fn is_local(&self) -> bool {
|
||||
self.origin.is_local()
|
||||
}
|
||||
|
||||
/// The heap allocated size of this transaction.
|
||||
pub(crate) fn size(&self) -> usize {
|
||||
self.transaction.size()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PoolTransaction> IntoRecoveredTransaction for ValidPoolTransaction<T> {
|
||||
fn to_recovered_transaction(&self) -> TransactionSignedEcRecovered {
|
||||
self.transaction.to_recovered_transaction()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl<T: PoolTransaction + Clone> Clone for ValidPoolTransaction<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
transaction: self.transaction.clone(),
|
||||
transaction_id: self.transaction_id,
|
||||
propagate: self.propagate,
|
||||
cost: self.cost,
|
||||
timestamp: self.timestamp,
|
||||
origin: self.origin,
|
||||
encoded_length: self.encoded_length,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PoolTransaction> fmt::Debug for ValidPoolTransaction<T> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(fmt, "Transaction {{ ")?;
|
||||
write!(fmt, "hash: {:?}, ", &self.transaction.hash())?;
|
||||
write!(fmt, "provides: {:?}, ", &self.transaction_id)?;
|
||||
write!(fmt, "raw tx: {:?}", &self.transaction)?;
|
||||
write!(fmt, "}}")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Validation Errors that can occur during transaction validation.
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum TransactionValidatorError {
|
||||
/// Failed to communicate with the validation service.
|
||||
#[error("Validation service unreachable")]
|
||||
ValidationServiceUnreachable,
|
||||
}
|
||||
62
crates/transaction-pool/src/validate/task.rs
Normal file
62
crates/transaction-pool/src/validate/task.rs
Normal file
@ -0,0 +1,62 @@
|
||||
//! A validation service for transactions.
|
||||
|
||||
use crate::validate::TransactionValidatorError;
|
||||
use futures_util::{lock::Mutex, StreamExt};
|
||||
use std::{future::Future, pin::Pin, sync::Arc};
|
||||
use tokio::sync::mpsc;
|
||||
use tokio_stream::wrappers::ReceiverStream;
|
||||
|
||||
/// A service that performs validation jobs.
|
||||
#[derive(Clone)]
|
||||
pub struct ValidationTask {
|
||||
#[allow(clippy::type_complexity)]
|
||||
validation_jobs: Arc<Mutex<ReceiverStream<Pin<Box<dyn Future<Output = ()> + Send>>>>>,
|
||||
}
|
||||
|
||||
impl ValidationTask {
|
||||
/// Creates a new clonable task pair
|
||||
pub fn new() -> (ValidationJobSender, Self) {
|
||||
let (tx, rx) = mpsc::channel(1);
|
||||
(ValidationJobSender { tx }, Self::with_receiver(rx))
|
||||
}
|
||||
|
||||
/// Creates a new task with the given receiver.
|
||||
pub fn with_receiver(jobs: mpsc::Receiver<Pin<Box<dyn Future<Output = ()> + Send>>>) -> Self {
|
||||
ValidationTask { validation_jobs: Arc::new(Mutex::new(ReceiverStream::new(jobs))) }
|
||||
}
|
||||
|
||||
/// Executes all new validation jobs that come in.
|
||||
///
|
||||
/// This will run as long as the channel is alive and is expected to be spawned as a task.
|
||||
pub async fn run(self) {
|
||||
loop {
|
||||
let task = self.validation_jobs.lock().await.next().await;
|
||||
match task {
|
||||
None => return,
|
||||
Some(task) => task.await,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ValidationTask {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("ValidationTask").field("validation_jobs", &"...").finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// A sender new type for sending validation jobs to [ValidationTask].
|
||||
#[derive(Debug)]
|
||||
pub struct ValidationJobSender {
|
||||
tx: mpsc::Sender<Pin<Box<dyn Future<Output = ()> + Send>>>,
|
||||
}
|
||||
|
||||
impl ValidationJobSender {
|
||||
/// Sends the given job to the validation task.
|
||||
pub async fn send(
|
||||
&self,
|
||||
job: Pin<Box<dyn Future<Output = ()> + Send>>,
|
||||
) -> Result<(), TransactionValidatorError> {
|
||||
self.tx.send(job).await.map_err(|_| TransactionValidatorError::ValidationServiceUnreachable)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user