Skip to content

Commit 2bf5dc4

Browse files
authored
Fix change/range proofs + simplify the code (#3688)
1 parent acb9fe6 commit 2bf5dc4

File tree

11 files changed

+761
-683
lines changed

11 files changed

+761
-683
lines changed

x/merkledb/db.go

Lines changed: 46 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -442,19 +442,19 @@ func (db *merkleDB) CommitRangeProof(ctx context.Context, start, end maybe.Maybe
442442
return database.ErrClosed
443443
}
444444

445-
ops := make([]database.BatchOp, len(proof.KeyValues))
446-
keys := set.NewSet[string](len(proof.KeyValues))
447-
for i, kv := range proof.KeyValues {
445+
ops := make([]database.BatchOp, len(proof.KeyChanges))
446+
keys := set.NewSet[string](len(proof.KeyChanges))
447+
for i, kv := range proof.KeyChanges {
448448
keys.Add(string(kv.Key))
449449
ops[i] = database.BatchOp{
450450
Key: kv.Key,
451-
Value: kv.Value,
451+
Value: kv.Value.Value(),
452452
}
453453
}
454454

455455
largestKey := end
456-
if len(proof.KeyValues) > 0 {
457-
largestKey = maybe.Some(proof.KeyValues[len(proof.KeyValues)-1].Key)
456+
if len(proof.KeyChanges) > 0 {
457+
largestKey = maybe.Some(proof.KeyChanges[len(proof.KeyChanges)-1].Key)
458458
}
459459
keysToDelete, err := db.getKeysNotInSet(start, largestKey, keys)
460460
if err != nil {
@@ -1094,86 +1094,66 @@ func (db *merkleDB) VerifyChangeProof(
10941094
end maybe.Maybe[[]byte],
10951095
expectedEndRootID ids.ID,
10961096
) error {
1097-
switch {
1098-
case start.HasValue() && end.HasValue() && bytes.Compare(start.Value(), end.Value()) > 0:
1099-
return ErrStartAfterEnd
1100-
case proof.Empty():
1097+
if proof == nil {
11011098
return ErrEmptyProof
1102-
case end.HasValue() && len(proof.KeyChanges) == 0 && len(proof.EndProof) == 0:
1103-
// We requested an end proof but didn't get one.
1104-
return ErrNoEndProof
1105-
case start.HasValue() && len(proof.StartProof) == 0 && len(proof.EndProof) == 0:
1106-
// We requested a start proof but didn't get one.
1107-
// Note that we also have to check that [proof.EndProof] is empty
1108-
// to handle the case that the start proof is empty because all
1109-
// its nodes are also in the end proof, and those nodes are omitted.
1110-
return ErrNoStartProof
1111-
}
1112-
1113-
// Make sure the key-value pairs are sorted and in [start, end].
1114-
if err := verifyKeyChanges(proof.KeyChanges, start, end); err != nil {
1115-
return err
11161099
}
11171100

1118-
smallestKey := maybe.Bind(start, ToKey)
1101+
startProofKey := maybe.Bind(start, ToKey)
1102+
endProofKey := maybe.Bind(end, ToKey)
11191103

1120-
// Make sure the start proof, if given, is well-formed.
1121-
if err := verifyProofPath(proof.StartProof, smallestKey); err != nil {
1122-
return err
1123-
}
1124-
1125-
// Find the greatest key in [proof.KeyChanges]
1126-
// Note that [proof.EndProof] is a proof for this key.
1127-
// [largestKey] is also used when we add children of proof nodes to [trie] below.
1128-
largestKey := maybe.Bind(end, ToKey)
1104+
// Update [endProofKey] with the largest key in [keyValues].
11291105
if len(proof.KeyChanges) > 0 {
1130-
// If [proof] has key-value pairs, we should insert children
1131-
// greater than [end] to ancestors of the node containing [end]
1132-
// so that we get the expected root ID.
1133-
largestKey = maybe.Some(ToKey(proof.KeyChanges[len(proof.KeyChanges)-1].Key))
1106+
endProofKey = maybe.Some(ToKey(proof.KeyChanges[len(proof.KeyChanges)-1].Key))
11341107
}
11351108

1136-
// Make sure the end proof, if given, is well-formed.
1137-
if err := verifyProofPath(proof.EndProof, largestKey); err != nil {
1109+
// Validate proof.
1110+
if err := validateChangeProof(
1111+
startProofKey,
1112+
maybe.Bind(end, ToKey),
1113+
proof.StartProof,
1114+
proof.EndProof,
1115+
proof.KeyChanges,
1116+
endProofKey,
1117+
db.tokenSize,
1118+
); err != nil {
11381119
return err
11391120
}
11401121

1141-
keyValues := make(map[Key]maybe.Maybe[[]byte], len(proof.KeyChanges))
1142-
for _, keyValue := range proof.KeyChanges {
1143-
keyValues[ToKey(keyValue.Key)] = keyValue.Value
1144-
}
1145-
1146-
// want to prevent commit writes to DB, but not prevent DB reads
1122+
// Prevent commit writes to DB, but not prevent DB reads
11471123
db.commitLock.RLock()
11481124
defer db.commitLock.RUnlock()
11491125

11501126
if db.closed {
11511127
return database.ErrClosed
11521128
}
11531129

1154-
if err := verifyAllChangeProofKeyValuesPresent(
1130+
// Ensure that the [startProof] has correct values.
1131+
if err := verifyChangeProofKeyValues(
11551132
ctx,
11561133
db,
1134+
proof.KeyChanges,
11571135
proof.StartProof,
1158-
smallestKey,
1159-
largestKey,
1160-
keyValues,
1136+
startProofKey,
1137+
endProofKey,
1138+
db.hasher,
11611139
); err != nil {
1162-
return err
1140+
return fmt.Errorf("failed to verify start proof nodes: %w", err)
11631141
}
11641142

1165-
if err := verifyAllChangeProofKeyValuesPresent(
1143+
// Ensure that the [endProof] has correct values.
1144+
if err := verifyChangeProofKeyValues(
11661145
ctx,
11671146
db,
1147+
proof.KeyChanges,
11681148
proof.EndProof,
1169-
smallestKey,
1170-
largestKey,
1171-
keyValues,
1149+
startProofKey,
1150+
endProofKey,
1151+
db.hasher,
11721152
); err != nil {
1173-
return err
1153+
return fmt.Errorf("failed to validate end proof nodes: %w", err)
11741154
}
11751155

1176-
// Insert the key-value pairs into the trie.
1156+
// Prepare ops for the creation of the view.
11771157
ops := make([]database.BatchOp, len(proof.KeyChanges))
11781158
for i, kv := range proof.KeyChanges {
11791159
ops[i] = database.BatchOp{
@@ -1189,32 +1169,34 @@ func (db *merkleDB) VerifyChangeProof(
11891169
return err
11901170
}
11911171

1192-
// For all the nodes along the edges of the proof, insert the children whose
1172+
// For all the nodes along the edges of the proofs, insert the children whose
11931173
// keys are less than [insertChildrenLessThan] or whose keys are greater
11941174
// than [insertChildrenGreaterThan] into the trie so that we get the
11951175
// expected root ID (if this proof is valid).
11961176
if err := addPathInfo(
11971177
view,
11981178
proof.StartProof,
1199-
smallestKey,
1200-
largestKey,
1179+
startProofKey,
1180+
endProofKey,
12011181
); err != nil {
1202-
return err
1182+
return fmt.Errorf("failed to add start proof path info: %w", err)
12031183
}
1184+
12041185
if err := addPathInfo(
12051186
view,
12061187
proof.EndProof,
1207-
smallestKey,
1208-
largestKey,
1188+
startProofKey,
1189+
endProofKey,
12091190
); err != nil {
1210-
return err
1191+
return fmt.Errorf("failed to add end proof path info: %w", err)
12111192
}
12121193

12131194
// Make sure we get the expected root.
12141195
calculatedRoot, err := view.GetMerkleRoot(ctx)
12151196
if err != nil {
12161197
return err
12171198
}
1199+
12181200
if expectedEndRootID != calculatedRoot {
12191201
return fmt.Errorf("%w:[%s], expected:[%s]", ErrInvalidProof, calculatedRoot, expectedEndRootID)
12201202
}

x/merkledb/db_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ func Test_MerkleDB_CommitRangeProof_DeletesValuesInRange(t *testing.T) {
317317
require.NoError(err)
318318

319319
// confirm there are no key.values in the proof
320-
require.Empty(proof.KeyValues)
320+
require.Empty(proof.KeyChanges)
321321

322322
// add values to be deleted by proof commit
323323
batch := db.NewBatch()
@@ -938,7 +938,7 @@ func runRandDBTest(require *require.Assertions, r *rand.Rand, rt randTest, token
938938
continue
939939
}
940940
require.NoError(err)
941-
require.LessOrEqual(len(rangeProof.KeyValues), maxProofLen)
941+
require.LessOrEqual(len(rangeProof.KeyChanges), maxProofLen)
942942

943943
require.NoError(rangeProof.Verify(
944944
context.Background(),

x/merkledb/helpers_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,15 @@ func getBasicDB() (*merkleDB, error) {
2525
)
2626
}
2727

28-
func getBasicDBWithBranchFactor(bf BranchFactor) (MerkleDB, error) {
28+
func getBasicDBWithBranchFactor(bf BranchFactor) (*merkleDB, error) {
2929
config := NewConfig()
3030
config.BranchFactor = bf
31-
return New(
31+
32+
return newDatabase(
3233
context.Background(),
3334
memdb.New(),
3435
config,
36+
&mockMetrics{},
3537
)
3638
}
3739

0 commit comments

Comments
 (0)