|
|
|
@ -341,59 +341,55 @@ public class BonsaiWorldState |
|
|
|
|
final Optional<BonsaiWorldStateKeyValueStorage.BonsaiUpdater> maybeStateUpdater, |
|
|
|
|
final BonsaiWorldStateUpdateAccumulator worldStateUpdater) { |
|
|
|
|
|
|
|
|
|
maybeStateUpdater.ifPresent( |
|
|
|
|
bonsaiUpdater -> { |
|
|
|
|
for (final Address address : worldStateUpdater.getStorageToClear()) { |
|
|
|
|
// because we are clearing persisted values we need the account root as persisted
|
|
|
|
|
final BonsaiAccount oldAccount = |
|
|
|
|
worldStateStorage |
|
|
|
|
.getAccount(address.addressHash()) |
|
|
|
|
.map( |
|
|
|
|
bytes -> BonsaiAccount.fromRLP(BonsaiWorldState.this, address, bytes, true)) |
|
|
|
|
.orElse(null); |
|
|
|
|
if (oldAccount == null) { |
|
|
|
|
// This is when an account is both created and deleted within the scope of the same
|
|
|
|
|
// block. A not-uncommon DeFi bot pattern.
|
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
final Hash addressHash = address.addressHash(); |
|
|
|
|
final MerkleTrie<Bytes, Bytes> storageTrie = |
|
|
|
|
createTrie( |
|
|
|
|
(location, key) -> getStorageTrieNode(addressHash, location, key), |
|
|
|
|
oldAccount.getStorageRoot()); |
|
|
|
|
try { |
|
|
|
|
|
|
|
|
|
final StorageConsumingMap<StorageSlotKey, BonsaiValue<UInt256>> storageToDelete = |
|
|
|
|
worldStateUpdater.getStorageToUpdate().get(address); |
|
|
|
|
Map<Bytes32, Bytes> entriesToDelete = storageTrie.entriesFrom(Bytes32.ZERO, 256); |
|
|
|
|
while (!entriesToDelete.isEmpty()) { |
|
|
|
|
entriesToDelete.forEach( |
|
|
|
|
(k, v) -> { |
|
|
|
|
final StorageSlotKey storageSlotKey = |
|
|
|
|
new StorageSlotKey(Hash.wrap(k), Optional.empty()); |
|
|
|
|
final UInt256 slotValue = |
|
|
|
|
UInt256.fromBytes(Bytes32.leftPad(RLP.decodeValue(v))); |
|
|
|
|
bonsaiUpdater.removeStorageValueBySlotHash( |
|
|
|
|
address.addressHash(), storageSlotKey.getSlotHash()); |
|
|
|
|
storageToDelete |
|
|
|
|
.computeIfAbsent( |
|
|
|
|
storageSlotKey, key -> new BonsaiValue<>(slotValue, null, true)) |
|
|
|
|
.setPrior(slotValue); |
|
|
|
|
}); |
|
|
|
|
entriesToDelete.keySet().forEach(storageTrie::remove); |
|
|
|
|
if (entriesToDelete.size() == 256) { |
|
|
|
|
entriesToDelete = storageTrie.entriesFrom(Bytes32.ZERO, 256); |
|
|
|
|
} else { |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} catch (MerkleTrieException e) { |
|
|
|
|
// need to throw to trigger the heal
|
|
|
|
|
throw new MerkleTrieException( |
|
|
|
|
e.getMessage(), Optional.of(Address.wrap(address)), e.getHash(), e.getLocation()); |
|
|
|
|
} |
|
|
|
|
for (final Address address : worldStateUpdater.getStorageToClear()) { |
|
|
|
|
// because we are clearing persisted values we need the account root as persisted
|
|
|
|
|
final BonsaiAccount oldAccount = |
|
|
|
|
worldStateStorage |
|
|
|
|
.getAccount(address.addressHash()) |
|
|
|
|
.map(bytes -> BonsaiAccount.fromRLP(BonsaiWorldState.this, address, bytes, true)) |
|
|
|
|
.orElse(null); |
|
|
|
|
if (oldAccount == null) { |
|
|
|
|
// This is when an account is both created and deleted within the scope of the same
|
|
|
|
|
// block. A not-uncommon DeFi bot pattern.
|
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
final Hash addressHash = address.addressHash(); |
|
|
|
|
final MerkleTrie<Bytes, Bytes> storageTrie = |
|
|
|
|
createTrie( |
|
|
|
|
(location, key) -> getStorageTrieNode(addressHash, location, key), |
|
|
|
|
oldAccount.getStorageRoot()); |
|
|
|
|
try { |
|
|
|
|
final StorageConsumingMap<StorageSlotKey, BonsaiValue<UInt256>> storageToDelete = |
|
|
|
|
worldStateUpdater.getStorageToUpdate().get(address); |
|
|
|
|
Map<Bytes32, Bytes> entriesToDelete = storageTrie.entriesFrom(Bytes32.ZERO, 256); |
|
|
|
|
while (!entriesToDelete.isEmpty()) { |
|
|
|
|
entriesToDelete.forEach( |
|
|
|
|
(k, v) -> { |
|
|
|
|
final StorageSlotKey storageSlotKey = |
|
|
|
|
new StorageSlotKey(Hash.wrap(k), Optional.empty()); |
|
|
|
|
final UInt256 slotValue = UInt256.fromBytes(Bytes32.leftPad(RLP.decodeValue(v))); |
|
|
|
|
maybeStateUpdater.ifPresent( |
|
|
|
|
bonsaiUpdater -> |
|
|
|
|
bonsaiUpdater.removeStorageValueBySlotHash( |
|
|
|
|
address.addressHash(), storageSlotKey.getSlotHash())); |
|
|
|
|
storageToDelete |
|
|
|
|
.computeIfAbsent( |
|
|
|
|
storageSlotKey, key -> new BonsaiValue<>(slotValue, null, true)) |
|
|
|
|
.setPrior(slotValue); |
|
|
|
|
}); |
|
|
|
|
entriesToDelete.keySet().forEach(storageTrie::remove); |
|
|
|
|
if (entriesToDelete.size() == 256) { |
|
|
|
|
entriesToDelete = storageTrie.entriesFrom(Bytes32.ZERO, 256); |
|
|
|
|
} else { |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
} catch (MerkleTrieException e) { |
|
|
|
|
// need to throw to trigger the heal
|
|
|
|
|
throw new MerkleTrieException( |
|
|
|
|
e.getMessage(), Optional.of(Address.wrap(address)), e.getHash(), e.getLocation()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|