refactor(primitives): use alloy's EthereumReceipt type (#22254)

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
stevencartavia
2026-02-17 14:30:52 -06:00
committed by GitHub
parent 59993b974a
commit 477fed7a11
13 changed files with 283 additions and 671 deletions

122
Cargo.lock generated
View File

@@ -121,9 +121,9 @@ dependencies = [
[[package]]
name = "alloy-consensus"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e4ff99651d46cef43767b5e8262ea228cd05287409ccb0c947cc25e70a952f9"
checksum = "3ac62771adeba3957d5612481cce02e99c3faa2c62f4fc0539fa22e023bb58ec"
dependencies = [
"alloy-eips",
"alloy-primitives",
@@ -149,9 +149,9 @@ dependencies = [
[[package]]
name = "alloy-consensus-any"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a0701b0eda8051a2398591113e7862f807ccdd3315d0b441f06c2a0865a379b"
checksum = "e3a8d617f7ccd3d93d44c7e30a9a3bfae209883b9c59a4b91b9168066742a888"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -164,9 +164,9 @@ dependencies = [
[[package]]
name = "alloy-contract"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3c83c7a3c4e1151e8cac383d0a67ddf358f37e5ea51c95a1283d897c9de0a5a"
checksum = "f7b80d98a1e93bc7437fdf2cee6bbb27adb2623db96790d5fdab646fab2ceb63"
dependencies = [
"alloy-consensus",
"alloy-dyn-abi",
@@ -262,9 +262,9 @@ dependencies = [
[[package]]
name = "alloy-eips"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "def1626eea28d48c6cc0a6f16f34d4af0001906e4f889df6c660b39c86fd044d"
checksum = "fc41cef32ed4225d5ce5429d17acd9cfe0bf7cf1bc206571c78e6985486a2da7"
dependencies = [
"alloy-eip2124",
"alloy-eip2930",
@@ -311,9 +311,9 @@ dependencies = [
[[package]]
name = "alloy-genesis"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55d9d1aba3f914f0e8db9e4616ae37f3d811426d95bdccf44e47d0605ab202f6"
checksum = "2c4e42af8ba0d266565a185cb7249509049edc95a719761fd1f939079f6fbd65"
dependencies = [
"alloy-eips",
"alloy-primitives",
@@ -365,9 +365,9 @@ dependencies = [
[[package]]
name = "alloy-json-rpc"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e57586581f2008933241d16c3e3f633168b3a5d2738c5c42ea5246ec5e0ef17a"
checksum = "e4239d7a1dd9e6c2ee7c126681bfb14e96ba62492f7870e3a1340ecd9eb507d7"
dependencies = [
"alloy-primitives",
"alloy-sol-types",
@@ -380,9 +380,9 @@ dependencies = [
[[package]]
name = "alloy-network"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b36c2a0ed74e48851f78415ca5b465211bd678891ba11e88fee09eac534bab1"
checksum = "d8db418e7a3664e44f17888dae0deab83815e69ff0c3035e786a8227190a580e"
dependencies = [
"alloy-consensus",
"alloy-consensus-any",
@@ -406,9 +406,9 @@ dependencies = [
[[package]]
name = "alloy-network-primitives"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "636c8051da58802e757b76c3b65af610b95799f72423dc955737dec73de234fd"
checksum = "e0c122ad8fe501326e73786f3bc778fbe9399a48513a0657e4ba33a60a5d502a"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -484,9 +484,9 @@ dependencies = [
[[package]]
name = "alloy-provider"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3dd56e2eafe8b1803e325867ac2c8a4c73c9fb5f341ffd8347f9344458c5922"
checksum = "02e853a33d674476c2d9305c4f0ce2aadee2e473b51168fd0bcd2cb2cdd66343"
dependencies = [
"alloy-chains",
"alloy-consensus",
@@ -529,9 +529,9 @@ dependencies = [
[[package]]
name = "alloy-pubsub"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6eebf54983d4fccea08053c218ee5c288adf2e660095a243d0532a8070b43955"
checksum = "8626237b5b2665e18bc6a35a547ec2ea41712c1d7e060d96ce1cb3222a64ac66"
dependencies = [
"alloy-json-rpc",
"alloy-primitives",
@@ -573,9 +573,9 @@ dependencies = [
[[package]]
name = "alloy-rpc-client"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91577235d341a1bdbee30a463655d08504408a4d51e9f72edbfc5a622829f402"
checksum = "8f3cfcfec14d694e3201c760a25c5c080bc37ef5f7edf21132b26e79f067d67b"
dependencies = [
"alloy-json-rpc",
"alloy-primitives",
@@ -599,9 +599,9 @@ dependencies = [
[[package]]
name = "alloy-rpc-types"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79cff039bf01a17d76c0aace3a3a773d5f895eb4c68baaae729ec9da9e86c99c"
checksum = "80a879af27313f5b97ff61674aa36c2b5ea092d932a27d089e00aa4d858b04c2"
dependencies = [
"alloy-primitives",
"alloy-rpc-types-engine",
@@ -612,9 +612,9 @@ dependencies = [
[[package]]
name = "alloy-rpc-types-admin"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "564afceae126df73b95f78c81eb46e2ef689a45ace0fcdaf5c9a178693a5ccca"
checksum = "4311dcd4777732fc4b1b29963563c98e24d1bd8a9d03ce5d412efc289e320662"
dependencies = [
"alloy-genesis",
"alloy-primitives",
@@ -624,9 +624,9 @@ dependencies = [
[[package]]
name = "alloy-rpc-types-anvil"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d22250cf438b6a3926de67683c08163bfa1fd1efa47ee9512cbcd631b6b0243c"
checksum = "e26eac56a2908a0b847f4606c3e519e9fd576a571aee929d0a74222bd01e9e01"
dependencies = [
"alloy-primitives",
"alloy-rpc-types-eth",
@@ -636,9 +636,9 @@ dependencies = [
[[package]]
name = "alloy-rpc-types-any"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73234a141ecce14e2989748c04fcac23deee67a445e2c4c167cfb42d4dacd1b6"
checksum = "f375243e3ce50309b52bc5516cf9ec29235259357b58783c251d06f4679621cf"
dependencies = [
"alloy-consensus-any",
"alloy-rpc-types-eth",
@@ -647,9 +647,9 @@ dependencies = [
[[package]]
name = "alloy-rpc-types-beacon"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "625af0c3ebd3c31322edb1fb6b8e3e518acc39e164ed07e422eaff05310ff2fa"
checksum = "08e69e48ea882b9f852e34a34c80440d8300f418fb9b41bf321de915d5d75a75"
dependencies = [
"alloy-eips",
"alloy-primitives",
@@ -667,9 +667,9 @@ dependencies = [
[[package]]
name = "alloy-rpc-types-debug"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "779f70ab16a77e305571881b07a9bc6b0068ae6f962497baf5762825c5b839fb"
checksum = "2c55187c9162b8f2bcddc444046b50a227029af89876ab6e5db2c600a3a989b7"
dependencies = [
"alloy-primitives",
"derive_more",
@@ -679,9 +679,9 @@ dependencies = [
[[package]]
name = "alloy-rpc-types-engine"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10620d600cc46538f613c561ac9a923843c6c74c61f054828dcdb8dd18c72ec4"
checksum = "622934088b592f05ef3870d67ec37689ee402f5900a0a730b37dbcaaf9c31eaf"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -700,9 +700,9 @@ dependencies = [
[[package]]
name = "alloy-rpc-types-eth"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "010e101dbebe0c678248907a2545b574a87d078d82c2f6f5d0e8e7c9a6149a10"
checksum = "544d4b49ed745cf9b712b7b244a176752149ee7a82dcf84c90eb64dfeea64e43"
dependencies = [
"alloy-consensus",
"alloy-consensus-any",
@@ -722,9 +722,9 @@ dependencies = [
[[package]]
name = "alloy-rpc-types-mev"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "375e4bf001135fe4f344db6197fafed8c2b61e99fa14d3597f44cd413f79e45b"
checksum = "9437141664df8a0643054340c337d3f99cedbdaaa490d11f2b6a94824465e56f"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -737,9 +737,9 @@ dependencies = [
[[package]]
name = "alloy-rpc-types-trace"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be096f74d85e1f927580b398bf7bc5b4aa62326f149680ec0867e3c040c9aced"
checksum = "cbcf0a427056ee12d9fd713c17275526e52e806d866d613169bc2f67f40d7432"
dependencies = [
"alloy-primitives",
"alloy-rpc-types-eth",
@@ -751,9 +751,9 @@ dependencies = [
[[package]]
name = "alloy-rpc-types-txpool"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14ab75189fbc29c5dd6f0bc1529bccef7b00773b458763f4d9d81a77ae4a1a2d"
checksum = "d9da21a07fa522597ef6cb339594cbb7420f82794f9ddc3ed715ab2bda0de03b"
dependencies = [
"alloy-primitives",
"alloy-rpc-types-eth",
@@ -763,9 +763,9 @@ dependencies = [
[[package]]
name = "alloy-serde"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e6d631f8b975229361d8af7b2c749af31c73b3cf1352f90e144ddb06227105e"
checksum = "e7da7b302b464e666856fefaed3f85a3cfb8ba73df064e6ca4abbd8809f9a816"
dependencies = [
"alloy-primitives",
"arbitrary",
@@ -775,9 +775,9 @@ dependencies = [
[[package]]
name = "alloy-signer"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97f40010b5e8f79b70bf163b38cd15f529b18ca88c4427c0e43441ee54e4ed82"
checksum = "aaedc76636029c936f2374824d1c0c24b9041e7a496e1c984755c6ad99cf098b"
dependencies = [
"alloy-primitives",
"async-trait",
@@ -790,9 +790,9 @@ dependencies = [
[[package]]
name = "alloy-signer-local"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c4ec1cc27473819399a3f0da83bc1cef0ceaac8c1c93997696e46dc74377a58"
checksum = "2884f4d92e9f2e97a78e15c7d251502b0fbd162c20c8fa69babcfc0e39e17c38"
dependencies = [
"alloy-consensus",
"alloy-network",
@@ -879,9 +879,9 @@ dependencies = [
[[package]]
name = "alloy-transport"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a03bb3f02b9a7ab23dacd1822fa7f69aa5c8eefcdcf57fad085e0b8d76fb4334"
checksum = "d9f745ea15b72fdf80f9788a56dfeffa0a418c4aa555f712e1de3d926bc95aef"
dependencies = [
"alloy-json-rpc",
"auto_impl",
@@ -902,9 +902,9 @@ dependencies = [
[[package]]
name = "alloy-transport-http"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ce599598ef8ebe067f3627509358d9faaa1ef94f77f834a7783cd44209ef55c"
checksum = "2219ca0a55410886f0b2020aa9116290f7d849795f6bde20d0800818b5c98243"
dependencies = [
"alloy-json-rpc",
"alloy-transport",
@@ -918,9 +918,9 @@ dependencies = [
[[package]]
name = "alloy-transport-ipc"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49963a2561ebd439549915ea61efb70a7b13b97500ec16ca507721c9d9957d07"
checksum = "5c854e8092cce775d93f3d587aa76df88dc899089e16e31820964cfa8a41887e"
dependencies = [
"alloy-json-rpc",
"alloy-pubsub",
@@ -938,9 +938,9 @@ dependencies = [
[[package]]
name = "alloy-transport-ws"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ed38ea573c6658e0c2745af9d1f1773b1ed83aa59fbd9c286358ad469c3233a"
checksum = "d104c7ff76a1bac3b650eea676ca09fd0d8d5d368eca864de8fe472918a6a22f"
dependencies = [
"alloy-pubsub",
"alloy-transport",
@@ -976,9 +976,9 @@ dependencies = [
[[package]]
name = "alloy-tx-macros"
version = "1.6.3"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "397406cf04b11ca2a48e6f81804c70af3f40a36abf648e11dc7416043eb0834d"
checksum = "0b2e24e8235af401185f477c2be85d6dda4386d6bc6e18249198b14252b795df"
dependencies = [
"darling 0.21.3",
"proc-macro2",
@@ -8710,9 +8710,7 @@ dependencies = [
"alloy-rpc-types-eth",
"alloy-serde",
"arbitrary",
"bincode 1.3.3",
"derive_more",
"modular-bitfield",
"proptest",
"proptest-arbitrary-interop",
"rand 0.8.5",

View File

@@ -459,33 +459,33 @@ alloy-trie = { version = "0.9.4", default-features = false }
alloy-hardforks = "0.4.5"
alloy-consensus = { version = "1.6.3", default-features = false }
alloy-contract = { version = "1.6.3", default-features = false }
alloy-eips = { version = "1.6.3", default-features = false }
alloy-genesis = { version = "1.6.3", default-features = false }
alloy-json-rpc = { version = "1.6.3", default-features = false }
alloy-network = { version = "1.6.3", default-features = false }
alloy-network-primitives = { version = "1.6.3", default-features = false }
alloy-provider = { version = "1.6.3", features = ["reqwest", "debug-api"], default-features = false }
alloy-pubsub = { version = "1.6.3", default-features = false }
alloy-rpc-client = { version = "1.6.3", default-features = false }
alloy-rpc-types = { version = "1.6.3", features = ["eth"], default-features = false }
alloy-rpc-types-admin = { version = "1.6.3", default-features = false }
alloy-rpc-types-anvil = { version = "1.6.3", default-features = false }
alloy-rpc-types-beacon = { version = "1.6.3", default-features = false }
alloy-rpc-types-debug = { version = "1.6.3", default-features = false }
alloy-rpc-types-engine = { version = "1.6.3", default-features = false }
alloy-rpc-types-eth = { version = "1.6.3", default-features = false }
alloy-rpc-types-mev = { version = "1.6.3", default-features = false }
alloy-rpc-types-trace = { version = "1.6.3", default-features = false }
alloy-rpc-types-txpool = { version = "1.6.3", default-features = false }
alloy-serde = { version = "1.6.3", default-features = false }
alloy-signer = { version = "1.6.3", default-features = false }
alloy-signer-local = { version = "1.6.3", default-features = false }
alloy-transport = { version = "1.6.3" }
alloy-transport-http = { version = "1.6.3", features = ["reqwest-rustls-tls"], default-features = false }
alloy-transport-ipc = { version = "1.6.3", default-features = false }
alloy-transport-ws = { version = "1.6.3", default-features = false }
alloy-consensus = { version = "1.7.1", default-features = false }
alloy-contract = { version = "1.7.1", default-features = false }
alloy-eips = { version = "1.7.1", default-features = false }
alloy-genesis = { version = "1.7.1", default-features = false }
alloy-json-rpc = { version = "1.7.1", default-features = false }
alloy-network = { version = "1.7.1", default-features = false }
alloy-network-primitives = { version = "1.7.1", default-features = false }
alloy-provider = { version = "1.7.1", features = ["reqwest", "debug-api"], default-features = false }
alloy-pubsub = { version = "1.7.1", default-features = false }
alloy-rpc-client = { version = "1.7.1", default-features = false }
alloy-rpc-types = { version = "1.7.1", features = ["eth"], default-features = false }
alloy-rpc-types-admin = { version = "1.7.1", default-features = false }
alloy-rpc-types-anvil = { version = "1.7.1", default-features = false }
alloy-rpc-types-beacon = { version = "1.7.1", default-features = false }
alloy-rpc-types-debug = { version = "1.7.1", default-features = false }
alloy-rpc-types-engine = { version = "1.7.1", default-features = false }
alloy-rpc-types-eth = { version = "1.7.1", default-features = false }
alloy-rpc-types-mev = { version = "1.7.1", default-features = false }
alloy-rpc-types-trace = { version = "1.7.1", default-features = false }
alloy-rpc-types-txpool = { version = "1.7.1", default-features = false }
alloy-serde = { version = "1.7.1", default-features = false }
alloy-signer = { version = "1.7.1", default-features = false }
alloy-signer-local = { version = "1.7.1", default-features = false }
alloy-transport = { version = "1.7.1" }
alloy-transport-http = { version = "1.7.1", features = ["reqwest-rustls-tls"], default-features = false }
alloy-transport-ipc = { version = "1.7.1", default-features = false }
alloy-transport-ws = { version = "1.7.1", default-features = false }
# op
alloy-op-evm = { version = "0.27.2", default-features = false }

View File

@@ -15,35 +15,31 @@ workspace = true
# reth
reth-codecs = { workspace = true, optional = true }
reth-primitives-traits.workspace = true
reth-zstd-compressors = { workspace = true, optional = true }
# ethereum
alloy-eips = { workspace = true, features = ["k256"] }
alloy-primitives.workspace = true
alloy-consensus = { workspace = true, features = ["serde"] }
alloy-serde = { workspace = true, optional = true }
alloy-rpc-types-eth = { workspace = true, optional = true }
alloy-rlp.workspace = true
# misc
arbitrary = { workspace = true, optional = true, features = ["derive"] }
modular-bitfield = { workspace = true, optional = true }
serde = { workspace = true, optional = true }
serde_with = { workspace = true, optional = true }
[dev-dependencies]
alloy-serde.workspace = true
derive_more.workspace = true
arbitrary.workspace = true
bincode.workspace = true
proptest.workspace = true
proptest-arbitrary-interop.workspace = true
rand_08.workspace = true
rand.workspace = true
alloy-rlp.workspace = true
reth-codecs = { workspace = true, features = ["test-utils"] }
reth-zstd-compressors.workspace = true
secp256k1 = { workspace = true, features = ["rand"] }
alloy-consensus = { workspace = true, features = ["serde", "arbitrary"] }
serde_json.workspace = true
serde_with.workspace = true
[features]
default = ["std"]
@@ -54,27 +50,24 @@ test-utils = [
std = [
"alloy-consensus/std",
"alloy-primitives/std",
"alloy-rlp/std",
"reth-primitives-traits/std",
"reth-zstd-compressors?/std",
"serde?/std",
"alloy-eips/std",
"derive_more/std",
"serde_with?/std",
"secp256k1/std",
"alloy-rpc-types-eth?/std",
"alloy-serde?/std",
"alloy-rlp/std",
"alloy-serde/std",
"derive_more/std",
"reth-zstd-compressors/std",
"secp256k1/std",
"serde_json/std",
"serde_with/std",
]
reth-codec = [
"std",
"dep:reth-codecs",
"dep:modular-bitfield",
"dep:reth-zstd-compressors",
]
arbitrary = [
"std",
"dep:arbitrary",
"alloy-consensus/arbitrary",
"alloy-consensus/k256",
"alloy-primitives/arbitrary",
@@ -82,10 +75,9 @@ arbitrary = [
"reth-primitives-traits/arbitrary",
"alloy-eips/arbitrary",
"alloy-rpc-types-eth?/arbitrary",
"alloy-serde?/arbitrary",
"alloy-serde/arbitrary",
]
serde-bincode-compat = [
"dep:serde_with",
"alloy-consensus/serde-bincode-compat",
"alloy-eips/serde-bincode-compat",
"reth-primitives-traits/serde-bincode-compat",
@@ -93,15 +85,14 @@ serde-bincode-compat = [
]
serde = [
"dep:serde",
"dep:alloy-serde",
"alloy-consensus/serde",
"alloy-eips/serde",
"alloy-primitives/serde",
"reth-codecs?/serde",
"reth-primitives-traits/serde",
"rand/serde",
"rand_08/serde",
"secp256k1/serde",
"alloy-rpc-types-eth?/serde",
"rand_08/serde",
"rand/serde",
"secp256k1/serde",
]
rpc = ["dep:alloy-rpc-types-eth"]

View File

@@ -9,7 +9,9 @@
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
// Feature-only dep: activated by `reth-codec` feature for downstream consumers.
#[cfg(feature = "reth-codec")]
use reth_codecs as _;
mod receipt;
pub use receipt::*;
@@ -35,8 +37,7 @@ pub type PooledTransactionVariant =
/// Bincode-compatible serde implementations.
#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))]
pub mod serde_bincode_compat {
pub use super::receipt::serde_bincode_compat::*;
pub use alloy_consensus::serde_bincode_compat::transaction::*;
pub use alloy_consensus::serde_bincode_compat::{transaction::*, EthereumReceipt as Receipt};
}
/// Type alias for the ethereum block

View File

@@ -1,42 +1,8 @@
use core::fmt::Debug;
use alloc::vec::Vec;
use alloy_consensus::{
Eip2718DecodableReceipt, Eip2718EncodableReceipt, Eip658Value, ReceiptEnvelope,
ReceiptWithBloom, RlpDecodableReceipt, RlpEncodableReceipt, TxReceipt, TxType, Typed2718,
};
use alloy_eips::eip2718::{Eip2718Error, Eip2718Result, Encodable2718, IsTyped2718};
use alloy_primitives::{Bloom, Log, B256};
use alloy_rlp::{BufMut, Decodable, Encodable, Header, RlpDecodable, RlpEncodable};
use reth_primitives_traits::{proofs::ordered_trie_root_with_encoder, InMemorySize};
/// Helper trait alias with requirements for transaction type generic to be used within [`Receipt`].
pub trait TxTy:
Debug
+ Copy
+ Eq
+ Send
+ Sync
+ InMemorySize
+ Typed2718
+ TryFrom<u8, Error = Eip2718Error>
+ Decodable
+ 'static
{
}
impl<T> TxTy for T where
T: Debug
+ Copy
+ Eq
+ Send
+ Sync
+ InMemorySize
+ Typed2718
+ TryFrom<u8, Error = Eip2718Error>
+ Decodable
+ 'static
{
}
use alloy_consensus::TxType;
pub use alloy_consensus::{EthereumReceipt, TxTy};
use alloy_eips::eip2718::Encodable2718;
use alloy_primitives::B256;
use reth_primitives_traits::proofs::ordered_trie_root_with_encoder;
/// Raw ethereum receipt.
pub type Receipt<T = TxType> = EthereumReceipt<T>;
@@ -45,528 +11,25 @@ pub type Receipt<T = TxType> = EthereumReceipt<T>;
/// Receipt representation for RPC.
pub type RpcReceipt<T = TxType> = EthereumReceipt<T, alloy_rpc_types_eth::Log>;
/// Typed ethereum transaction receipt.
/// Receipt containing result of transaction execution.
#[derive(Clone, Debug, PartialEq, Eq, Default, RlpEncodable, RlpDecodable)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "reth-codec", reth_codecs::add_arbitrary_tests(compact, rlp))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct EthereumReceipt<T = TxType, L = Log> {
/// Receipt type.
#[cfg_attr(feature = "serde", serde(rename = "type"))]
pub tx_type: T,
/// If transaction is executed successfully.
///
/// This is the `statusCode`
#[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity", rename = "status"))]
pub success: bool,
/// Gas used
#[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
pub cumulative_gas_used: u64,
/// Log send from contracts.
pub logs: Vec<L>,
/// Calculates the receipt root for a header for the reference type of [`Receipt`].
///
/// NOTE: Prefer `proofs::calculate_receipt_root` if you have log blooms memoized.
pub fn calculate_receipt_root_no_memo<T: TxTy>(receipts: &[Receipt<T>]) -> B256 {
ordered_trie_root_with_encoder(receipts, |r, buf| {
alloy_consensus::TxReceipt::with_bloom_ref(r).encode_2718(buf)
})
}
#[cfg(feature = "rpc")]
impl<T> Receipt<T> {
/// Converts the logs of the receipt to RPC logs.
pub fn into_rpc(
self,
next_log_index: usize,
meta: alloy_consensus::transaction::TransactionMeta,
) -> RpcReceipt<T> {
let Self { tx_type, success, cumulative_gas_used, logs } = self;
let logs = alloy_rpc_types_eth::Log::collect_for_receipt(next_log_index, meta, logs);
RpcReceipt { tx_type, success, cumulative_gas_used, logs }
}
}
impl<T: TxTy> Receipt<T> {
/// Returns length of RLP-encoded receipt fields with the given [`Bloom`] without an RLP header.
pub fn rlp_encoded_fields_length(&self, bloom: &Bloom) -> usize {
self.success.length() +
self.cumulative_gas_used.length() +
bloom.length() +
self.logs.length()
}
/// RLP-encodes receipt fields with the given [`Bloom`] without an RLP header.
pub fn rlp_encode_fields(&self, bloom: &Bloom, out: &mut dyn BufMut) {
self.success.encode(out);
self.cumulative_gas_used.encode(out);
bloom.encode(out);
self.logs.encode(out);
}
/// Returns RLP header for inner encoding.
pub fn rlp_header_inner(&self, bloom: &Bloom) -> Header {
Header { list: true, payload_length: self.rlp_encoded_fields_length(bloom) }
}
/// RLP-decodes the receipt from the provided buffer. This does not expect a type byte or
/// network header.
pub fn rlp_decode_inner(
buf: &mut &[u8],
tx_type: T,
) -> alloy_rlp::Result<ReceiptWithBloom<Self>> {
let header = Header::decode(buf)?;
if !header.list {
return Err(alloy_rlp::Error::UnexpectedString);
}
let remaining = buf.len();
let success = Decodable::decode(buf)?;
let cumulative_gas_used = Decodable::decode(buf)?;
let logs_bloom = Decodable::decode(buf)?;
let logs = Decodable::decode(buf)?;
if buf.len() + header.payload_length != remaining {
return Err(alloy_rlp::Error::UnexpectedLength);
}
Ok(ReceiptWithBloom {
receipt: Self { cumulative_gas_used, tx_type, success, logs },
logs_bloom,
})
}
/// Calculates the receipt root for a header for the reference type of [Receipt].
///
/// NOTE: Prefer `proofs::calculate_receipt_root` if you have log blooms memoized.
pub fn calculate_receipt_root_no_memo(receipts: &[Self]) -> B256 {
ordered_trie_root_with_encoder(receipts, |r, buf| r.with_bloom_ref().encode_2718(buf))
}
}
impl<T: TxTy> Eip2718EncodableReceipt for Receipt<T> {
fn eip2718_encoded_length_with_bloom(&self, bloom: &Bloom) -> usize {
!self.tx_type.is_legacy() as usize + self.rlp_header_inner(bloom).length_with_payload()
}
fn eip2718_encode_with_bloom(&self, bloom: &Bloom, out: &mut dyn BufMut) {
if !self.tx_type.is_legacy() {
out.put_u8(self.tx_type.ty());
}
self.rlp_header_inner(bloom).encode(out);
self.rlp_encode_fields(bloom, out);
}
}
impl<T: TxTy> Eip2718DecodableReceipt for Receipt<T> {
fn typed_decode_with_bloom(ty: u8, buf: &mut &[u8]) -> Eip2718Result<ReceiptWithBloom<Self>> {
Ok(Self::rlp_decode_inner(buf, T::try_from(ty)?)?)
}
fn fallback_decode_with_bloom(buf: &mut &[u8]) -> Eip2718Result<ReceiptWithBloom<Self>> {
Ok(Self::rlp_decode_inner(buf, T::try_from(0)?)?)
}
}
impl<T: TxTy> RlpEncodableReceipt for Receipt<T> {
fn rlp_encoded_length_with_bloom(&self, bloom: &Bloom) -> usize {
let mut len = self.eip2718_encoded_length_with_bloom(bloom);
if !self.tx_type.is_legacy() {
len += Header {
list: false,
payload_length: self.eip2718_encoded_length_with_bloom(bloom),
}
.length();
}
len
}
fn rlp_encode_with_bloom(&self, bloom: &Bloom, out: &mut dyn BufMut) {
if !self.tx_type.is_legacy() {
Header { list: false, payload_length: self.eip2718_encoded_length_with_bloom(bloom) }
.encode(out);
}
self.eip2718_encode_with_bloom(bloom, out);
}
}
impl<T: TxTy> RlpDecodableReceipt for Receipt<T> {
fn rlp_decode_with_bloom(buf: &mut &[u8]) -> alloy_rlp::Result<ReceiptWithBloom<Self>> {
let header_buf = &mut &**buf;
let header = Header::decode(header_buf)?;
// Legacy receipt, reuse initial buffer without advancing
if header.list {
return Self::rlp_decode_inner(buf, T::try_from(0)?)
}
// Otherwise, advance the buffer and try decoding type flag followed by receipt
*buf = *header_buf;
let remaining = buf.len();
let tx_type = T::decode(buf)?;
let this = Self::rlp_decode_inner(buf, tx_type)?;
if buf.len() + header.payload_length != remaining {
return Err(alloy_rlp::Error::UnexpectedLength);
}
Ok(this)
}
}
impl<T, L> TxReceipt for EthereumReceipt<T, L>
where
T: TxTy,
L: Send + Sync + Clone + Debug + Eq + AsRef<Log>,
{
type Log = L;
fn status_or_post_state(&self) -> Eip658Value {
self.success.into()
}
fn status(&self) -> bool {
self.success
}
fn bloom(&self) -> Bloom {
alloy_primitives::logs_bloom(self.logs.iter().map(|l| l.as_ref()))
}
fn cumulative_gas_used(&self) -> u64 {
self.cumulative_gas_used
}
fn logs(&self) -> &[L] {
&self.logs
}
fn into_logs(self) -> Vec<L> {
self.logs
}
}
impl<T: TxTy> Typed2718 for Receipt<T> {
fn ty(&self) -> u8 {
self.tx_type.ty()
}
}
impl<T: TxTy> IsTyped2718 for Receipt<T> {
fn is_type(type_id: u8) -> bool {
<TxType as IsTyped2718>::is_type(type_id)
}
}
impl<T: TxTy> InMemorySize for Receipt<T> {
fn size(&self) -> usize {
size_of::<Self>() + self.logs.iter().map(|log| log.size()).sum::<usize>()
}
}
impl<T> From<ReceiptEnvelope<T>> for Receipt<TxType>
where
T: Into<Log>,
{
fn from(value: ReceiptEnvelope<T>) -> Self {
let value = value.into_primitives_receipt();
Self {
tx_type: value.tx_type(),
success: value.is_success(),
cumulative_gas_used: value.cumulative_gas_used(),
logs: value.into_logs(),
}
}
}
impl<T, L> From<EthereumReceipt<T, L>> for alloy_consensus::Receipt<L> {
fn from(value: EthereumReceipt<T, L>) -> Self {
Self {
status: value.success.into(),
cumulative_gas_used: value.cumulative_gas_used,
logs: value.logs,
}
}
}
impl<L> From<EthereumReceipt<TxType, L>> for ReceiptEnvelope<L>
where
L: Send + Sync + Clone + Debug + Eq + AsRef<Log>,
{
fn from(value: EthereumReceipt<TxType, L>) -> Self {
let tx_type = value.tx_type;
let receipt = value.into_with_bloom().map_receipt(Into::into);
match tx_type {
TxType::Legacy => Self::Legacy(receipt),
TxType::Eip2930 => Self::Eip2930(receipt),
TxType::Eip1559 => Self::Eip1559(receipt),
TxType::Eip4844 => Self::Eip4844(receipt),
TxType::Eip7702 => Self::Eip7702(receipt),
}
}
}
#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))]
pub(super) mod serde_bincode_compat {
use alloc::{borrow::Cow, vec::Vec};
use alloy_consensus::TxType;
use alloy_eips::eip2718::Eip2718Error;
use alloy_primitives::{Log, U8};
use core::fmt::Debug;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_with::{DeserializeAs, SerializeAs};
/// Bincode-compatible [`super::Receipt`] serde implementation.
///
/// Intended to use with the [`serde_with::serde_as`] macro in the following way:
/// ```rust
/// use alloy_consensus::TxType;
/// use reth_ethereum_primitives::{serde_bincode_compat, Receipt};
/// use serde::{de::DeserializeOwned, Deserialize, Serialize};
/// use serde_with::serde_as;
///
/// #[serde_as]
/// #[derive(Serialize, Deserialize)]
/// struct Data {
/// #[serde_as(as = "serde_bincode_compat::Receipt<'_>")]
/// receipt: Receipt<TxType>,
/// }
/// ```
#[derive(Debug, Serialize, Deserialize)]
#[serde(bound(deserialize = "T: TryFrom<u8, Error = Eip2718Error>"))]
pub struct Receipt<'a, T = TxType> {
/// Receipt type.
#[serde(deserialize_with = "deserde_txtype")]
pub tx_type: T,
/// If transaction is executed successfully.
///
/// This is the `statusCode`
pub success: bool,
/// Gas used
pub cumulative_gas_used: u64,
/// Log send from contracts.
pub logs: Cow<'a, Vec<Log>>,
}
/// Ensures that txtype is deserialized symmetrically as U8
fn deserde_txtype<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
T: TryFrom<u8, Error = Eip2718Error>,
{
U8::deserialize(deserializer)?.to::<u8>().try_into().map_err(serde::de::Error::custom)
}
impl<'a, T: Copy> From<&'a super::Receipt<T>> for Receipt<'a, T> {
fn from(value: &'a super::Receipt<T>) -> Self {
Self {
tx_type: value.tx_type,
success: value.success,
cumulative_gas_used: value.cumulative_gas_used,
logs: Cow::Borrowed(&value.logs),
}
}
}
impl<'a, T> From<Receipt<'a, T>> for super::Receipt<T> {
fn from(value: Receipt<'a, T>) -> Self {
Self {
tx_type: value.tx_type,
success: value.success,
cumulative_gas_used: value.cumulative_gas_used,
logs: value.logs.into_owned(),
}
}
}
impl<T: Copy + Serialize> SerializeAs<super::Receipt<T>> for Receipt<'_, T> {
fn serialize_as<S>(source: &super::Receipt<T>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
Receipt::<'_>::from(source).serialize(serializer)
}
}
impl<'de, T: TryFrom<u8, Error = Eip2718Error>> DeserializeAs<'de, super::Receipt<T>>
for Receipt<'de, T>
{
fn deserialize_as<D>(deserializer: D) -> Result<super::Receipt<T>, D::Error>
where
D: Deserializer<'de>,
{
Receipt::<'_, T>::deserialize(deserializer).map(Into::into)
}
}
impl<T> reth_primitives_traits::serde_bincode_compat::SerdeBincodeCompat for super::Receipt<T>
where
T: Copy + Serialize + TryFrom<u8, Error = Eip2718Error> + Debug + 'static,
{
type BincodeRepr<'a> = Receipt<'a, T>;
fn as_repr(&self) -> Self::BincodeRepr<'_> {
self.into()
}
fn from_repr(repr: Self::BincodeRepr<'_>) -> Self {
repr.into()
}
}
#[cfg(test)]
mod tests {
use crate::{receipt::serde_bincode_compat, Receipt};
use alloy_consensus::TxType;
use arbitrary::Arbitrary;
use rand::Rng;
use serde_with::serde_as;
#[test]
fn test_receipt_bincode_roundtrip() {
#[serde_as]
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
struct Data {
#[serde_as(as = "serde_bincode_compat::Receipt<'_, TxType>")]
receipt: Receipt<TxType>,
}
let mut bytes = [0u8; 1024];
rand::rng().fill(bytes.as_mut_slice());
let data = Data {
receipt: Receipt::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap(),
};
let encoded = bincode::serialize(&data).unwrap();
let decoded: Data = bincode::deserialize(&encoded).unwrap();
assert_eq!(decoded, data);
}
}
}
#[cfg(feature = "reth-codec")]
mod compact {
use super::*;
use reth_codecs::{
Compact,
__private::{modular_bitfield::prelude::*, Buf},
};
impl Receipt {
#[doc = "Used bytes by [`ReceiptFlags`]"]
pub const fn bitflag_encoded_bytes() -> usize {
1u8 as usize
}
#[doc = "Unused bits for new fields by [`ReceiptFlags`]"]
pub const fn bitflag_unused_bits() -> usize {
0u8 as usize
}
}
#[allow(non_snake_case, unused_parens)]
mod flags {
use super::*;
#[doc = "Fieldset that facilitates compacting the parent type. Used bytes: 1 | Unused bits: 0"]
#[bitfield]
#[derive(Clone, Copy, Debug, Default)]
pub struct ReceiptFlags {
pub tx_type_len: B2,
pub success_len: B1,
pub cumulative_gas_used_len: B4,
pub __zstd: B1,
}
impl ReceiptFlags {
#[doc = r" Deserializes this fieldset and returns it, alongside the original slice in an advanced position."]
pub fn from(mut buf: &[u8]) -> (Self, &[u8]) {
(Self::from_bytes([buf.get_u8()]), buf)
}
}
}
pub use flags::ReceiptFlags;
impl<T: Compact> Compact for Receipt<T> {
fn to_compact<B>(&self, buf: &mut B) -> usize
where
B: reth_codecs::__private::bytes::BufMut + AsMut<[u8]>,
{
let mut flags = ReceiptFlags::default();
let mut total_length = 0;
let mut buffer = reth_codecs::__private::bytes::BytesMut::new();
let tx_type_len = self.tx_type.to_compact(&mut buffer);
flags.set_tx_type_len(tx_type_len as u8);
let success_len = self.success.to_compact(&mut buffer);
flags.set_success_len(success_len as u8);
let cumulative_gas_used_len = self.cumulative_gas_used.to_compact(&mut buffer);
flags.set_cumulative_gas_used_len(cumulative_gas_used_len as u8);
self.logs.to_compact(&mut buffer);
let zstd = buffer.len() > 7;
if zstd {
flags.set___zstd(1);
}
let flags = flags.into_bytes();
total_length += flags.len() + buffer.len();
buf.put_slice(&flags);
if zstd {
reth_zstd_compressors::with_receipt_compressor(|compressor| {
let compressed = compressor.compress(&buffer).expect("Failed to compress.");
buf.put(compressed.as_slice());
});
} else {
buf.put(buffer);
}
total_length
}
fn from_compact(buf: &[u8], _len: usize) -> (Self, &[u8]) {
let (flags, mut buf) = ReceiptFlags::from(buf);
if flags.__zstd() != 0 {
reth_zstd_compressors::with_receipt_decompressor(|decompressor| {
let decompressed = decompressor.decompress(buf);
let original_buf = buf;
let mut buf: &[u8] = decompressed;
let (tx_type, new_buf) = T::from_compact(buf, flags.tx_type_len() as usize);
buf = new_buf;
let (success, new_buf) = bool::from_compact(buf, flags.success_len() as usize);
buf = new_buf;
let (cumulative_gas_used, new_buf) =
u64::from_compact(buf, flags.cumulative_gas_used_len() as usize);
buf = new_buf;
let (logs, _) = Vec::from_compact(buf, buf.len());
(Self { tx_type, success, cumulative_gas_used, logs }, original_buf)
})
} else {
let (tx_type, new_buf) = T::from_compact(buf, flags.tx_type_len() as usize);
buf = new_buf;
let (success, new_buf) = bool::from_compact(buf, flags.success_len() as usize);
buf = new_buf;
let (cumulative_gas_used, new_buf) =
u64::from_compact(buf, flags.cumulative_gas_used_len() as usize);
buf = new_buf;
let (logs, new_buf) = Vec::from_compact(buf, buf.len());
buf = new_buf;
let obj = Self { tx_type, success, cumulative_gas_used, logs };
(obj, buf)
}
}
}
}
#[cfg(feature = "reth-codec")]
pub use compact::*;
#[cfg(test)]
mod tests {
use super::*;
use crate::TransactionSigned;
use alloy_consensus::{ReceiptWithBloom, TxReceipt, TxType};
use alloy_eips::eip2718::Encodable2718;
use alloy_primitives::{
address, b256, bloom, bytes, hex_literal::hex, Address, Bytes, Log, LogData,
address, b256, bloom, bytes, hex_literal::hex, Address, Bloom, Bytes, Log, LogData,
};
use alloy_rlp::Decodable;
use alloy_rlp::{Decodable, Encodable};
use reth_codecs::Compact;
use reth_primitives_traits::proofs::{
calculate_receipt_root, calculate_transaction_root, calculate_withdrawals_root,
@@ -784,6 +247,8 @@ mod tests {
#[test]
#[cfg(feature = "rpc")]
fn test_receipt_serde() {
use alloy_consensus::ReceiptEnvelope;
let input = r#"{"status":"0x1","cumulativeGasUsed":"0x175cc0e","logs":[{"address":"0xa18b9ca2a78660d44ab38ae72e72b18792ffe413","topics":["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925","0x000000000000000000000000e7e7d8006cbff47bc6ac2dabf592c98e97502708","0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"],"data":"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","blockHash":"0xbf9e6a368a399f996a0f0b27cab4191c028c3c99f5f76ea08a5b70b961475fcb","blockNumber":"0x164b59f","blockTimestamp":"0x68c9a713","transactionHash":"0x533aa9e57865675bb94f41aa2895c0ac81eee69686c77af16149c301e19805f1","transactionIndex":"0x14d","logIndex":"0x238","removed":false}],"logsBloom":"0x00000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000400000040000000000000004000000000000000000000000000000000000000000000020000000000000000000000000080000000000000000000000000200000020000000000000000000000000000000000000000000000000000000000000020000010000000000000000000000000000000000000000000000000000000000000","type":"0x2","transactionHash":"0x533aa9e57865675bb94f41aa2895c0ac81eee69686c77af16149c301e19805f1","transactionIndex":"0x14d","blockHash":"0xbf9e6a368a399f996a0f0b27cab4191c028c3c99f5f76ea08a5b70b961475fcb","blockNumber":"0x164b59f","gasUsed":"0xb607","effectiveGasPrice":"0x4a3ee768","from":"0xe7e7d8006cbff47bc6ac2dabf592c98e97502708","to":"0xa18b9ca2a78660d44ab38ae72e72b18792ffe413","contractAddress":null}"#;
let receipt: RpcReceipt = serde_json::from_str(input).unwrap();
let envelope: ReceiptEnvelope<alloy_rpc_types_eth::Log> =

View File

@@ -1,6 +1,8 @@
//! This file contains the legacy reth `TransactionSigned` type that has been replaced with
//! alloy's TxEnvelope To test for consistency this is kept
extern crate alloc;
use alloc::vec::Vec;
use alloy_consensus::{
transaction::{RlpEcdsaDecodableTx, RlpEcdsaEncodableTx, SignerRecoverable, TxHashRef},

View File

@@ -411,7 +411,7 @@ impl ExecutionOutcome {
pub fn ethereum_receipts_root(&self, block_number: BlockNumber) -> Option<B256> {
self.generic_receipts_root_slow(
block_number,
reth_ethereum_primitives::Receipt::calculate_receipt_root_no_memo,
reth_ethereum_primitives::calculate_receipt_root_no_memo,
)
}
}

View File

@@ -346,6 +346,18 @@ mod block_bincode {
}
}
impl super::SerdeBincodeCompat for alloy_consensus::EthereumReceipt {
type BincodeRepr<'a> = alloy_consensus::serde_bincode_compat::EthereumReceipt<'a>;
fn as_repr(&self) -> Self::BincodeRepr<'_> {
self.into()
}
fn from_repr(repr: Self::BincodeRepr<'_>) -> Self {
repr.into()
}
}
#[cfg(feature = "op")]
impl super::SerdeBincodeCompat for op_alloy_consensus::OpReceipt {
type BincodeRepr<'a> = op_alloy_consensus::serde_bincode_compat::OpReceipt<'a>;

View File

@@ -78,6 +78,12 @@ impl InMemorySize for alloy_consensus::Receipt {
}
}
impl<T: InMemorySize> InMemorySize for alloy_consensus::EthereumReceipt<T> {
fn size(&self) -> usize {
core::mem::size_of::<Self>() + self.logs.iter().map(|log| log.size()).sum::<usize>()
}
}
impl InMemorySize for LogData {
fn size(&self) -> usize {
self.data.len() + core::mem::size_of_val(self.topics())

View File

@@ -78,8 +78,24 @@ impl<ChainSpec> EthReceiptConverter<ChainSpec> {
pub const fn new(chain_spec: Arc<ChainSpec>) -> Self {
Self {
chain_spec,
build_rpc_receipt: |receipt, next_log_index, meta| {
receipt.into_rpc(next_log_index, meta).into()
build_rpc_receipt: |receipt: Receipt, next_log_index, meta: TransactionMeta| {
let mut log_index = next_log_index;
receipt
.map_logs(|log| {
let idx = log_index;
log_index += 1;
Log {
inner: log,
block_hash: Some(meta.block_hash),
block_number: Some(meta.block_number),
block_timestamp: Some(meta.timestamp),
transaction_hash: Some(meta.tx_hash),
transaction_index: Some(meta.index),
log_index: Some(idx as u64),
removed: false,
}
})
.into()
},
}
}

View File

@@ -18,6 +18,7 @@ cond_mod!(
genesis_account,
header,
log,
receipt,
signature,
trie,
txkind,

View File

@@ -0,0 +1,122 @@
//! Compact implementation for [`AlloyEthereumReceipt`]
use crate::Compact;
use alloc::vec::Vec;
use alloy_consensus::EthereumReceipt as AlloyEthereumReceipt;
use alloy_primitives::Log;
use bytes::Buf;
use modular_bitfield::prelude::*;
#[allow(non_snake_case)]
mod flags {
use super::*;
/// Bitflag fieldset for receipt compact encoding.
///
/// Used bytes: 1 | Unused bits: 0
#[bitfield]
#[derive(Clone, Copy, Debug, Default)]
pub struct ReceiptFlags {
pub tx_type_len: B2,
pub success_len: B1,
pub cumulative_gas_used_len: B4,
pub __zstd: B1,
}
impl ReceiptFlags {
/// Deserializes this fieldset and returns it, alongside the original slice in an advanced
/// position.
pub fn from(mut buf: &[u8]) -> (Self, &[u8]) {
(Self::from_bytes([buf.get_u8()]), buf)
}
}
}
pub(crate) use flags::ReceiptFlags;
impl<T: Compact> Compact for AlloyEthereumReceipt<T> {
fn to_compact<B>(&self, buf: &mut B) -> usize
where
B: bytes::BufMut + AsMut<[u8]>,
{
let mut flags = ReceiptFlags::default();
let mut total_length = 0;
let mut buffer = bytes::BytesMut::new();
let tx_type_len = self.tx_type.to_compact(&mut buffer);
flags.set_tx_type_len(tx_type_len as u8);
let success_len = self.success.to_compact(&mut buffer);
flags.set_success_len(success_len as u8);
let cumulative_gas_used_len = self.cumulative_gas_used.to_compact(&mut buffer);
flags.set_cumulative_gas_used_len(cumulative_gas_used_len as u8);
self.logs.to_compact(&mut buffer);
let zstd = buffer.len() > 7;
if zstd {
flags.set___zstd(1);
}
let flags = flags.into_bytes();
total_length += flags.len() + buffer.len();
buf.put_slice(&flags);
if zstd {
reth_zstd_compressors::with_receipt_compressor(|compressor| {
let compressed = compressor.compress(&buffer).expect("Failed to compress.");
buf.put(compressed.as_slice());
});
} else {
buf.put(buffer);
}
total_length
}
fn from_compact(buf: &[u8], _len: usize) -> (Self, &[u8]) {
let (flags, mut buf) = ReceiptFlags::from(buf);
if flags.__zstd() != 0 {
reth_zstd_compressors::with_receipt_decompressor(|decompressor| {
let decompressed = decompressor.decompress(buf);
let original_buf = buf;
let mut buf: &[u8] = decompressed;
let (tx_type, new_buf) = T::from_compact(buf, flags.tx_type_len() as usize);
buf = new_buf;
let (success, new_buf) = bool::from_compact(buf, flags.success_len() as usize);
buf = new_buf;
let (cumulative_gas_used, new_buf) =
u64::from_compact(buf, flags.cumulative_gas_used_len() as usize);
buf = new_buf;
let (logs, _) = Vec::<Log>::from_compact(buf, buf.len());
(Self { tx_type, success, cumulative_gas_used, logs }, original_buf)
})
} else {
let (tx_type, new_buf) = T::from_compact(buf, flags.tx_type_len() as usize);
buf = new_buf;
let (success, new_buf) = bool::from_compact(buf, flags.success_len() as usize);
buf = new_buf;
let (cumulative_gas_used, new_buf) =
u64::from_compact(buf, flags.cumulative_gas_used_len() as usize);
buf = new_buf;
let (logs, new_buf) = Vec::<Log>::from_compact(buf, buf.len());
buf = new_buf;
let obj = Self { tx_type, success, cumulative_gas_used, logs };
(obj, buf)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloy_consensus::TxType;
use proptest::proptest;
use proptest_arbitrary_interop::arb;
proptest! {
#[test]
fn roundtrip_receipt(receipt in arb::<AlloyEthereumReceipt<TxType>>()) {
let mut compacted_receipt = Vec::<u8>::new();
let len = receipt.to_compact(&mut compacted_receipt);
let (decoded, _) = AlloyEthereumReceipt::<TxType>::from_compact(&compacted_receipt, len);
assert_eq!(receipt, decoded)
}
}
}

View File

@@ -343,7 +343,6 @@ mod tests {
assert_eq!(PruneCheckpoint::bitflag_encoded_bytes(), 1);
assert_eq!(PruneMode::bitflag_encoded_bytes(), 1);
assert_eq!(PruneSegment::bitflag_encoded_bytes(), 1);
assert_eq!(Receipt::bitflag_encoded_bytes(), 1);
assert_eq!(StageCheckpoint::bitflag_encoded_bytes(), 1);
assert_eq!(StageUnitCheckpoint::bitflag_encoded_bytes(), 1);
assert_eq!(StoredBlockBodyIndices::bitflag_encoded_bytes(), 1);
@@ -363,7 +362,6 @@ mod tests {
validate_bitflag_backwards_compat!(PruneCheckpoint, UnusedBits::NotZero);
validate_bitflag_backwards_compat!(PruneMode, UnusedBits::Zero);
validate_bitflag_backwards_compat!(PruneSegment, UnusedBits::Zero);
validate_bitflag_backwards_compat!(Receipt, UnusedBits::Zero);
validate_bitflag_backwards_compat!(StageCheckpoint, UnusedBits::NotZero);
validate_bitflag_backwards_compat!(StageUnitCheckpoint, UnusedBits::Zero);
validate_bitflag_backwards_compat!(StoredBlockBodyIndices, UnusedBits::Zero);