-
Notifications
You must be signed in to change notification settings - Fork 1.6k
fix(chainbase): defensive checks and resource leak fixes #6633
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,7 +35,7 @@ public enum Cursor { | |
| //true:fullnode, false:soliditynode | ||
| private ThreadLocal<Cursor> cursor = new ThreadLocal<>(); | ||
| private ThreadLocal<Long> offset = new ThreadLocal<>(); | ||
| private Snapshot head; | ||
| private volatile Snapshot head; | ||
|
|
||
| public Chainbase(Snapshot head) { | ||
| this.head = head; | ||
|
|
@@ -349,28 +349,32 @@ private Map<byte[], byte[]> getNext(Snapshot head, byte[] key, long limit) { | |
| .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); | ||
| } | ||
|
|
||
| // Snapshot head once: prefixQueryRoot and prefixQuerySnapshot both need the same | ||
| // head reference. Other read methods (get, getUnchecked, has) only read head once | ||
| // via head(), so volatile alone is sufficient for them. | ||
| public Map<WrappedByteArray, byte[]> prefixQuery(byte[] key) { | ||
| Map<WrappedByteArray, byte[]> result = prefixQueryRoot(key); | ||
| Map<WrappedByteArray, byte[]> snapshot = prefixQuerySnapshot(key); | ||
| Snapshot localHead = head; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Valid issue. The original code used Fix: change |
||
| Map<WrappedByteArray, byte[]> result = prefixQueryRoot(localHead, key); | ||
| Map<WrappedByteArray, byte[]> snapshot = prefixQuerySnapshot(localHead, key); | ||
| result.putAll(snapshot); | ||
| result.entrySet().removeIf(e -> e.getValue() == null); | ||
| return result; | ||
| } | ||
|
|
||
| private Map<WrappedByteArray, byte[]> prefixQueryRoot(byte[] key) { | ||
| private Map<WrappedByteArray, byte[]> prefixQueryRoot(Snapshot localHead, byte[] key) { | ||
| Map<WrappedByteArray, byte[]> result = new HashMap<>(); | ||
| if (((SnapshotRoot) head.getRoot()).db.getClass() == LevelDB.class) { | ||
| result = ((LevelDB) ((SnapshotRoot) head.getRoot()).db).getDb().prefixQuery(key); | ||
| } else if (((SnapshotRoot) head.getRoot()).db.getClass() == RocksDB.class) { | ||
| result = ((RocksDB) ((SnapshotRoot) head.getRoot()).db).getDb().prefixQuery(key); | ||
| if (((SnapshotRoot) localHead.getRoot()).db.getClass() == LevelDB.class) { | ||
| result = ((LevelDB) ((SnapshotRoot) localHead.getRoot()).db).getDb().prefixQuery(key); | ||
| } else if (((SnapshotRoot) localHead.getRoot()).db.getClass() == RocksDB.class) { | ||
| result = ((RocksDB) ((SnapshotRoot) localHead.getRoot()).db).getDb().prefixQuery(key); | ||
| } | ||
| return result; | ||
| } | ||
|
|
||
| private Map<WrappedByteArray, byte[]> prefixQuerySnapshot(byte[] key) { | ||
| private Map<WrappedByteArray, byte[]> prefixQuerySnapshot(Snapshot localHead, byte[] key) { | ||
| Map<WrappedByteArray, byte[]> result = new HashMap<>(); | ||
| Snapshot snapshot = head(); | ||
| if (!snapshot.equals(head.getRoot())) { | ||
| Snapshot snapshot = localHead; | ||
| if (!snapshot.equals(localHead.getRoot())) { | ||
| Map<WrappedByteArray, WrappedByteArray> all = new HashMap<>(); | ||
| ((SnapshotImpl) snapshot).collect(all, key); | ||
| all.forEach((k, v) -> result.put(k, v.getBytes())); | ||
|
Comment on lines
+376
to
380
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Though it appears to bind the query to the caller-selected view via
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch. You're right that This can be fixed by adding a boundary parameter to // SnapshotImpl.java
synchronized void collect(Map<WrappedByteArray, WrappedByteArray> all,
byte[] prefix, Snapshot boundary) {
Snapshot next = getRoot().getNext();
while (next != null) {
Streams.stream(((SnapshotImpl) next).db)
.filter(e -> Bytes.indexOf(
Objects.requireNonNull(e.getKey().getBytes()), prefix) == 0)
.forEach(e -> all.put(WrappedByteArray.of(e.getKey().getBytes()),
WrappedByteArray.of(e.getValue().getBytes())));
if (next == boundary) {
break;
}
next = next.getNext();
}
}Then ((SnapshotImpl) localHead).collect(all, key, localHead);That said, two notes:
Recommend tracking this as a separate follow-up issue rather than expanding the scope of this PR. |
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| package org.tron.common.zksnark; | ||
|
|
||
| import static org.junit.Assert.assertThrows; | ||
|
|
||
| import com.google.common.collect.Lists; | ||
| import java.util.Arrays; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
| import org.junit.Test; | ||
| import org.tron.core.exception.ZksnarkException; | ||
|
|
||
| public class MerklePathEncodeTest { | ||
|
|
||
| @Test | ||
| public void testEncode_sizeMismatch_throwsZksnarkException() { | ||
| List<List<Boolean>> authPath = Arrays.asList( | ||
| Arrays.asList(true, false), | ||
| Arrays.asList(false, true) | ||
| ); | ||
| List<Boolean> index = Collections.singletonList(true); // size 1, authPath size 2 | ||
|
|
||
| MerklePath merklePath = new MerklePath(authPath, index); | ||
|
|
||
| assertThrows(ZksnarkException.class, merklePath::encode); | ||
| } | ||
|
|
||
| @Test | ||
| public void testEncode_emptyLists_noException() throws ZksnarkException { | ||
| MerklePath merklePath = new MerklePath(Lists.newArrayList(), Lists.newArrayList()); | ||
| merklePath.encode(); // should not throw | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It needs to be further confirmed that this branch would not have occurred historically.