From 041ed2c3acef2daf403cea16c4a63f9cae8154fa Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 10 Mar 2026 09:57:01 +0700 Subject: [PATCH 1/2] fix: version-gate commit_batch accumulated costs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fix in 4a0731e changed commit_batch to return accumulated batch costs instead of discarding them. This affects cost calculations which need to be consistent per protocol version. - V1/V2: commit version 0 — discard batch costs (legacy behavior) - V3: commit version 1 — preserve accumulated batch costs Co-Authored-By: Claude Opus 4.6 --- grovedb-version/src/version/merk_versions.rs | 8 ++++++++ grovedb-version/src/version/v1.rs | 3 ++- grovedb-version/src/version/v2.rs | 3 ++- grovedb-version/src/version/v3.rs | 3 ++- merk/src/merk/apply.rs | 8 +++++++- merk/src/merk/mod.rs | 16 ++++++++++++---- 6 files changed, 33 insertions(+), 8 deletions(-) diff --git a/grovedb-version/src/version/merk_versions.rs b/grovedb-version/src/version/merk_versions.rs index d0d122da2..34cd4bf28 100644 --- a/grovedb-version/src/version/merk_versions.rs +++ b/grovedb-version/src/version/merk_versions.rs @@ -2,9 +2,17 @@ use versioned_feature_core::FeatureVersion; #[derive(Clone, Debug, Default)] pub struct MerkVersions { + pub commit: MerkCommitVersions, pub average_case_costs: MerkAverageCaseCostsVersions, } +#[derive(Clone, Debug, Default)] +pub struct MerkCommitVersions { + /// Version 0: commit_batch discards accumulated batch costs (legacy bug) + /// Version 1: commit_batch returns accumulated batch costs + pub commit: FeatureVersion, +} + #[derive(Clone, Debug, Default)] pub struct MerkAverageCaseCostsVersions { pub add_average_case_merk_propagate: FeatureVersion, diff --git a/grovedb-version/src/version/v1.rs b/grovedb-version/src/version/v1.rs index 1c9656cc4..4cfe5cc16 100644 --- a/grovedb-version/src/version/v1.rs +++ b/grovedb-version/src/version/v1.rs @@ -9,7 +9,7 @@ use crate::version::{ GroveDBOperationsWorstCaseVersions, GroveDBPathQueryMethodVersions, GroveDBQueryLimits, GroveDBReplicationVersions, GroveDBVersions, }, - merk_versions::{MerkAverageCaseCostsVersions, MerkVersions}, + merk_versions::{MerkAverageCaseCostsVersions, MerkCommitVersions, MerkVersions}, GroveVersion, }; @@ -206,6 +206,7 @@ pub const GROVE_V1: GroveVersion = GroveVersion { }, }, merk_versions: MerkVersions { + commit: MerkCommitVersions { commit: 0 }, average_case_costs: MerkAverageCaseCostsVersions { add_average_case_merk_propagate: 0, sum_tree_estimated_size: 0, diff --git a/grovedb-version/src/version/v2.rs b/grovedb-version/src/version/v2.rs index 67425f25c..faca231fa 100644 --- a/grovedb-version/src/version/v2.rs +++ b/grovedb-version/src/version/v2.rs @@ -9,7 +9,7 @@ use crate::version::{ GroveDBOperationsWorstCaseVersions, GroveDBPathQueryMethodVersions, GroveDBQueryLimits, GroveDBReplicationVersions, GroveDBVersions, }, - merk_versions::{MerkAverageCaseCostsVersions, MerkVersions}, + merk_versions::{MerkAverageCaseCostsVersions, MerkCommitVersions, MerkVersions}, GroveVersion, }; @@ -206,6 +206,7 @@ pub const GROVE_V2: GroveVersion = GroveVersion { }, }, merk_versions: MerkVersions { + commit: MerkCommitVersions { commit: 0 }, average_case_costs: MerkAverageCaseCostsVersions { add_average_case_merk_propagate: 1, // changed sum_tree_estimated_size: 1, // changed diff --git a/grovedb-version/src/version/v3.rs b/grovedb-version/src/version/v3.rs index 8cb8aede3..ec64313f4 100644 --- a/grovedb-version/src/version/v3.rs +++ b/grovedb-version/src/version/v3.rs @@ -9,7 +9,7 @@ use crate::version::{ GroveDBOperationsWorstCaseVersions, GroveDBPathQueryMethodVersions, GroveDBQueryLimits, GroveDBReplicationVersions, GroveDBVersions, }, - merk_versions::{MerkAverageCaseCostsVersions, MerkVersions}, + merk_versions::{MerkAverageCaseCostsVersions, MerkCommitVersions, MerkVersions}, GroveVersion, }; @@ -206,6 +206,7 @@ pub const GROVE_V3: GroveVersion = GroveVersion { }, }, merk_versions: MerkVersions { + commit: MerkCommitVersions { commit: 1 }, // return accumulated batch costs average_case_costs: MerkAverageCaseCostsVersions { add_average_case_merk_propagate: 1, sum_tree_estimated_size: 1, diff --git a/merk/src/merk/apply.rs b/merk/src/merk/apply.rs index 774af16c9..d19ca7001 100644 --- a/merk/src/merk/apply.rs +++ b/merk/src/merk/apply.rs @@ -364,7 +364,13 @@ where // we set the new root node of the merk tree self.tree.set(maybe_tree); // commit changes to db - self.commit(key_updates, aux, options, old_specialized_cost) + self.commit( + key_updates, + aux, + options, + old_specialized_cost, + grove_version, + ) }) } } diff --git a/merk/src/merk/mod.rs b/merk/src/merk/mod.rs index 768bef435..1145ec31c 100644 --- a/merk/src/merk/mod.rs +++ b/merk/src/merk/mod.rs @@ -384,6 +384,7 @@ where aux: &AuxMerkBatch, options: Option, old_specialized_cost: &impl Fn(&Vec, &Vec) -> Result, + grove_version: &GroveVersion, ) -> CostResult<(), Error> where K: AsRef<[u8]>, @@ -501,10 +502,17 @@ where } // write to db - self.storage - .commit_batch(batch) - .map_err(StorageError) - .add_cost(cost) + let commit_result = self.storage.commit_batch(batch).map_err(StorageError); + if grove_version.merk_versions.commit.commit >= 1 { + // V1+: preserve accumulated batch costs (seek counts, storage costs) + commit_result.add_cost(cost) + } else { + // V0: discard batch costs (legacy behavior) + CostContext { + value: commit_result.value, + cost, + } + } } /// Walk From 460c1a164b82e0d083b5f4d292ca80f102fd548f Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 10 Mar 2026 10:06:35 +0700 Subject: [PATCH 2/2] refactor: rename MerkCommitVersions to MerkBatchVersions Access path is now grove_version.merk_versions.batch.commit instead of grove_version.merk_versions.commit.commit. Co-Authored-By: Claude Opus 4.6 --- grovedb-version/src/version/merk_versions.rs | 4 ++-- grovedb-version/src/version/v1.rs | 4 ++-- grovedb-version/src/version/v2.rs | 4 ++-- grovedb-version/src/version/v3.rs | 4 ++-- merk/src/merk/mod.rs | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/grovedb-version/src/version/merk_versions.rs b/grovedb-version/src/version/merk_versions.rs index 34cd4bf28..69351b492 100644 --- a/grovedb-version/src/version/merk_versions.rs +++ b/grovedb-version/src/version/merk_versions.rs @@ -2,12 +2,12 @@ use versioned_feature_core::FeatureVersion; #[derive(Clone, Debug, Default)] pub struct MerkVersions { - pub commit: MerkCommitVersions, + pub batch: MerkBatchVersions, pub average_case_costs: MerkAverageCaseCostsVersions, } #[derive(Clone, Debug, Default)] -pub struct MerkCommitVersions { +pub struct MerkBatchVersions { /// Version 0: commit_batch discards accumulated batch costs (legacy bug) /// Version 1: commit_batch returns accumulated batch costs pub commit: FeatureVersion, diff --git a/grovedb-version/src/version/v1.rs b/grovedb-version/src/version/v1.rs index 4cfe5cc16..ff3d9fb93 100644 --- a/grovedb-version/src/version/v1.rs +++ b/grovedb-version/src/version/v1.rs @@ -9,7 +9,7 @@ use crate::version::{ GroveDBOperationsWorstCaseVersions, GroveDBPathQueryMethodVersions, GroveDBQueryLimits, GroveDBReplicationVersions, GroveDBVersions, }, - merk_versions::{MerkAverageCaseCostsVersions, MerkCommitVersions, MerkVersions}, + merk_versions::{MerkAverageCaseCostsVersions, MerkBatchVersions, MerkVersions}, GroveVersion, }; @@ -206,7 +206,7 @@ pub const GROVE_V1: GroveVersion = GroveVersion { }, }, merk_versions: MerkVersions { - commit: MerkCommitVersions { commit: 0 }, + batch: MerkBatchVersions { commit: 0 }, average_case_costs: MerkAverageCaseCostsVersions { add_average_case_merk_propagate: 0, sum_tree_estimated_size: 0, diff --git a/grovedb-version/src/version/v2.rs b/grovedb-version/src/version/v2.rs index faca231fa..99b7aea27 100644 --- a/grovedb-version/src/version/v2.rs +++ b/grovedb-version/src/version/v2.rs @@ -9,7 +9,7 @@ use crate::version::{ GroveDBOperationsWorstCaseVersions, GroveDBPathQueryMethodVersions, GroveDBQueryLimits, GroveDBReplicationVersions, GroveDBVersions, }, - merk_versions::{MerkAverageCaseCostsVersions, MerkCommitVersions, MerkVersions}, + merk_versions::{MerkAverageCaseCostsVersions, MerkBatchVersions, MerkVersions}, GroveVersion, }; @@ -206,7 +206,7 @@ pub const GROVE_V2: GroveVersion = GroveVersion { }, }, merk_versions: MerkVersions { - commit: MerkCommitVersions { commit: 0 }, + batch: MerkBatchVersions { commit: 0 }, average_case_costs: MerkAverageCaseCostsVersions { add_average_case_merk_propagate: 1, // changed sum_tree_estimated_size: 1, // changed diff --git a/grovedb-version/src/version/v3.rs b/grovedb-version/src/version/v3.rs index ec64313f4..217b679dd 100644 --- a/grovedb-version/src/version/v3.rs +++ b/grovedb-version/src/version/v3.rs @@ -9,7 +9,7 @@ use crate::version::{ GroveDBOperationsWorstCaseVersions, GroveDBPathQueryMethodVersions, GroveDBQueryLimits, GroveDBReplicationVersions, GroveDBVersions, }, - merk_versions::{MerkAverageCaseCostsVersions, MerkCommitVersions, MerkVersions}, + merk_versions::{MerkAverageCaseCostsVersions, MerkBatchVersions, MerkVersions}, GroveVersion, }; @@ -206,7 +206,7 @@ pub const GROVE_V3: GroveVersion = GroveVersion { }, }, merk_versions: MerkVersions { - commit: MerkCommitVersions { commit: 1 }, // return accumulated batch costs + batch: MerkBatchVersions { commit: 1 }, // return accumulated batch costs average_case_costs: MerkAverageCaseCostsVersions { add_average_case_merk_propagate: 1, sum_tree_estimated_size: 1, diff --git a/merk/src/merk/mod.rs b/merk/src/merk/mod.rs index 1145ec31c..3f86f3717 100644 --- a/merk/src/merk/mod.rs +++ b/merk/src/merk/mod.rs @@ -503,7 +503,7 @@ where // write to db let commit_result = self.storage.commit_batch(batch).map_err(StorageError); - if grove_version.merk_versions.commit.commit >= 1 { + if grove_version.merk_versions.batch.commit >= 1 { // V1+: preserve accumulated batch costs (seek counts, storage costs) commit_result.add_cost(cost) } else {