diff --git a/Cargo.lock b/Cargo.lock index a944292c9125..f4314782c69a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2753,7 +2753,7 @@ checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7" [[package]] name = "bin-version" -version = "1.73.0" +version = "1.74.0" dependencies = [ "const-str", "git-version", @@ -3727,7 +3727,7 @@ dependencies = [ "tokio", "tokio-stream", "tokio-util 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)", - "tonic 0.14.5", + "tonic 0.14.6", "tonic-build", "tonic-prost", "tonic-rustls", @@ -6076,7 +6076,7 @@ dependencies = [ "time", "tokio", "tokio-stream", - "tonic 0.14.5", + "tonic 0.14.6", "tonic-build", "tonic-prost", "tonic-prost-build", @@ -8406,7 +8406,7 @@ dependencies = [ [[package]] name = "minibytes" version = "0.1.0" -source = "git+https://github.com/mystenlabs/tidehunter.git?rev=9a0472f81e71e821e1f4f71e308c2580f16f9e05#9a0472f81e71e821e1f4f71e308c2580f16f9e05" +source = "git+https://github.com/mystenlabs/tidehunter.git?rev=14b04e9d8130c20fdc03a629c02fe50f628cb789#14b04e9d8130c20fdc03a629c02fe50f628cb789" dependencies = [ "bytes", "memmap2 0.7.1", @@ -9431,7 +9431,7 @@ dependencies = [ [[package]] name = "msim" version = "0.1.0" -source = "git+https://github.com/MystenLabs/mysten-sim.git?rev=53016c1a9038154b1e47b96f0a314efa7e7d809b#53016c1a9038154b1e47b96f0a314efa7e7d809b" +source = "git+https://github.com/MystenLabs/mysten-sim.git?rev=2c2ec3ffbc1e559c575dc7de1ff2498d1f6700f6#2c2ec3ffbc1e559c575dc7de1ff2498d1f6700f6" dependencies = [ "ahash 0.7.8", "async-task", @@ -9460,7 +9460,7 @@ dependencies = [ [[package]] name = "msim-macros" version = "0.1.0" -source = "git+https://github.com/MystenLabs/mysten-sim.git?rev=53016c1a9038154b1e47b96f0a314efa7e7d809b#53016c1a9038154b1e47b96f0a314efa7e7d809b" +source = "git+https://github.com/MystenLabs/mysten-sim.git?rev=2c2ec3ffbc1e559c575dc7de1ff2498d1f6700f6#2c2ec3ffbc1e559c575dc7de1ff2498d1f6700f6" dependencies = [ "darling 0.14.2", "proc-macro2", @@ -9541,10 +9541,12 @@ dependencies = [ "mysten-metrics", "once_cell", "parking_lot 0.12.3", + "prost-types 0.14.1", "rand 0.8.5", "serde_json", "sui-macros", "tempfile", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -9599,7 +9601,7 @@ dependencies = [ "sui-tls", "tokio", "tokio-rustls", - "tonic 0.14.5", + "tonic 0.14.6", "tower 0.5.3", "tower-http 0.5.2", "tracing", @@ -11332,7 +11334,7 @@ version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac6c3320f9abac597dcbc668774ef006702672474aad53c6d596b62e487b40b1" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "itertools 0.14.0", "log", "multimap", @@ -13805,7 +13807,7 @@ checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" [[package]] name = "sui" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anemo", "anyhow", @@ -14068,7 +14070,7 @@ dependencies = [ [[package]] name = "sui-analytics-indexer" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "arrow", @@ -14127,7 +14129,7 @@ dependencies = [ [[package]] name = "sui-analytics-indexer-derive" -version = "1.73.0" +version = "1.74.0" dependencies = [ "proc-macro2", "quote", @@ -14200,7 +14202,7 @@ dependencies = [ [[package]] name = "sui-bridge" -version = "1.73.0" +version = "1.74.0" dependencies = [ "alloy", "alloy-multiprovider-strategy", @@ -14250,7 +14252,7 @@ dependencies = [ "test-cluster", "thiserror 1.0.69", "tokio", - "tonic 0.14.5", + "tonic 0.14.6", "tower 0.5.3", "tracing", "typed-store", @@ -14259,7 +14261,7 @@ dependencies = [ [[package]] name = "sui-bridge-cli" -version = "1.73.0" +version = "1.74.0" dependencies = [ "alloy", "anyhow", @@ -14355,7 +14357,7 @@ dependencies = [ [[package]] name = "sui-checkpoint-blob-indexer" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "async-trait", @@ -14386,7 +14388,7 @@ dependencies = [ [[package]] name = "sui-cluster-test" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "async-trait", @@ -14515,6 +14517,7 @@ dependencies = [ "reqwest", "roaring", "rstest", + "rustc-hash 2.1.1", "scopeguard", "serde", "serde_json", @@ -14530,6 +14533,7 @@ dependencies = [ "sui-execution", "sui-framework", "sui-genesis-builder", + "sui-inverted-index", "sui-json-rpc-types", "sui-macros", "sui-move", @@ -14583,7 +14587,7 @@ dependencies = [ [[package]] name = "sui-crypto" version = "0.3.0" -source = "git+https://github.com/MystenLabs/sui-rust-sdk.git?rev=f7487a58c6c31f07da08ba1c0cd81ebb8fe90ddd#f7487a58c6c31f07da08ba1c0cd81ebb8fe90ddd" +source = "git+https://github.com/MystenLabs/sui-rust-sdk.git?rev=5b41bc701525f1b94f1fe63008d4841bc6fb1065#5b41bc701525f1b94f1fe63008d4841bc6fb1065" dependencies = [ "ark-bn254", "ark-ff 0.4.2", @@ -14591,6 +14595,7 @@ dependencies = [ "ark-snark", "ark-std 0.4.0", "base64ct", + "blst", "bnum", "ed25519-dalek", "itertools 0.14.0", @@ -14657,7 +14662,7 @@ dependencies = [ [[package]] name = "sui-default-config" -version = "1.73.0" +version = "1.74.0" dependencies = [ "quote", "syn 1.0.107", @@ -14665,7 +14670,7 @@ dependencies = [ [[package]] name = "sui-display" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "async-trait", @@ -14689,7 +14694,7 @@ dependencies = [ [[package]] name = "sui-e2e-tests" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "async-trait", @@ -14707,6 +14712,7 @@ dependencies = [ "move-core-types", "mysten-common", "mysten-metrics", + "mysten-network", "p256", "passkey-authenticator", "passkey-client", @@ -14749,7 +14755,7 @@ dependencies = [ "test-cluster", "tokio", "tokio-stream", - "tonic 0.14.5", + "tonic 0.14.6", "tracing", "url", ] @@ -14825,7 +14831,7 @@ dependencies = [ [[package]] name = "sui-faucet" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "axum 0.8.3", @@ -14837,6 +14843,7 @@ dependencies = [ "serde_json", "shared-crypto", "sui-config", + "sui-futures", "sui-keys", "sui-rpc-api", "sui-sdk", @@ -14851,14 +14858,14 @@ dependencies = [ [[package]] name = "sui-field-count" -version = "1.73.0" +version = "1.74.0" dependencies = [ "sui-field-count-derive", ] [[package]] name = "sui-field-count-derive" -version = "1.73.0" +version = "1.74.0" dependencies = [ "quote", "syn 1.0.107", @@ -14866,7 +14873,7 @@ dependencies = [ [[package]] name = "sui-fork" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "async-trait", @@ -14893,7 +14900,7 @@ dependencies = [ "sui-types", "tempfile", "tokio", - "tonic 0.14.5", + "tonic 0.14.6", "tonic-prost", "tracing", "tracing-subscriber", @@ -14925,7 +14932,7 @@ dependencies = [ [[package]] name = "sui-framework-snapshot" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "bcs", @@ -14969,7 +14976,7 @@ dependencies = [ [[package]] name = "sui-futures" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "futures", @@ -15029,7 +15036,7 @@ dependencies = [ [[package]] name = "sui-indexer-alt" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "async-trait", @@ -15062,12 +15069,12 @@ dependencies = [ [[package]] name = "sui-indexer-alt-consistent-api" -version = "1.73.0" +version = "1.74.0" dependencies = [ "prost 0.14.1", "prost-types 0.14.1", "protox", - "tonic 0.14.5", + "tonic 0.14.6", "tonic-prost", "tonic-prost-build", "walkdir", @@ -15075,7 +15082,7 @@ dependencies = [ [[package]] name = "sui-indexer-alt-consistent-store" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "async-trait", @@ -15116,7 +15123,7 @@ dependencies = [ "tokio", "tokio-stream", "toml 0.7.4", - "tonic 0.14.5", + "tonic 0.14.6", "tonic-health", "tonic-reflection", "tower 0.5.3", @@ -15188,7 +15195,7 @@ dependencies = [ "test-cluster", "tokio", "tokio-stream", - "tonic 0.14.5", + "tonic 0.14.6", "tracing", "url", "zstd 0.12.3+zstd.1.5.2", @@ -15196,7 +15203,7 @@ dependencies = [ [[package]] name = "sui-indexer-alt-framework" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "async-trait", @@ -15235,7 +15242,7 @@ dependencies = [ "thiserror 1.0.69", "tokio", "tokio-stream", - "tonic 0.14.5", + "tonic 0.14.6", "tracing", "tracing-subscriber", "url", @@ -15245,7 +15252,7 @@ dependencies = [ [[package]] name = "sui-indexer-alt-framework-store-traits" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "async-trait", @@ -15257,7 +15264,7 @@ dependencies = [ [[package]] name = "sui-indexer-alt-graphql" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "async-graphql", @@ -15315,7 +15322,7 @@ dependencies = [ "tokio", "tokio-stream", "toml 0.7.4", - "tonic 0.14.5", + "tonic 0.14.6", "tower-http 0.5.2", "tracing", "url", @@ -15324,7 +15331,7 @@ dependencies = [ [[package]] name = "sui-indexer-alt-jsonrpc" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "async-graphql", @@ -15375,7 +15382,7 @@ dependencies = [ "thiserror 1.0.69", "tokio", "toml 0.7.4", - "tonic 0.14.5", + "tonic 0.14.6", "tower 0.4.13", "tower-http 0.5.2", "tower-layer", @@ -15385,7 +15392,7 @@ dependencies = [ [[package]] name = "sui-indexer-alt-metrics" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "axum 0.8.3", @@ -15400,7 +15407,7 @@ dependencies = [ [[package]] name = "sui-indexer-alt-object-store" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "async-trait", @@ -15414,7 +15421,7 @@ dependencies = [ [[package]] name = "sui-indexer-alt-reader" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "async-graphql", @@ -15442,7 +15449,7 @@ dependencies = [ "sui-types", "thiserror 1.0.69", "tokio", - "tonic 0.14.5", + "tonic 0.14.6", "tower 0.5.3", "tracing", "url", @@ -15450,7 +15457,7 @@ dependencies = [ [[package]] name = "sui-indexer-alt-schema" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "bcs", @@ -15466,16 +15473,16 @@ dependencies = [ [[package]] name = "sui-inverted-index" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "async-stream", "bcs", "futures", - "itertools 0.13.0", "move-core-types", "roaring", "sui-types", + "thiserror 1.0.69", "tokio", ] @@ -15678,7 +15685,7 @@ dependencies = [ [[package]] name = "sui-kv-rpc" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "async-stream", @@ -15699,7 +15706,10 @@ dependencies = [ "prost 0.14.1", "prost-types 0.14.1", "rustls", + "schemars 0.8.21", "serde", + "serde_json", + "serde_yaml 0.8.26", "sui-futures", "sui-inverted-index", "sui-kvstore", @@ -15711,8 +15721,9 @@ dependencies = [ "sui-storage", "sui-types", "telemetry-subscribers", + "thiserror 1.0.69", "tokio", - "tonic 0.14.5", + "tonic 0.14.6", "tonic-prost", "tonic-reflection", "tracing", @@ -15720,7 +15731,7 @@ dependencies = [ [[package]] name = "sui-kvstore" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "arc-swap", @@ -15764,7 +15775,7 @@ dependencies = [ "tokio", "tokio-stream", "toml 0.7.4", - "tonic 0.14.5", + "tonic 0.14.6", "tonic-prost", "tracing", "url", @@ -15772,7 +15783,7 @@ dependencies = [ [[package]] name = "sui-light-client" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "async-trait", @@ -15805,7 +15816,7 @@ dependencies = [ "thiserror 1.0.69", "tokio", "tokio-stream", - "tonic 0.14.5", + "tonic 0.14.6", "tracing", "url", ] @@ -15822,7 +15833,7 @@ dependencies = [ [[package]] name = "sui-metric-checker" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "backoff", @@ -15859,7 +15870,7 @@ dependencies = [ [[package]] name = "sui-move" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "bin-version", @@ -15906,7 +15917,7 @@ dependencies = [ [[package]] name = "sui-move-build" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "fastcrypto", @@ -15932,7 +15943,7 @@ dependencies = [ [[package]] name = "sui-move-lsp" -version = "1.73.0" +version = "1.74.0" dependencies = [ "bin-version", "clap", @@ -16047,7 +16058,7 @@ dependencies = [ [[package]] name = "sui-name-service" -version = "1.73.0" +version = "1.74.0" dependencies = [ "bcs", "move-core-types", @@ -16101,7 +16112,7 @@ dependencies = [ "tempfile", "tokio", "tokio-rustls", - "tonic 0.14.5", + "tonic 0.14.6", "tonic-build", "tonic-health", "tonic-prost", @@ -16114,7 +16125,7 @@ dependencies = [ [[package]] name = "sui-node" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anemo", "anemo-tower", @@ -16169,7 +16180,7 @@ dependencies = [ [[package]] name = "sui-open-rpc" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "bcs", @@ -16203,7 +16214,7 @@ dependencies = [ [[package]] name = "sui-oracle" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "bcs", @@ -16233,7 +16244,7 @@ dependencies = [ [[package]] name = "sui-package-alt" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "async-trait", @@ -16252,7 +16263,7 @@ dependencies = [ [[package]] name = "sui-package-dump" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "bcs", @@ -16268,7 +16279,7 @@ dependencies = [ [[package]] name = "sui-package-management" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "sui-framework-snapshot", @@ -16301,7 +16312,7 @@ dependencies = [ [[package]] name = "sui-pg-db" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "async-trait", @@ -16350,6 +16361,7 @@ dependencies = [ "move-core-types", "move-vm-config", "mysten-common", + "prost-types 0.14.1", "rand 0.8.5", "schemars 0.8.21", "serde", @@ -16497,7 +16509,7 @@ dependencies = [ [[package]] name = "sui-rosetta" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "async-trait", @@ -16538,14 +16550,14 @@ dependencies = [ "test-cluster", "thiserror 1.0.69", "tokio", - "tonic 0.14.5", + "tonic 0.14.6", "tracing", ] [[package]] name = "sui-rpc" version = "0.3.1" -source = "git+https://github.com/MystenLabs/sui-rust-sdk.git?rev=f7487a58c6c31f07da08ba1c0cd81ebb8fe90ddd#f7487a58c6c31f07da08ba1c0cd81ebb8fe90ddd" +source = "git+https://github.com/MystenLabs/sui-rust-sdk.git?rev=5b41bc701525f1b94f1fe63008d4841bc6fb1065#5b41bc701525f1b94f1fe63008d4841bc6fb1065" dependencies = [ "base64 0.22.1", "bcs", @@ -16557,10 +16569,11 @@ dependencies = [ "prost-types 0.14.1", "serde", "serde_json", + "sui-crypto", "sui-sdk-types", "tap", "tokio", - "tonic 0.14.5", + "tonic 0.14.6", "tonic-prost", "tower 0.5.3", ] @@ -16588,11 +16601,13 @@ dependencies = [ "prost-types 0.14.1", "protox", "rand 0.8.5", + "roaring", "serde", "serde_json", "sui-config", "sui-crypto", "sui-display", + "sui-inverted-index", "sui-macros", "sui-name-service", "sui-package-resolver", @@ -16604,7 +16619,8 @@ dependencies = [ "sui-types", "tap", "tokio", - "tonic 0.14.5", + "tokio-util 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)", + "tonic 0.14.6", "tonic-health", "tonic-prost", "tonic-prost-build", @@ -16617,7 +16633,7 @@ dependencies = [ [[package]] name = "sui-rpc-benchmark" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "bb8", @@ -16642,7 +16658,7 @@ dependencies = [ [[package]] name = "sui-rpc-loadgen" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "async-trait", @@ -16663,13 +16679,13 @@ dependencies = [ "sui-types", "telemetry-subscribers", "tokio", - "tonic 0.14.5", + "tonic 0.14.6", "tracing", ] [[package]] name = "sui-rpc-resolver" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "async-trait", @@ -16688,7 +16704,7 @@ dependencies = [ [[package]] name = "sui-sdk" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "async-trait", @@ -16732,7 +16748,7 @@ dependencies = [ [[package]] name = "sui-sdk-types" version = "0.3.1" -source = "git+https://github.com/MystenLabs/sui-rust-sdk.git?rev=f7487a58c6c31f07da08ba1c0cd81ebb8fe90ddd#f7487a58c6c31f07da08ba1c0cd81ebb8fe90ddd" +source = "git+https://github.com/MystenLabs/sui-rust-sdk.git?rev=5b41bc701525f1b94f1fe63008d4841bc6fb1065#5b41bc701525f1b94f1fe63008d4841bc6fb1065" dependencies = [ "base64ct", "bcs", @@ -16752,7 +16768,7 @@ dependencies = [ [[package]] name = "sui-security-watchdog" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "arrow-array", @@ -16800,7 +16816,7 @@ dependencies = [ [[package]] name = "sui-single-node-benchmark" -version = "1.73.0" +version = "1.74.0" dependencies = [ "bcs", "clap", @@ -16859,7 +16875,7 @@ dependencies = [ [[package]] name = "sui-source-validation" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "colored", @@ -16902,7 +16918,7 @@ dependencies = [ [[package]] name = "sui-sql-macro" -version = "1.73.0" +version = "1.74.0" dependencies = [ "quote", "syn 1.0.107", @@ -16968,7 +16984,7 @@ dependencies = [ [[package]] name = "sui-surfer" -version = "1.73.0" +version = "1.74.0" dependencies = [ "bcs", "clap", @@ -17090,7 +17106,7 @@ dependencies = [ [[package]] name = "sui-test-validator" -version = "1.73.0" +version = "1.74.0" [[package]] name = "sui-tls" @@ -17116,7 +17132,7 @@ dependencies = [ [[package]] name = "sui-tool" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anemo", "anemo-cli", @@ -17324,7 +17340,7 @@ dependencies = [ "tap", "thiserror 1.0.69", "tokio", - "tonic 0.14.5", + "tonic 0.14.6", "tracing", "typed-store-error", "url", @@ -17806,7 +17822,7 @@ dependencies = [ "sui-test-transaction-builder", "sui-types", "tokio", - "tonic 0.14.5", + "tonic 0.14.6", "tracing", ] @@ -17965,7 +17981,7 @@ dependencies = [ [[package]] name = "tideconsole" version = "0.1.0" -source = "git+https://github.com/mystenlabs/tidehunter.git?rev=9a0472f81e71e821e1f4f71e308c2580f16f9e05#9a0472f81e71e821e1f4f71e308c2580f16f9e05" +source = "git+https://github.com/mystenlabs/tidehunter.git?rev=14b04e9d8130c20fdc03a629c02fe50f628cb789#14b04e9d8130c20fdc03a629c02fe50f628cb789" dependencies = [ "anyhow", "clap", @@ -17979,7 +17995,7 @@ dependencies = [ [[package]] name = "tidehunter" version = "0.1.0" -source = "git+https://github.com/mystenlabs/tidehunter.git?rev=9a0472f81e71e821e1f4f71e308c2580f16f9e05#9a0472f81e71e821e1f4f71e308c2580f16f9e05" +source = "git+https://github.com/mystenlabs/tidehunter.git?rev=14b04e9d8130c20fdc03a629c02fe50f628cb789#14b04e9d8130c20fdc03a629c02fe50f628cb789" dependencies = [ "arc-swap", "bincode 1.3.3", @@ -17989,6 +18005,7 @@ dependencies = [ "crc32fast", "libc", "lru 0.12.5", + "lz4_flex", "memmap2 0.7.1", "minibytes", "parking_lot 0.12.3", @@ -18445,8 +18462,9 @@ dependencies = [ [[package]] name = "tonic" -version = "0.14.5" -source = "git+https://github.com/hyperium/tonic.git?rev=d6ce69b0d93e1de21b0769e942ace00b48f52e17#d6ce69b0d93e1de21b0769e942ace00b48f52e17" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" dependencies = [ "async-trait", "axum 0.8.3", @@ -18478,9 +18496,9 @@ dependencies = [ [[package]] name = "tonic-build" -version = "0.14.2" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40aaccc9f9eccf2cd82ebc111adc13030d23e887244bc9cfa5d1d636049de3" +checksum = "c68f61875ac5293cf72e6c8cf0158086428c82c37229e98c840878f1706b0322" dependencies = [ "prettyplease", "proc-macro2", @@ -18490,32 +18508,33 @@ dependencies = [ [[package]] name = "tonic-health" -version = "0.14.2" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a82868bf299e0a1d2e8dce0dc33a46c02d6f045b2c1f1d6cc8dc3d0bf1812ef" +checksum = "fcfab99db777fba2802f0dfa861d1628d1ae916fb199d29819941f139ae85082" dependencies = [ "prost 0.14.1", "tokio", "tokio-stream", - "tonic 0.14.5", + "tonic 0.14.6", "tonic-prost", ] [[package]] name = "tonic-prost" -version = "0.14.5" -source = "git+https://github.com/hyperium/tonic.git?rev=d6ce69b0d93e1de21b0769e942ace00b48f52e17#d6ce69b0d93e1de21b0769e942ace00b48f52e17" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50849f68853be452acf590cde0b146665b8d507b3b8af17261df47e02c209ea0" dependencies = [ "bytes", "prost 0.14.1", - "tonic 0.14.5", + "tonic 0.14.6", ] [[package]] name = "tonic-prost-build" -version = "0.14.2" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4a16cba4043dc3ff43fcb3f96b4c5c154c64cbd18ca8dce2ab2c6a451d058a2" +checksum = "654e5643eff75d7f8c99197ce1440ed19a3474eada74c12bbac488b2cafdae27" dependencies = [ "prettyplease", "proc-macro2", @@ -18529,14 +18548,15 @@ dependencies = [ [[package]] name = "tonic-reflection" -version = "0.14.5" -source = "git+https://github.com/hyperium/tonic.git?rev=d6ce69b0d93e1de21b0769e942ace00b48f52e17#d6ce69b0d93e1de21b0769e942ace00b48f52e17" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acccd136a4bf19810a1fde9c74edc6129b42a66b44d0c1c8aaa67aeb49a146a7" dependencies = [ "prost 0.14.1", "prost-types 0.14.1", "tokio", "tokio-stream", - "tonic 0.14.5", + "tonic 0.14.6", "tonic-prost", ] @@ -18560,7 +18580,7 @@ dependencies = [ "tokio", "tokio-rustls", "tokio-stream", - "tonic 0.14.5", + "tonic 0.14.6", "tower 0.5.3", "tower-layer", "tower-service", @@ -18569,9 +18589,9 @@ dependencies = [ [[package]] name = "tonic-web" -version = "0.14.2" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75214f6b6bd28c19aa752ac09fdf0eea546095670906c21fe3940e180a4c43f2" +checksum = "b5e6a1b6319ca4b61a4c0f0c94d439c8f3ed344cca56fe0df40e1fe4be11380b" dependencies = [ "base64 0.22.1", "bytes", @@ -18579,7 +18599,7 @@ dependencies = [ "http-body 1.0.1", "pin-project", "tokio-stream", - "tonic 0.14.5", + "tonic 0.14.6", "tower-layer", "tower-service", "tracing", @@ -18918,7 +18938,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", - "rand 0.7.3", + "rand 0.8.5", "static_assertions", ] @@ -20305,7 +20325,7 @@ dependencies = [ [[package]] name = "x" -version = "1.73.0" +version = "1.74.0" dependencies = [ "anyhow", "camino", diff --git a/crates/simulacrum/src/epoch_state.rs b/crates/simulacrum/src/epoch_state.rs index 4f1639d0ab89..c925a19c9241 100644 --- a/crates/simulacrum/src/epoch_state.rs +++ b/crates/simulacrum/src/epoch_state.rs @@ -150,26 +150,26 @@ impl EpochState { let transaction_data = transaction.data().transaction_data(); let (kind, signer, gas_data) = transaction_data.execution_parts(); - let (inner_temp_store, gas_status, effects, _timings, result) = self - .executor - .execute_transaction_to_effects_and_execution_error( - store.backing_store(), - &self.protocol_config, - self.execution_metrics.clone(), - false, // enable_expensive_checks - // TODO: Integrate with early execution error - ExecutionOrEarlyError::Ok(()), - &self.epoch_start_state.epoch(), - self.epoch_start_state.epoch_start_timestamp_ms(), - checked_input_objects, - gas_data, - gas_status, - kind, - None, // compat_args - signer, - tx_digest, - &mut None, - ); + let (inner_temp_store, gas_status, effects, _timings, result, _execution_error_metadata) = + self.executor + .execute_transaction_to_effects_and_execution_error( + store.backing_store(), + &self.protocol_config, + self.execution_metrics.clone(), + false, // enable_expensive_checks + // TODO: Integrate with early execution error + ExecutionOrEarlyError::Ok(()), + &self.epoch_start_state.epoch(), + self.epoch_start_state.epoch_start_timestamp_ms(), + checked_input_objects, + gas_data, + gas_status, + kind, + None, // compat_args + signer, + tx_digest, + &mut None, + ); Ok((inner_temp_store, gas_status, effects, result)) } } diff --git a/crates/sui-core/src/authority.rs b/crates/sui-core/src/authority.rs index 02b67ce8b4fc..dd96263062df 100644 --- a/crates/sui-core/src/authority.rs +++ b/crates/sui-core/src/authority.rs @@ -139,7 +139,7 @@ use sui_types::effects::{ InputConsensusObject, SignedTransactionEffects, TransactionEffects, TransactionEffectsAPI, TransactionEvents, VerifiedSignedTransactionEffects, }; -use sui_types::error::{ExecutionError, SuiErrorKind, UserInputError}; +use sui_types::error::{ExecutionError, ExecutionErrorMetadata, SuiErrorKind, UserInputError}; use sui_types::event::EventID; use sui_types::executable_transaction::VerifiedExecutableTransaction; use sui_types::execution_status::ExecutionErrorKind; @@ -1905,16 +1905,27 @@ impl AuthorityState { rewritten_inputs: Option>, signer: SuiAddress, tx_digest: TransactionDigest, + is_fullnode: bool, ) -> ( InnerTemporaryStore, SuiGasStatus, TransactionEffects, Vec, Result<(), ExecutionError>, + Option, ) { - let (inner_temp_store, gas_status, effects, timings, execution_error) = executor - // TODO only run this function on FullNodes, use `execute_transaction_to_effects` on validators. - .execute_transaction_to_effects_and_execution_error( + // Fullnodes retain source errors and VM metadata as sidecar data for richer user-facing + // error reporting. Validators use the lean execution path and intentionally return no + // sidecar metadata so effects stay independent of non-consensus data. + if is_fullnode { + let ( + inner_temp_store, + gas_status, + effects, + timings, + execution_error, + execution_error_metadata, + ) = executor.execute_transaction_to_effects_and_execution_error( store, protocol_config, self.metrics.execution_metrics.clone(), @@ -1932,13 +1943,43 @@ impl AuthorityState { &mut None, ); - ( - inner_temp_store, - gas_status, - effects, - timings, - execution_error, - ) + ( + inner_temp_store, + gas_status, + effects, + timings, + execution_error, + execution_error_metadata, + ) + } else { + let (inner_temp_store, gas_status, effects, timings, execution_failure) = executor + .execute_transaction_to_effects( + store, + protocol_config, + self.metrics.execution_metrics.clone(), + enable_expensive_checks, + execution_params, + epoch_id, + epoch_timestamp_ms, + input_objects, + gas_data, + gas_status, + kind, + rewritten_inputs, + signer, + tx_digest, + &mut None, + ); + + ( + inner_temp_store, + gas_status, + effects, + timings, + execution_failure.map_err(ExecutionError::from), + None, + ) + } } /// execute_certificate validates the transaction input, and executes the certificate, @@ -2025,30 +2066,39 @@ impl AuthorityState { let tracking_store = TrackingBackingStore::new(self.get_backing_store().as_ref()); #[allow(unused_mut)] - let (inner_temp_store, _, mut effects, timings, execution_error_opt) = self - .execute_transaction_to_effects( - &**epoch_store.executor(), - &tracking_store, - protocol_config, - // TODO: would be nice to pass the whole NodeConfig here, but it creates a - // cyclic dependency w/ sui-adapter - self.config - .expensive_safety_check_config - .enable_deep_per_tx_sui_conservation_check(), - execution_params, - &epoch_store.epoch_start_config().epoch_data().epoch_id(), - epoch_store - .epoch_start_config() - .epoch_data() - .epoch_start_timestamp(), - input_objects, - gas_data, - gas_status, - kind, - rewritten_inputs, - signer, - tx_digest, - ); + let ( + inner_temp_store, + _, + mut effects, + timings, + execution_error_opt, + execution_error_metadata, + ) = self.execute_transaction_to_effects( + &**epoch_store.executor(), + &tracking_store, + protocol_config, + // TODO: would be nice to pass the whole NodeConfig here, but it creates a + // cyclic dependency w/ sui-adapter + self.config + .expensive_safety_check_config + .enable_deep_per_tx_sui_conservation_check(), + execution_params, + &epoch_store.epoch_start_config().epoch_data().epoch_id(), + epoch_store + .epoch_start_config() + .epoch_data() + .epoch_start_timestamp(), + input_objects, + gas_data, + gas_status, + kind, + rewritten_inputs, + signer, + tx_digest, + self.is_fullnode(epoch_store), + ); + + let execution_error_opt = execution_error_opt.err(); let object_funds_checker = self.object_funds_checker.load(); if let Some(object_funds_checker) = object_funds_checker.as_ref() @@ -2174,6 +2224,7 @@ impl AuthorityState { effects, inner_temp_store, unchanged_loaded_runtime_objects, + execution_error_metadata, ); let elapsed = prepare_certificate_start_time.elapsed().as_micros() as f64; @@ -2187,7 +2238,7 @@ impl AuthorityState { ); } - ExecutionOutput::Success((transaction_outputs, timings, execution_error_opt.err())) + ExecutionOutput::Success((transaction_outputs, timings, execution_error_opt)) } pub fn prepare_certificate_for_benchmark( diff --git a/crates/sui-core/src/authority/authority_store.rs b/crates/sui-core/src/authority/authority_store.rs index 48160736004f..44012b6259b0 100644 --- a/crates/sui-core/src/authority/authority_store.rs +++ b/crates/sui-core/src/authority/authority_store.rs @@ -19,10 +19,12 @@ use fastcrypto::hash::{HashFunction, MultisetHash, Sha3_256}; use futures::stream::FuturesUnordered; use move_core_types::account_address::AccountAddress; use move_core_types::resolver::{ModuleResolver, SerializedPackage}; +use prost::Message as _; use serde::{Deserialize, Serialize}; use sui_config::node::AuthorityStorePruningConfig; use sui_macros::fail_point_arg; -use sui_types::error::{SuiErrorKind, UserInputError}; +use sui_rpc::proto::sui::rpc::v2::ExecutionErrorMetadata as RpcExecutionErrorMetadata; +use sui_types::error::{ExecutionErrorMetadata, SuiErrorKind, UserInputError}; use sui_types::execution::TypeLayoutStore; use sui_types::global_state_hash::GlobalStateHash; use sui_types::message_envelope::Message; @@ -344,6 +346,25 @@ impl AuthorityStore { .get(digest) } + pub fn get_execution_error_metadata( + &self, + digest: &TransactionDigest, + ) -> Result, TypedStoreError> { + self.perpetual_tables + .execution_error_metadata + .get(digest)? + .map(|bytes| { + RpcExecutionErrorMetadata::decode(bytes.as_slice()) + .map(|metadata| ExecutionErrorMetadata::from(&metadata)) + }) + .transpose() + .map_err(|err| { + TypedStoreError::SerializationError(format!( + "failed to decode execution error metadata: {err}" + )) + }) + } + pub fn multi_get_effects<'a>( &self, effects_digests: impl Iterator, @@ -791,6 +812,7 @@ impl AuthorityStore { written, events, unchanged_loaded_runtime_objects, + execution_error_metadata, locks_to_delete, new_locks_to_init, .. @@ -863,6 +885,16 @@ impl AuthorityStore { )?; } + if let Some(metadata) = execution_error_metadata + && !metadata.is_empty() + { + let metadata: RpcExecutionErrorMetadata = metadata.into(); + write_batch.insert_batch( + &self.perpetual_tables.execution_error_metadata, + [(transaction_digest, metadata.encode_to_vec())], + )?; + } + self.initialize_live_object_markers_impl(write_batch, new_locks_to_init, false)?; // Note: deletes locks for received objects as well (but not for objects that were in diff --git a/crates/sui-core/src/authority/authority_store_pruner.rs b/crates/sui-core/src/authority/authority_store_pruner.rs index 619fb81f0f1d..282537af3b0d 100644 --- a/crates/sui-core/src/authority/authority_store_pruner.rs +++ b/crates/sui-core/src/authority/authority_store_pruner.rs @@ -300,6 +300,8 @@ impl AuthorityStorePruner { &perpetual_db.unchanged_loaded_runtime_objects, transactions.iter(), )?; + perpetual_batch + .delete_batch(&perpetual_db.execution_error_metadata, transactions.iter())?; perpetual_batch.delete_batch(&perpetual_db.effects, effect_digests)?; let mut checkpoints_batch = checkpoint_db.tables.certified_checkpoints.batch(); diff --git a/crates/sui-core/src/authority/authority_store_tables.rs b/crates/sui-core/src/authority/authority_store_tables.rs index 7b306afbca75..5324d1c65419 100644 --- a/crates/sui-core/src/authority/authority_store_tables.rs +++ b/crates/sui-core/src/authority/authority_store_tables.rs @@ -100,6 +100,10 @@ pub struct AuthorityPerpetualTables { // Loaded (and unchanged) runtime object references. pub(crate) unchanged_loaded_runtime_objects: DBMap>, + // Local execution error metadata, keyed by the digest of the transaction that produced it. + // Values are encoded `sui_rpc::proto::sui::rpc::v2::ExecutionErrorMetadata` bytes. + pub(crate) execution_error_metadata: DBMap>, + /// DEPRECATED in favor of the table of the same name in authority_per_epoch_store. /// Please do not add new accessors/callsites. /// When transaction is executed via checkpoint executor, we store association here @@ -331,6 +335,16 @@ impl AuthorityPerpetualTables { digest_prefix.clone(), ), ), + ( + "execution_error_metadata".to_string(), + ThConfig::new_with_rm_prefix( + 32, + mutexes, + uniform_key, + KeySpaceConfig::default().with_relocation_filter(|_, _| Decision::Remove), + digest_prefix.clone(), + ), + ), ( "executed_transactions_to_checkpoint".to_string(), ThConfig::new_with_rm_prefix( diff --git a/crates/sui-core/src/checkpoints/checkpoint_executor/data_ingestion_handler.rs b/crates/sui-core/src/checkpoints/checkpoint_executor/data_ingestion_handler.rs index bc865f3de6ef..053934e176cd 100644 --- a/crates/sui-core/src/checkpoints/checkpoint_executor/data_ingestion_handler.rs +++ b/crates/sui-core/src/checkpoints/checkpoint_executor/data_ingestion_handler.rs @@ -123,6 +123,8 @@ pub(crate) fn load_checkpoint( signatures: tx.tx_signatures().to_vec(), effects: fx.clone(), events, + execution_error_metadata: transaction_cache_reader + .get_execution_error_metadata(tx.digest()), unchanged_loaded_runtime_objects: transaction_cache_reader .get_unchanged_loaded_runtime_objects(tx.digest()) // We don't write empty sets to the DB to save space, so if this load went through diff --git a/crates/sui-core/src/checkpoints/mod.rs b/crates/sui-core/src/checkpoints/mod.rs index c03918092818..dfe16eb96e48 100644 --- a/crates/sui-core/src/checkpoints/mod.rs +++ b/crates/sui-core/src/checkpoints/mod.rs @@ -4190,6 +4190,13 @@ mod tests { unimplemented!() } + fn get_execution_error_metadata( + &self, + _digest: &TransactionDigest, + ) -> Option { + unimplemented!() + } + fn transaction_executed_in_last_epoch(&self, _: &TransactionDigest, _: EpochId) -> bool { unimplemented!() } diff --git a/crates/sui-core/src/execution_cache.rs b/crates/sui-core/src/execution_cache.rs index d23584acb60a..9ed9099721a7 100644 --- a/crates/sui-core/src/execution_cache.rs +++ b/crates/sui-core/src/execution_cache.rs @@ -26,7 +26,7 @@ use sui_protocol_config::ProtocolVersion; use sui_types::base_types::{FullObjectID, VerifiedExecutionData}; use sui_types::digests::{TransactionDigest, TransactionEffectsDigest}; use sui_types::effects::{TransactionEffects, TransactionEvents}; -use sui_types::error::{SuiError, SuiErrorKind, SuiResult, UserInputError}; +use sui_types::error::{ExecutionErrorMetadata, SuiError, SuiErrorKind, SuiResult, UserInputError}; use sui_types::executable_transaction::VerifiedExecutableTransaction; use sui_types::messages_checkpoint::CheckpointSequenceNumber; use sui_types::object::Object; @@ -534,6 +534,11 @@ pub trait TransactionCacheRead: Send + Sync { digest: &TransactionDigest, ) -> Option>; + fn get_execution_error_metadata( + &self, + digest: &TransactionDigest, + ) -> Option; + fn take_accumulator_events(&self, digest: &TransactionDigest) -> Option>; fn notify_read_executed_effects_digests<'a>( diff --git a/crates/sui-core/src/execution_cache/unit_tests/writeback_cache_tests.rs b/crates/sui-core/src/execution_cache/unit_tests/writeback_cache_tests.rs index 7638fdeaa594..f4922f7bb883 100644 --- a/crates/sui-core/src/execution_cache/unit_tests/writeback_cache_tests.rs +++ b/crates/sui-core/src/execution_cache/unit_tests/writeback_cache_tests.rs @@ -23,6 +23,7 @@ use sui_types::{ }; use sui_types::{ effects::{TestEffectsBuilder, TransactionEffectsAPI}, + error::ExecutionErrorMetadata, event::Event, }; use tokio::sync::RwLock; @@ -157,6 +158,7 @@ impl Scenario { effects, events, unchanged_loaded_runtime_objects: Default::default(), + execution_error_metadata: None, accumulator_events: Default::default(), markers: Default::default(), wrapped: Default::default(), @@ -551,6 +553,56 @@ async fn test_committed() { .await; } +#[tokio::test] +async fn test_execution_error_metadata_round_trip() { + telemetry_subscribers::init_for_testing(); + Scenario::iterate(|mut s| async move { + let metadata = ExecutionErrorMetadata::new("Object runtime cached objects limit reached"); + s.outputs.execution_error_metadata = Some(metadata.clone()); + + let tx = s.do_tx().await; + assert!(s.cache.dirty.execution_error_metadata.contains_key(&tx)); + assert_eq!( + s.cache.get_execution_error_metadata(&tx), + Some(metadata.clone()) + ); + + s.commit(tx).await.unwrap(); + assert_eq!( + s.cache.get_execution_error_metadata(&tx), + Some(metadata.clone()) + ); + + s.reset_cache(); + assert_eq!( + s.store.get_execution_error_metadata(&tx).unwrap(), + Some(metadata.clone()) + ); + assert_eq!(s.cache.get_execution_error_metadata(&tx), Some(metadata)); + }) + .await; +} + +#[tokio::test] +async fn test_empty_execution_error_metadata_is_ignored() { + telemetry_subscribers::init_for_testing(); + Scenario::iterate(|mut s| async move { + s.outputs.execution_error_metadata = Some(ExecutionErrorMetadata::default()); + + let tx = s.do_tx().await; + assert!(!s.cache.dirty.execution_error_metadata.contains_key(&tx)); + assert_eq!(s.cache.get_execution_error_metadata(&tx), None); + + s.commit(tx).await.unwrap(); + assert_eq!(s.cache.get_execution_error_metadata(&tx), None); + + s.reset_cache(); + assert_eq!(s.store.get_execution_error_metadata(&tx).unwrap(), None); + assert_eq!(s.cache.get_execution_error_metadata(&tx), None); + }) + .await; +} + #[tokio::test] async fn test_mutated() { telemetry_subscribers::init_for_testing(); diff --git a/crates/sui-core/src/execution_cache/writeback_cache.rs b/crates/sui-core/src/execution_cache/writeback_cache.rs index 6bfaeb3faee6..c6c81bc0a3ee 100644 --- a/crates/sui-core/src/execution_cache/writeback_cache.rs +++ b/crates/sui-core/src/execution_cache/writeback_cache.rs @@ -76,7 +76,7 @@ use sui_types::base_types::{ use sui_types::bridge::{Bridge, get_bridge}; use sui_types::digests::{ObjectDigest, TransactionDigest, TransactionEffectsDigest}; use sui_types::effects::{TransactionEffects, TransactionEvents}; -use sui_types::error::{SuiError, SuiErrorKind, SuiResult, UserInputError}; +use sui_types::error::{ExecutionErrorMetadata, SuiError, SuiErrorKind, SuiResult, UserInputError}; use sui_types::executable_transaction::VerifiedExecutableTransaction; use sui_types::global_state_hash::GlobalStateHash; use sui_types::message_envelope::Message; @@ -233,6 +233,10 @@ struct UncommittedData { unchanged_loaded_runtime_objects: DashMap>, + /// Error metadata originating from `ExecutionErrorContext`, retained with transaction + /// data until pruning. Includes source errors and VM-level details when available. + execution_error_metadata: DashMap, + executed_effects_digests: DashMap, // Transaction outputs that have not yet been written to the DB. Items are removed from this @@ -253,6 +257,7 @@ impl UncommittedData { pending_transaction_writes: DashMap::with_shard_amount(2048), transaction_events: DashMap::with_shard_amount(2048), unchanged_loaded_runtime_objects: DashMap::with_shard_amount(2048), + execution_error_metadata: DashMap::with_shard_amount(2048), total_transaction_inserts: AtomicU64::new(0), total_transaction_commits: AtomicU64::new(0), } @@ -266,6 +271,7 @@ impl UncommittedData { self.pending_transaction_writes.clear(); self.transaction_events.clear(); self.unchanged_loaded_runtime_objects.clear(); + self.execution_error_metadata.clear(); self.total_transaction_inserts .store(0, std::sync::atomic::Ordering::Relaxed); self.total_transaction_commits @@ -282,6 +288,7 @@ impl UncommittedData { && self.executed_effects_digests.is_empty() && self.transaction_events.is_empty() && self.unchanged_loaded_runtime_objects.is_empty() + && self.execution_error_metadata.is_empty() && self .total_transaction_inserts .load(std::sync::atomic::Ordering::Relaxed) @@ -913,6 +920,7 @@ impl WritebackCache { wrapped, events, unchanged_loaded_runtime_objects, + execution_error_metadata, .. } = &*tx_outputs; @@ -988,6 +996,15 @@ impl WritebackCache { .unchanged_loaded_runtime_objects .insert(tx_digest, unchanged_loaded_runtime_objects.clone()); + if let Some(metadata) = execution_error_metadata + && !metadata.is_empty() + { + self.metrics.record_cache_write("execution_error_metadata"); + self.dirty + .execution_error_metadata + .insert(tx_digest, metadata.clone()); + } + self.metrics.record_cache_write("executed_effects_digests"); self.dirty .executed_effects_digests @@ -1190,6 +1207,8 @@ impl WritebackCache { .remove(&tx_digest) .expect("unchanged_loaded_runtime_objects must exist"); + self.dirty.execution_error_metadata.remove(&tx_digest); + self.dirty .executed_effects_digests .remove(&tx_digest) @@ -2309,6 +2328,21 @@ impl TransactionCacheRead for WritebackCache { }) } + fn get_execution_error_metadata( + &self, + digest: &TransactionDigest, + ) -> Option { + self.dirty + .execution_error_metadata + .get(digest) + .map(|b| b.clone()) + .or_else(|| { + self.store + .get_execution_error_metadata(digest) + .expect("db error") + }) + } + fn take_accumulator_events(&self, digest: &TransactionDigest) -> Option> { self.dirty .pending_transaction_writes diff --git a/crates/sui-core/src/storage.rs b/crates/sui-core/src/storage.rs index b6dae65260db..b86014f7ed3c 100644 --- a/crates/sui-core/src/storage.rs +++ b/crates/sui-core/src/storage.rs @@ -19,7 +19,7 @@ use sui_types::base_types::TransactionDigest; use sui_types::committee::Committee; use sui_types::committee::EpochId; use sui_types::effects::{TransactionEffects, TransactionEvents}; -use sui_types::error::{SuiErrorKind, SuiResult}; +use sui_types::error::{ExecutionErrorMetadata, SuiErrorKind, SuiResult}; use sui_types::full_checkpoint_content::ObjectSet; use sui_types::messages_checkpoint::CheckpointContentsDigest; use sui_types::messages_checkpoint::CheckpointDigest; @@ -245,6 +245,15 @@ impl ReadStore for RocksDbStore { .get_unchanged_loaded_runtime_objects(digest) } + fn get_execution_error_metadata( + &self, + digest: &TransactionDigest, + ) -> Option { + self.cache_traits + .transaction_cache_reader + .get_execution_error_metadata(digest) + } + fn get_transaction_checkpoint( &self, digest: &TransactionDigest, @@ -489,6 +498,13 @@ impl ReadStore for RestReadStore { self.rocks.get_unchanged_loaded_runtime_objects(digest) } + fn get_execution_error_metadata( + &self, + digest: &TransactionDigest, + ) -> Option { + self.rocks.get_execution_error_metadata(digest) + } + fn get_transaction_checkpoint( &self, digest: &TransactionDigest, diff --git a/crates/sui-core/src/transaction_outputs.rs b/crates/sui-core/src/transaction_outputs.rs index f46fb41ffef7..25f6403635e7 100644 --- a/crates/sui-core/src/transaction_outputs.rs +++ b/crates/sui-core/src/transaction_outputs.rs @@ -7,6 +7,7 @@ use std::sync::Arc; use sui_types::accumulator_event::AccumulatorEvent; use sui_types::base_types::{FullObjectID, ObjectRef}; use sui_types::effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}; +use sui_types::error::ExecutionErrorMetadata; use sui_types::full_checkpoint_content::ObjectSet; use sui_types::inner_temporary_store::{InnerTemporaryStore, WrittenObjects}; use sui_types::storage::{FullObjectKey, MarkerValue, ObjectKey}; @@ -19,6 +20,7 @@ pub struct TransactionOutputs { pub effects: TransactionEffects, pub events: TransactionEvents, pub unchanged_loaded_runtime_objects: Vec, + pub execution_error_metadata: Option, pub accumulator_events: Mutex>>, pub markers: Vec<(FullObjectKey, MarkerValue)>, @@ -36,6 +38,7 @@ impl TransactionOutputs { effects: TransactionEffects, inner_temporary_store: InnerTemporaryStore, unchanged_loaded_runtime_objects: Vec, + execution_error_metadata: Option, ) -> TransactionOutputs { let InnerTemporaryStore { input_objects, @@ -186,6 +189,7 @@ impl TransactionOutputs { effects, events, unchanged_loaded_runtime_objects, + execution_error_metadata, accumulator_events: Mutex::new(Some(accumulator_events)), markers, wrapped, @@ -210,6 +214,7 @@ impl TransactionOutputs { effects, events: TransactionEvents { data: vec![] }, unchanged_loaded_runtime_objects: vec![], + execution_error_metadata: None, accumulator_events: Mutex::new(Some(vec![])), markers: vec![], wrapped: vec![], diff --git a/crates/sui-core/src/unit_tests/authority_tests.rs b/crates/sui-core/src/unit_tests/authority_tests.rs index 9a2efb0fd851..bc8c48639345 100644 --- a/crates/sui-core/src/unit_tests/authority_tests.rs +++ b/crates/sui-core/src/unit_tests/authority_tests.rs @@ -34,7 +34,7 @@ use sui_protocol_config::{ Chain, ExecutionTimeEstimateParams, PerObjectCongestionControlMode, ProtocolConfig, ProtocolVersion, }; -use sui_types::effects::TransactionEffects; +use sui_types::effects::{TransactionEffects, TransactionEffectsAPI}; use sui_types::epoch_data::EpochData; use sui_types::error::UserInputError; use sui_types::execution::SharedInput; @@ -5398,6 +5398,100 @@ async fn test_function_not_found() { assert_eq!(execution_error_source, Some("Could not resolve function 'bad_function' in module '0x0000000000000000000000000000000000000000000000000000000000000001::option'".to_string()),) } +#[tokio::test] +async fn test_validator_execution_does_not_store_error_metadata() { + let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); + let gas_object_id = ObjectID::random(); + let (validator, fullnode, _) = + init_state_with_ids_and_object_basics_with_fullnode(vec![(sender, gas_object_id)]).await; + + let mut builder = ProgrammableTransactionBuilder::new(); + builder + .move_call( + ObjectID::from_single_byte(1), + ident_str!("option").to_owned(), + ident_str!("bad_function").to_owned(), + vec![], + vec![], + ) + .unwrap(); + let kind = TransactionKind::programmable(builder.finish()); + + let rgp = validator.reference_gas_price_for_testing().unwrap(); + let txn_data = TransactionData::new_with_gas_coins( + kind, + sender, + vec![ + validator + .get_object(&gas_object_id) + .await + .unwrap() + .compute_object_reference(), + ], + TEST_ONLY_GAS_UNIT_FOR_PUBLISH * rgp, + rgp, + ); + + let transaction = to_sender_signed_transaction(txn_data, &sender_key); + let executable = create_executable_transaction(&validator, transaction).unwrap(); + let env = ExecutionEnv::new().with_assigned_versions(AssignedVersions::new(vec![], None)); + + let (validator_effects, validator_execution_error) = validator + .try_execute_executable_for_test(&executable, env.clone()) + .await; + let (fullnode_effects, fullnode_execution_error) = fullnode + .try_execute_executable_for_test(&executable, env) + .await; + + let validator_effects = validator_effects.inner().data(); + let fullnode_effects = fullnode_effects.inner().data(); + assert_eq!(validator_effects.status(), fullnode_effects.status()); + assert_eq!( + validator_effects.transaction_digest(), + fullnode_effects.transaction_digest() + ); + assert_eq!( + validator_effects.gas_cost_summary(), + fullnode_effects.gas_cost_summary() + ); + assert_eq!(validator_effects.created(), fullnode_effects.created()); + assert_eq!(validator_effects.mutated(), fullnode_effects.mutated()); + assert_eq!(validator_effects.deleted(), fullnode_effects.deleted()); + assert_eq!(validator_effects.wrapped(), fullnode_effects.wrapped()); + assert!(matches!( + validator_effects.status(), + ExecutionStatus::Failure(ExecutionFailure { + error: ExecutionErrorKind::FunctionNotFound, + command: Some(0), + }) + )); + + assert!(validator_execution_error.is_some()); + assert_eq!( + validator + .get_transaction_cache_reader() + .get_execution_error_metadata(executable.digest()), + None, + ); + + let fullnode_source = fullnode_execution_error + .as_ref() + .and_then(|error| std::error::Error::source(error)) + .map(ToString::to_string) + .unwrap(); + assert!(fullnode_source.contains("bad_function")); + let fullnode_metadata = fullnode + .get_transaction_cache_reader() + .get_execution_error_metadata(executable.digest()) + .unwrap(); + assert!( + fullnode_metadata + .message + .as_deref() + .is_some_and(|source| source.contains("bad_function")) + ); +} + #[tokio::test] async fn test_arity_mismatch() { let (sender, sender_key): (_, AccountKeyPair) = get_key_pair(); diff --git a/crates/sui-genesis-builder/src/lib.rs b/crates/sui-genesis-builder/src/lib.rs index 3a0635bf8b17..0356f6cd44ec 100644 --- a/crates/sui-genesis-builder/src/lib.rs +++ b/crates/sui-genesis-builder/src/lib.rs @@ -919,8 +919,8 @@ fn create_genesis_transaction( let (kind, signer, mut gas_data) = transaction_data.execution_parts(); gas_data.payment = vec![]; let input_objects = CheckedInputObjects::new_for_genesis(vec![]); - let (inner_temp_store, _, effects, _timings, _execution_error) = executor - .execute_transaction_to_effects_and_execution_error( + let (inner_temp_store, _, effects, _timings, _execution_error, _execution_error_metadata) = + executor.execute_transaction_to_effects_and_execution_error( &InMemoryStorage::new(Vec::new()), protocol_config, metrics, diff --git a/crates/sui-kv-rpc/src/v2alpha/list_checkpoints.rs b/crates/sui-kv-rpc/src/v2alpha/list_checkpoints.rs index 02d7148c2b0e..7e1ea44ffa07 100644 --- a/crates/sui-kv-rpc/src/v2alpha/list_checkpoints.rs +++ b/crates/sui-kv-rpc/src/v2alpha/list_checkpoints.rs @@ -499,6 +499,7 @@ fn render_full_checkpoint( signatures: tx.signatures.unwrap_or_default(), effects, events: tx.events, + execution_error_metadata: None, unchanged_loaded_runtime_objects: tx.unchanged_loaded_runtime_objects, }) }) diff --git a/crates/sui-replay-2/src/execution.rs b/crates/sui-replay-2/src/execution.rs index 7fd7a6ee267e..92c721f5738f 100644 --- a/crates/sui-replay-2/src/execution.rs +++ b/crates/sui-replay-2/src/execution.rs @@ -129,25 +129,26 @@ pub fn execute_transaction_to_effects( Some(error) => ExecutionOrEarlyError::Err(error), None => ExecutionOrEarlyError::Ok(()), }; - let (inner_store, gas_status, effects, _execution_timing, result) = executor - .executor - .execute_transaction_to_effects_and_execution_error( - &store, - protocol_config, - executor.execution_metrics.clone(), - false, // expensive checks - execution_params, - &epoch, - epoch_start_timestamp, - input_objects, - txn_data.gas_data().clone(), - gas_status, - txn_data.kind().clone(), - None, // compat_args - txn_data.sender(), - digest, - trace_builder_opt, - ); + let (inner_store, gas_status, effects, _execution_timing, result, _execution_error_metadata) = + executor + .executor + .execute_transaction_to_effects_and_execution_error( + &store, + protocol_config, + executor.execution_metrics.clone(), + false, // expensive checks + execution_params, + &epoch, + epoch_start_timestamp, + input_objects, + txn_data.gas_data().clone(), + gas_status, + txn_data.kind().clone(), + None, // compat_args + txn_data.sender(), + digest, + trace_builder_opt, + ); let ReplayStore { object_cache, checkpoint: _, diff --git a/crates/sui-replay/src/replay.rs b/crates/sui-replay/src/replay.rs index 407a908fc1cb..53c7f35f5f63 100644 --- a/crates/sui-replay/src/replay.rs +++ b/crates/sui-replay/src/replay.rs @@ -792,8 +792,8 @@ impl LocalExec { Some(error) => ExecutionOrEarlyError::Err(error), None => ExecutionOrEarlyError::Ok(()), }; - let (inner_store, gas_status, effects, _timings, result) = executor - .execute_transaction_to_effects_and_execution_error( + let (inner_store, gas_status, effects, _timings, result, _execution_error_metadata) = + executor.execute_transaction_to_effects_and_execution_error( &self, protocol_config, metrics.clone(), @@ -988,7 +988,7 @@ impl LocalExec { Some(error) => ExecutionOrEarlyError::Err(error), None => ExecutionOrEarlyError::Ok(()), }; - let (_, _, effects, _timings, exec_res) = executor + let (_, _, effects, _timings, exec_res, _execution_error_metadata) = executor .execute_transaction_to_effects_and_execution_error( &store, &protocol_config, diff --git a/crates/sui-types/src/error.rs b/crates/sui-types/src/error.rs index f963a4fbfb4f..d50bc8d93601 100644 --- a/crates/sui-types/src/error.rs +++ b/crates/sui-types/src/error.rs @@ -1165,8 +1165,28 @@ impl std::fmt::Debug for SuiError { } } -pub(crate) type BoxError = Box; -pub type ExecutionErrorMetadata = BTreeMap; +pub type BoxError = Box; + +/// Additional fullnode execution details captured for failed transactions. +/// This metadata is stored as a non-consensus sidecar and can be different across fullnode versions. +/// Not a part of chain state. +#[derive(Clone, Debug, Default, Eq, PartialEq)] +pub struct ExecutionErrorMetadata { + /// Human-readable execution error detail intended for diagnostics and user-facing APIs. + pub message: Option, +} + +impl ExecutionErrorMetadata { + pub fn new(source: impl Into) -> Self { + Self { + message: Some(source.into()), + } + } + + pub fn is_empty(&self) -> bool { + self.message.as_deref().is_none_or(str::is_empty) + } +} /// A trait for execution errors that provides common methods for accessing error information and creating new errors. pub trait ExecutionErrorTrait: @@ -1258,6 +1278,15 @@ impl ExecutionError { &self.inner.source } + pub fn into_parts(self) -> (ExecutionErrorKind, Option, Option) { + let ExecutionErrorInner { + kind, + source, + command, + } = *self.inner; + (kind, source, command) + } + pub fn to_execution_status(&self) -> (ExecutionErrorKind, Option) { (self.kind().clone(), self.command()) } @@ -1291,126 +1320,6 @@ impl ExecutionErrorTrait for ExecutionError { } } -#[derive(Debug)] -pub struct ExecutionErrorContext { - kind: ExecutionErrorKind, - metadata: ExecutionErrorMetadata, - source: Option, - command: Option, -} - -impl ExecutionErrorContext { - pub fn kind(&self) -> &ExecutionErrorKind { - &self.kind - } - - pub fn command(&self) -> Option { - self.command - } - - pub fn metadata_with_source(&self) -> Option { - let mut metadata = self.metadata.clone(); - if let Some(source) = self.source.as_ref() { - metadata.insert("source".to_string(), source.to_string()); - } - - (!metadata.is_empty()).then_some(metadata) - } - - pub fn to_execution_status(&self) -> (ExecutionErrorKind, Option) { - (self.kind().clone(), self.command()) - } -} - -impl ExecutionErrorTrait for ExecutionErrorContext { - fn new( - failure: ExecutionFailure, - source: Option, - metadata: ExecutionErrorMetadata, - ) -> Self { - let ExecutionFailure { error, command } = failure; - Self { - kind: error, - metadata, - source, - command, - } - } - - fn with_command_index(self, command: CommandIndex) -> Self { - Self { - command: Some(command), - ..self - } - } - - fn kind(&self) -> &ExecutionErrorKind { - self.kind() - } - - fn command(&self) -> Option { - self.command() - } -} - -impl std::fmt::Display for ExecutionErrorContext { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "ExecutionErrorContext: {:?}", self) - } -} - -impl std::error::Error for ExecutionErrorContext { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - self.source.as_deref().map(|e| e as _) - } -} - -impl From for ExecutionErrorContext { - fn from(kind: ExecutionErrorKind) -> Self { - ::from_kind(kind) - } -} - -impl From for ExecutionErrorContext { - fn from(value: ExecutionFailure) -> Self { - ::from_execution_failure(value) - } -} - -impl From for ExecutionErrorContext { - fn from(value: ExecutionError) -> Self { - let ExecutionError { inner } = value; - let ExecutionErrorInner { - kind, - source, - command, - } = *inner; - Self { - kind, - metadata: BTreeMap::new(), - source, - command, - } - } -} - -impl From for ExecutionError { - fn from(value: ExecutionErrorContext) -> Self { - let ExecutionErrorContext { - kind, - metadata: _, - source, - command, - } = value; - let err = ExecutionError::new(kind, source); - if let Some(command) = command { - err.with_command_index(command) - } else { - err - } - } -} - impl std::fmt::Display for ExecutionError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "ExecutionError: {:?}", self) diff --git a/crates/sui-types/src/execution_status.rs b/crates/sui-types/src/execution_status.rs index bc89aebdc4b7..37fcde8c534c 100644 --- a/crates/sui-types/src/execution_status.rs +++ b/crates/sui-types/src/execution_status.rs @@ -3,7 +3,9 @@ use crate::ObjectID; use crate::base_types::SuiAddress; -use crate::error::{BoxError, ExecutionError, ExecutionErrorMetadata, ExecutionErrorTrait}; +pub(crate) use crate::error::{ + BoxError, ExecutionError, ExecutionErrorMetadata, ExecutionErrorTrait, +}; use move_binary_format::file_format::{CodeOffset, TypeParameterIndex}; use move_core_types::language_storage::ModuleId; use serde::{Deserialize, Serialize}; diff --git a/crates/sui-types/src/full_checkpoint_content.rs b/crates/sui-types/src/full_checkpoint_content.rs index 21b1d9afb924..26a3909eba8b 100644 --- a/crates/sui-types/src/full_checkpoint_content.rs +++ b/crates/sui-types/src/full_checkpoint_content.rs @@ -5,6 +5,7 @@ use std::collections::BTreeMap; use crate::base_types::{ExecutionData, ObjectID, ObjectRef}; use crate::effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}; +use crate::error::ExecutionErrorMetadata; use crate::messages_checkpoint::{CertifiedCheckpointSummary, CheckpointContents}; use crate::object::Object; use crate::signature::GenericSignature; @@ -217,6 +218,8 @@ pub struct ExecutedTransaction { pub effects: TransactionEffects, /// The events, if any, emitted by this transactions during execution pub events: Option, + /// Additional metadata captured when local execution fails. + pub execution_error_metadata: Option, pub unchanged_loaded_runtime_objects: Vec, } @@ -472,6 +475,7 @@ impl From for Checkpoint { events: tx.events, // lossy + execution_error_metadata: None, unchanged_loaded_runtime_objects: Vec::new(), } }) diff --git a/crates/sui-types/src/rpc_proto_conversions.rs b/crates/sui-types/src/rpc_proto_conversions.rs index 77168b7c0f19..67ebe7b6a8d3 100644 --- a/crates/sui-types/src/rpc_proto_conversions.rs +++ b/crates/sui-types/src/rpc_proto_conversions.rs @@ -220,6 +220,7 @@ impl TryFrom<&ExecutedTransaction> for crate::full_checkpoint_content::ExecutedT .iter() .map(TryInto::try_into) .collect::>()?, + execution_error_metadata: None, }) } } @@ -1180,6 +1181,7 @@ impl From for ExecutionStatus { } } + // // ExecutionError // @@ -1534,6 +1536,36 @@ impl From for MoveLocation { } } +// +// ExecutionErrorMetadata +// + +pub use sui_rpc::proto::sui::rpc::v2::ExecutionErrorMetadata; + +impl From for ExecutionErrorMetadata { + fn from(metadata: crate::error::ExecutionErrorMetadata) -> Self { + let mut message = Self::default(); + message.message = metadata.message; + message + } +} + +impl From<&crate::execution_status::ExecutionErrorMetadata> for ExecutionErrorMetadata { + fn from(metadata: &crate::error::ExecutionErrorMetadata) -> Self { + let mut message = Self::default(); + message.message = metadata.message.clone(); + message + } +} + +impl From<&ExecutionErrorMetadata> for crate::execution_status::ExecutionErrorMetadata { + fn from(metadata: &ExecutionErrorMetadata) -> Self { + Self { + message: metadata.message.clone(), + } + } +} + // // AuthorityQuorumSignInfo aka ValidatorAggregatedSignature // diff --git a/crates/sui-types/src/storage/read_store.rs b/crates/sui-types/src/storage/read_store.rs index 9fc66ecbe15d..c2d4bd0067d2 100644 --- a/crates/sui-types/src/storage/read_store.rs +++ b/crates/sui-types/src/storage/read_store.rs @@ -11,6 +11,7 @@ use crate::digests::{ }; use crate::dynamic_field::DynamicFieldType; use crate::effects::{TransactionEffects, TransactionEvents}; +use crate::error::ExecutionErrorMetadata; use crate::full_checkpoint_content::{Checkpoint, ExecutedTransaction, ObjectSet}; use crate::messages_checkpoint::{ CheckpointContents, CheckpointSequenceNumber, VerifiedCheckpoint, @@ -146,6 +147,13 @@ pub trait ReadStore: ObjectStore { digest: &TransactionDigest, ) -> Option>; + fn get_execution_error_metadata( + &self, + _digest: &TransactionDigest, + ) -> Option { + None + } + fn get_transaction_checkpoint( &self, digest: &TransactionDigest, @@ -222,6 +230,7 @@ pub trait ReadStore: ObjectStore { signatures: tx.tx_signatures().to_vec(), effects: fx.clone(), events, + execution_error_metadata: self.get_execution_error_metadata(tx.digest()), unchanged_loaded_runtime_objects: self .get_unchanged_loaded_runtime_objects(tx.digest()) //TODO Do we throw an error or just stub in an empty vector? @@ -360,6 +369,13 @@ impl ReadStore for &T { (*self).get_unchanged_loaded_runtime_objects(digest) } + fn get_execution_error_metadata( + &self, + digest: &TransactionDigest, + ) -> Option { + (*self).get_execution_error_metadata(digest) + } + fn get_transaction_checkpoint( &self, digest: &TransactionDigest, @@ -478,6 +494,13 @@ impl ReadStore for Box { (**self).get_unchanged_loaded_runtime_objects(digest) } + fn get_execution_error_metadata( + &self, + digest: &TransactionDigest, + ) -> Option { + (**self).get_execution_error_metadata(digest) + } + fn get_transaction_checkpoint( &self, digest: &TransactionDigest, @@ -596,6 +619,13 @@ impl ReadStore for Arc { (**self).get_unchanged_loaded_runtime_objects(digest) } + fn get_execution_error_metadata( + &self, + digest: &TransactionDigest, + ) -> Option { + (**self).get_execution_error_metadata(digest) + } + fn get_transaction_checkpoint( &self, digest: &TransactionDigest, diff --git a/crates/sui-types/src/test_checkpoint_data_builder.rs b/crates/sui-types/src/test_checkpoint_data_builder.rs index 7d192c570982..4729314b9709 100644 --- a/crates/sui-types/src/test_checkpoint_data_builder.rs +++ b/crates/sui-types/src/test_checkpoint_data_builder.rs @@ -648,6 +648,7 @@ impl TestCheckpointBuilder { signatures: sender_signed.tx_signatures, effects: tx.effects, events: tx.events, + execution_error_metadata: None, unchanged_loaded_runtime_objects: Vec::new(), } }) diff --git a/sui-execution/src/error_context.rs b/sui-execution/src/error_context.rs new file mode 100644 index 000000000000..b31cceaa3d1a --- /dev/null +++ b/sui-execution/src/error_context.rs @@ -0,0 +1,120 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use sui_types::error::{BoxError, ExecutionError, ExecutionErrorMetadata, ExecutionErrorTrait}; +use sui_types::execution_status::{CommandIndex, ExecutionErrorKind, ExecutionFailure}; + +#[derive(Debug)] +pub struct ExecutionErrorContext { + kind: ExecutionErrorKind, + metadata: ExecutionErrorMetadata, + source: Option, + command: Option, +} + +impl ExecutionErrorContext { + pub fn kind(&self) -> &ExecutionErrorKind { + &self.kind + } + + pub fn command(&self) -> Option { + self.command + } + + pub fn metadata_with_source(&self) -> Option { + let mut metadata = self.metadata.clone(); + if let Some(source) = self.source.as_ref() { + metadata.message.get_or_insert_with(|| source.to_string()); + } + + (!metadata.is_empty()).then_some(metadata) + } + + pub fn to_execution_status(&self) -> (ExecutionErrorKind, Option) { + (self.kind().clone(), self.command()) + } +} + +impl ExecutionErrorTrait for ExecutionErrorContext { + fn new( + failure: ExecutionFailure, + source: Option, + metadata: ExecutionErrorMetadata, + ) -> Self { + let ExecutionFailure { error, command } = failure; + Self { + kind: error, + metadata, + source, + command, + } + } + + fn with_command_index(self, command: CommandIndex) -> Self { + Self { + command: Some(command), + ..self + } + } + + fn kind(&self) -> &ExecutionErrorKind { + self.kind() + } + + fn command(&self) -> Option { + self.command() + } +} + +impl std::fmt::Display for ExecutionErrorContext { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "ExecutionErrorContext: {:?}", self) + } +} + +impl std::error::Error for ExecutionErrorContext { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + self.source.as_deref().map(|e| e as _) + } +} + +impl From for ExecutionErrorContext { + fn from(kind: ExecutionErrorKind) -> Self { + ::from_kind(kind) + } +} + +impl From for ExecutionErrorContext { + fn from(value: ExecutionFailure) -> Self { + ::from_execution_failure(value) + } +} + +impl From for ExecutionErrorContext { + fn from(value: ExecutionError) -> Self { + let (kind, source, command) = value.into_parts(); + Self { + kind, + metadata: ExecutionErrorMetadata::default(), + source, + command, + } + } +} + +impl From for ExecutionError { + fn from(value: ExecutionErrorContext) -> Self { + let ExecutionErrorContext { + kind, + metadata: _, + source, + command, + } = value; + let err = ExecutionError::new(kind, source); + if let Some(command) = command { + err.with_command_index(command) + } else { + err + } + } +} diff --git a/sui-execution/src/executor.rs b/sui-execution/src/executor.rs index 6f2c5fea138e..dc577424f7dc 100644 --- a/sui-execution/src/executor.rs +++ b/sui-execution/src/executor.rs @@ -13,7 +13,7 @@ use sui_types::{ committee::EpochId, digests::TransactionDigest, effects::TransactionEffects, - error::ExecutionError, + error::{ExecutionError, ExecutionErrorMetadata}, execution::{ExecutionResult, TypeLayoutStore}, execution_status::ExecutionFailure, gas::SuiGasStatus, @@ -80,6 +80,7 @@ pub trait Executor { TransactionEffects, Vec, Result<(), ExecutionError>, + Option, ); fn dev_inspect_transaction( diff --git a/sui-execution/src/latest.rs b/sui-execution/src/latest.rs index df1e26b5f5cb..adeefd82c337 100644 --- a/sui-execution/src/latest.rs +++ b/sui-execution/src/latest.rs @@ -14,7 +14,10 @@ use sui_types::{ committee::EpochId, digests::TransactionDigest, effects::TransactionEffects, - error::{ExecutionError, ExecutionErrorTrait, SuiError, SuiResult}, + error::{ + ExecutionError, ExecutionErrorMetadata, ExecutionErrorTrait, + SuiError, SuiResult, + }, execution::{ExecutionResult, TypeLayoutStore}, execution_status::ExecutionFailure, gas::SuiGasStatus, @@ -24,6 +27,7 @@ use sui_types::{ transaction::{CheckedInputObjects, ProgrammableTransaction, TransactionKind}, }; +use crate::error_context::ExecutionErrorContext; use move_bytecode_verifier_meter::Meter; use move_vm_runtime_latest::runtime::MoveRuntime; use mysten_common::debug_fatal; @@ -135,9 +139,10 @@ impl executor::Executor for Executor { TransactionEffects, Vec, Result<(), ExecutionError>, + Option, ) { let (store_out, gas_status_out, effects, timings, result) = - execute_transaction_to_effects::>( + execute_transaction_to_effects::>( store, input_objects, gas, @@ -158,7 +163,18 @@ impl executor::Executor for Executor { if let Err(error) = &result { log_execution_error(transaction_digest, error); } - (store_out, gas_status_out, effects, timings, result) + let execution_error_metadata = result + .as_ref() + .err() + .and_then(ExecutionErrorContext::metadata_with_source); + ( + store_out, + gas_status_out, + effects, + timings, + result.map_err(ExecutionError::from), + execution_error_metadata, + ) } fn dev_inspect_transaction( diff --git a/sui-execution/src/lib.rs b/sui-execution/src/lib.rs index bdd27320a930..63bcfefa52a7 100644 --- a/sui-execution/src/lib.rs +++ b/sui-execution/src/lib.rs @@ -22,6 +22,7 @@ mod v3; #[cfg(test)] mod tests; +mod error_context; pub fn executor( protocol_config: &ProtocolConfig, diff --git a/sui-execution/src/v0.rs b/sui-execution/src/v0.rs index 6018b95880b7..49200b132206 100644 --- a/sui-execution/src/v0.rs +++ b/sui-execution/src/v0.rs @@ -15,7 +15,7 @@ use sui_types::{ committee::EpochId, digests::TransactionDigest, effects::TransactionEffects, - error::{ExecutionError, SuiError, SuiResult}, + error::{ExecutionError, ExecutionErrorMetadata, SuiError, SuiResult}, execution::{ExecutionResult, TypeLayoutStore}, execution_status::ExecutionFailure, gas::SuiGasStatus, @@ -206,6 +206,7 @@ impl executor::Executor for Executor { TransactionEffects, Vec, Result<(), ExecutionError>, + Option, ) { let gas_coins = gas.payment; let (inner_temp_store, gas_status, effects, result) = @@ -228,7 +229,14 @@ impl executor::Executor for Executor { if let Err(error) = &result { log_execution_error(transaction_digest, error); } - (inner_temp_store, gas_status, effects, vec![], result) + ( + inner_temp_store, + gas_status, + effects, + vec![], + result, + None, + ) } fn update_genesis_state( diff --git a/sui-execution/src/v1.rs b/sui-execution/src/v1.rs index 1cd6fe851b64..4746ae9eea5d 100644 --- a/sui-execution/src/v1.rs +++ b/sui-execution/src/v1.rs @@ -15,7 +15,7 @@ use sui_types::{ committee::EpochId, digests::TransactionDigest, effects::TransactionEffects, - error::{ExecutionError, SuiError, SuiResult}, + error::{ExecutionError, ExecutionErrorMetadata, SuiError, SuiResult}, execution::{ExecutionResult, TypeLayoutStore}, execution_status::ExecutionFailure, gas::SuiGasStatus, @@ -206,6 +206,7 @@ impl executor::Executor for Executor { TransactionEffects, Vec, Result<(), ExecutionError>, + Option, ) { let gas_coins = gas.payment; let (inner_temp_store, gas_status, effects, result) = @@ -228,7 +229,14 @@ impl executor::Executor for Executor { if let Err(error) = &result { log_execution_error(transaction_digest, error); } - (inner_temp_store, gas_status, effects, vec![], result) + ( + inner_temp_store, + gas_status, + effects, + vec![], + result, + None, + ) } fn update_genesis_state( diff --git a/sui-execution/src/v2.rs b/sui-execution/src/v2.rs index 3da3e41f09ea..d580ce98dc7d 100644 --- a/sui-execution/src/v2.rs +++ b/sui-execution/src/v2.rs @@ -15,7 +15,7 @@ use sui_types::{ committee::EpochId, digests::TransactionDigest, effects::TransactionEffects, - error::{ExecutionError, SuiError, SuiResult}, + error::{ExecutionError, ExecutionErrorMetadata, SuiError, SuiResult}, execution::{ExecutionResult, TypeLayoutStore}, execution_status::ExecutionFailure, gas::SuiGasStatus, @@ -206,6 +206,7 @@ impl executor::Executor for Executor { TransactionEffects, Vec, Result<(), ExecutionError>, + Option, ) { let gas_coins = gas.payment; let (inner_temp_store, gas_status, effects, result) = @@ -228,7 +229,14 @@ impl executor::Executor for Executor { if let Err(error) = &result { log_execution_error(transaction_digest, error); } - (inner_temp_store, gas_status, effects, vec![], result) + ( + inner_temp_store, + gas_status, + effects, + vec![], + result, + None, + ) } fn update_genesis_state( diff --git a/sui-execution/src/v3.rs b/sui-execution/src/v3.rs index ca3d4d72b8c9..9626822cb580 100644 --- a/sui-execution/src/v3.rs +++ b/sui-execution/src/v3.rs @@ -14,7 +14,7 @@ use sui_types::{ committee::EpochId, digests::TransactionDigest, effects::TransactionEffects, - error::{ExecutionError, SuiError, SuiResult}, + error::{ExecutionError, ExecutionErrorMetadata, SuiError, SuiResult}, execution::{ExecutionResult, TypeLayoutStore}, gas::SuiGasStatus, inner_temporary_store::InnerTemporaryStore, @@ -140,6 +140,7 @@ impl executor::Executor for Executor { TransactionEffects, Vec, Result<(), ExecutionError>, + Option, ) { let (inner_temp_store, gas_status, effects, timings, result) = execute_transaction_to_effects::( @@ -162,7 +163,14 @@ impl executor::Executor for Executor { if let Err(error) = &result { log_execution_error(protocol_config, transaction_digest, error); } - (inner_temp_store, gas_status, effects, timings, result) + ( + inner_temp_store, + gas_status, + effects, + timings, + result, + None, + ) } fn dev_inspect_transaction(