-
Notifications
You must be signed in to change notification settings - Fork 880
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* use optimistictransactiondb for mutable isolated snapshots * plumbing necessary to have a snapshot specific updater. * snapshot rolling working * implement AutoCloseable on BonsaiSnapshotWorldState to ensure we can correctly dispose of snapshots * add snapshot transaction cloning, change snapshot based worldstate to extend persisted worldstate rather than in-memory worldstate Signed-off-by: garyschulte <garyschulte@gmail.com>
- Loading branch information
1 parent
e0b26d2
commit d73ce21
Showing
29 changed files
with
1,220 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
92 changes: 92 additions & 0 deletions
92
...eum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiSnapshotWorldState.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/* | ||
* Copyright Hyperledger Besu Contributors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on | ||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations under the License. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
package org.hyperledger.besu.ethereum.bonsai; | ||
|
||
import org.hyperledger.besu.ethereum.core.BlockHeader; | ||
import org.hyperledger.besu.ethereum.core.MutableWorldState; | ||
import org.hyperledger.besu.ethereum.core.SnapshotMutableWorldState; | ||
import org.hyperledger.besu.plugin.services.storage.SnappableKeyValueStorage; | ||
import org.hyperledger.besu.plugin.services.storage.SnappedKeyValueStorage; | ||
|
||
/** | ||
* This class takes a snapshot of the worldstate as the basis of a mutable worldstate. It is able to | ||
* commit/perist as a trielog layer only. This is useful for async blockchain opperations like block | ||
* creation and/or point-in-time queries since the snapshot worldstate is fully isolated from the | ||
* main BonsaiPersistedWorldState. | ||
*/ | ||
public class BonsaiSnapshotWorldState extends BonsaiInMemoryWorldState | ||
implements SnapshotMutableWorldState { | ||
|
||
private final SnappedKeyValueStorage accountSnap; | ||
private final SnappedKeyValueStorage codeSnap; | ||
private final SnappedKeyValueStorage storageSnap; | ||
private final SnappedKeyValueStorage trieBranchSnap; | ||
|
||
private BonsaiSnapshotWorldState( | ||
final BonsaiWorldStateArchive archive, | ||
final BonsaiSnapshotWorldStateKeyValueStorage snapshotWorldStateStorage) { | ||
super(archive, snapshotWorldStateStorage); | ||
this.accountSnap = (SnappedKeyValueStorage) snapshotWorldStateStorage.accountStorage; | ||
this.codeSnap = (SnappedKeyValueStorage) snapshotWorldStateStorage.codeStorage; | ||
this.storageSnap = (SnappedKeyValueStorage) snapshotWorldStateStorage.storageStorage; | ||
this.trieBranchSnap = (SnappedKeyValueStorage) snapshotWorldStateStorage.trieBranchStorage; | ||
} | ||
|
||
public static BonsaiSnapshotWorldState create( | ||
final BonsaiWorldStateArchive archive, | ||
final BonsaiWorldStateKeyValueStorage parentWorldStateStorage) { | ||
return new BonsaiSnapshotWorldState( | ||
archive, | ||
new BonsaiSnapshotWorldStateKeyValueStorage( | ||
((SnappableKeyValueStorage) parentWorldStateStorage.accountStorage).takeSnapshot(), | ||
((SnappableKeyValueStorage) parentWorldStateStorage.codeStorage).takeSnapshot(), | ||
((SnappableKeyValueStorage) parentWorldStateStorage.storageStorage).takeSnapshot(), | ||
((SnappableKeyValueStorage) parentWorldStateStorage.trieBranchStorage).takeSnapshot(), | ||
parentWorldStateStorage.trieLogStorage)); | ||
} | ||
|
||
@Override | ||
public void persist(final BlockHeader blockHeader) { | ||
super.persist(blockHeader); | ||
// persist roothash to snapshot tx | ||
trieBranchSnap | ||
.getSnapshotTransaction() | ||
.put( | ||
BonsaiWorldStateKeyValueStorage.WORLD_ROOT_HASH_KEY, | ||
worldStateRootHash.toArrayUnsafe()); | ||
} | ||
|
||
@Override | ||
public MutableWorldState copy() { | ||
// return a clone-based copy of worldstate storage | ||
return new BonsaiSnapshotWorldState( | ||
archive, | ||
new BonsaiSnapshotWorldStateKeyValueStorage( | ||
accountSnap.cloneFromSnapshot(), | ||
codeSnap.cloneFromSnapshot(), | ||
storageSnap.cloneFromSnapshot(), | ||
trieBranchSnap.cloneFromSnapshot(), | ||
worldStateStorage.trieLogStorage)); | ||
} | ||
|
||
@Override | ||
public void close() throws Exception { | ||
accountSnap.close(); | ||
codeSnap.close(); | ||
storageSnap.close(); | ||
trieBranchSnap.close(); | ||
} | ||
} |
190 changes: 190 additions & 0 deletions
190
...in/java/org/hyperledger/besu/ethereum/bonsai/BonsaiSnapshotWorldStateKeyValueStorage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
/* | ||
* Copyright Hyperledger Besu Contributors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on | ||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations under the License. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
package org.hyperledger.besu.ethereum.bonsai; | ||
|
||
import org.hyperledger.besu.datatypes.Hash; | ||
import org.hyperledger.besu.ethereum.trie.MerklePatriciaTrie; | ||
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; | ||
import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; | ||
import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction; | ||
import org.hyperledger.besu.plugin.services.storage.SnappedKeyValueStorage; | ||
|
||
import org.apache.tuweni.bytes.Bytes; | ||
import org.apache.tuweni.bytes.Bytes32; | ||
|
||
public class BonsaiSnapshotWorldStateKeyValueStorage extends BonsaiWorldStateKeyValueStorage { | ||
|
||
public BonsaiSnapshotWorldStateKeyValueStorage( | ||
final SnappedKeyValueStorage accountStorage, | ||
final SnappedKeyValueStorage codeStorage, | ||
final SnappedKeyValueStorage storageStorage, | ||
final SnappedKeyValueStorage trieBranchStorage, | ||
final KeyValueStorage trieLogStorage) { | ||
super(accountStorage, codeStorage, storageStorage, trieBranchStorage, trieLogStorage); | ||
} | ||
|
||
@Override | ||
public BonsaiUpdater updater() { | ||
return new SnapshotUpdater( | ||
(SnappedKeyValueStorage) accountStorage, | ||
(SnappedKeyValueStorage) codeStorage, | ||
(SnappedKeyValueStorage) storageStorage, | ||
(SnappedKeyValueStorage) trieBranchStorage, | ||
trieLogStorage); | ||
} | ||
|
||
public static class SnapshotUpdater implements BonsaiWorldStateKeyValueStorage.BonsaiUpdater { | ||
// private static final Logger LOG = | ||
// LoggerFactory.getLogger(BonsaiSnapshotWorldStateKeyValueStorage.class); | ||
|
||
private final SnappedKeyValueStorage accountStorage; | ||
private final SnappedKeyValueStorage codeStorage; | ||
private final SnappedKeyValueStorage storageStorage; | ||
private final SnappedKeyValueStorage trieBranchStorage; | ||
private final KeyValueStorageTransaction trieLogStorageTransaction; | ||
|
||
public SnapshotUpdater( | ||
final SnappedKeyValueStorage accountStorage, | ||
final SnappedKeyValueStorage codeStorage, | ||
final SnappedKeyValueStorage storageStorage, | ||
final SnappedKeyValueStorage trieBranchStorage, | ||
final KeyValueStorage trieLogStorage) { | ||
this.accountStorage = accountStorage; | ||
this.codeStorage = codeStorage; | ||
this.storageStorage = storageStorage; | ||
this.trieBranchStorage = trieBranchStorage; | ||
this.trieLogStorageTransaction = trieLogStorage.startTransaction(); | ||
} | ||
|
||
@Override | ||
public BonsaiUpdater removeCode(final Hash accountHash) { | ||
codeStorage.getSnapshotTransaction().remove(accountHash.toArrayUnsafe()); | ||
return this; | ||
} | ||
|
||
@Override | ||
public WorldStateStorage.Updater putCode( | ||
final Hash accountHash, final Bytes32 nodeHash, final Bytes code) { | ||
if (code.size() == 0) { | ||
// Don't save empty values | ||
return this; | ||
} | ||
codeStorage.getSnapshotTransaction().put(accountHash.toArrayUnsafe(), code.toArrayUnsafe()); | ||
return this; | ||
} | ||
|
||
@Override | ||
public BonsaiUpdater removeAccountInfoState(final Hash accountHash) { | ||
accountStorage.getSnapshotTransaction().remove(accountHash.toArrayUnsafe()); | ||
return this; | ||
} | ||
|
||
@Override | ||
public BonsaiUpdater putAccountInfoState(final Hash accountHash, final Bytes accountValue) { | ||
if (accountValue.size() == 0) { | ||
// Don't save empty values | ||
return this; | ||
} | ||
accountStorage | ||
.getSnapshotTransaction() | ||
.put(accountHash.toArrayUnsafe(), accountValue.toArrayUnsafe()); | ||
return this; | ||
} | ||
|
||
@Override | ||
public BonsaiUpdater putStorageValueBySlotHash( | ||
final Hash accountHash, final Hash slotHash, final Bytes storage) { | ||
storageStorage | ||
.getSnapshotTransaction() | ||
.put(Bytes.concatenate(accountHash, slotHash).toArrayUnsafe(), storage.toArrayUnsafe()); | ||
return this; | ||
} | ||
|
||
@Override | ||
public void removeStorageValueBySlotHash(final Hash accountHash, final Hash slotHash) { | ||
storageStorage | ||
.getSnapshotTransaction() | ||
.remove(Bytes.concatenate(accountHash, slotHash).toArrayUnsafe()); | ||
} | ||
|
||
@Override | ||
public KeyValueStorageTransaction getTrieBranchStorageTransaction() { | ||
return trieBranchStorage.getSnapshotTransaction(); | ||
} | ||
|
||
@Override | ||
public KeyValueStorageTransaction getTrieLogStorageTransaction() { | ||
return trieLogStorageTransaction; | ||
} | ||
|
||
@Override | ||
public WorldStateStorage.Updater saveWorldState( | ||
final Bytes blockHash, final Bytes32 nodeHash, final Bytes node) { | ||
trieBranchStorage | ||
.getSnapshotTransaction() | ||
.put(Bytes.EMPTY.toArrayUnsafe(), node.toArrayUnsafe()); | ||
trieBranchStorage.getSnapshotTransaction().put(WORLD_ROOT_HASH_KEY, nodeHash.toArrayUnsafe()); | ||
trieBranchStorage | ||
.getSnapshotTransaction() | ||
.put(WORLD_BLOCK_HASH_KEY, blockHash.toArrayUnsafe()); | ||
return this; | ||
} | ||
|
||
@Override | ||
public WorldStateStorage.Updater putAccountStateTrieNode( | ||
final Bytes location, final Bytes32 nodeHash, final Bytes node) { | ||
if (nodeHash.equals(MerklePatriciaTrie.EMPTY_TRIE_NODE_HASH)) { | ||
// Don't save empty nodes | ||
return this; | ||
} | ||
trieBranchStorage | ||
.getSnapshotTransaction() | ||
.put(location.toArrayUnsafe(), node.toArrayUnsafe()); | ||
return this; | ||
} | ||
|
||
@Override | ||
public WorldStateStorage.Updater removeAccountStateTrieNode( | ||
final Bytes location, final Bytes32 nodeHash) { | ||
trieBranchStorage.getSnapshotTransaction().remove(location.toArrayUnsafe()); | ||
return this; | ||
} | ||
|
||
@Override | ||
public WorldStateStorage.Updater putAccountStorageTrieNode( | ||
final Hash accountHash, final Bytes location, final Bytes32 nodeHash, final Bytes node) { | ||
if (nodeHash.equals(MerklePatriciaTrie.EMPTY_TRIE_NODE_HASH)) { | ||
// Don't save empty nodes | ||
return this; | ||
} | ||
trieBranchStorage | ||
.getSnapshotTransaction() | ||
.put(Bytes.concatenate(accountHash, location).toArrayUnsafe(), node.toArrayUnsafe()); | ||
return this; | ||
} | ||
|
||
@Override | ||
public void commit() { | ||
// only commit the trielog layer transaction, leave the snapshot transactions open: | ||
trieLogStorageTransaction.commit(); | ||
} | ||
|
||
@Override | ||
public void rollback() { | ||
// no-op | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.