Skip to content

Commit

Permalink
Withdrawals processor to clear empty accounts (hyperledger#4995)
Browse files Browse the repository at this point in the history
Signed-off-by: Jason Frame <jason.frame@consensys.net>
  • Loading branch information
jframe authored Jan 25, 2023
1 parent b22a52a commit 4c678a1
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
import org.hyperledger.besu.evm.worldstate.WorldUpdater;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -463,7 +462,7 @@ public TransactionProcessingResult processTransaction(
initialFrame.getSelfDestructs().forEach(worldState::deleteAccount);

if (clearEmptyAccounts) {
clearAccountsThatAreEmpty(worldState);
worldState.clearAccountsThatAreEmpty();
}

if (initialFrame.getState() == MessageFrame.State.COMPLETED_SUCCESS) {
Expand All @@ -489,11 +488,6 @@ public MainnetTransactionValidator getTransactionValidator() {
return transactionValidator;
}

private static void clearAccountsThatAreEmpty(final WorldUpdater worldState) {
new ArrayList<>(worldState.getTouchedAccounts())
.stream().filter(Account::isEmpty).forEach(a -> worldState.deleteAccount(a.getAddress()));
}

protected void process(final MessageFrame frame, final OperationTracer operationTracer) {
final AbstractMessageProcessor executor = getMessageProcessor(frame.getType());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public void processWithdrawals(
final EvmAccount account = worldUpdater.getOrCreate(withdrawal.getAddress());
account.getMutable().incrementBalance(withdrawal.getAmount().getAsWei());
}
worldUpdater.clearAccountsThatAreEmpty();
worldUpdater.commit();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
class WithdrawalsProcessorTest {

@Test
void defaultProcessor_shouldProcessEmptyWithdrawalsWithoutChangingWorldState() {
void shouldProcessEmptyWithdrawalsWithoutChangingWorldState() {
final MutableWorldState worldState =
createWorldStateWithAccounts(List.of(entry("0x1", 1), entry("0x2", 2), entry("0x3", 3)));
final MutableWorldState originalState = worldState.copy();
Expand All @@ -51,7 +51,7 @@ void defaultProcessor_shouldProcessEmptyWithdrawalsWithoutChangingWorldState() {
}

@Test
void defaultProcessor_shouldProcessWithdrawalsUpdatingExistingAccountsBalance() {
void shouldProcessWithdrawalsUpdatingExistingAccountsBalance() {
final MutableWorldState worldState =
createWorldStateWithAccounts(List.of(entry("0x1", 1), entry("0x2", 2), entry("0x3", 3)));
final WorldUpdater updater = worldState.updater();
Expand Down Expand Up @@ -79,7 +79,7 @@ void defaultProcessor_shouldProcessWithdrawalsUpdatingExistingAccountsBalance()
}

@Test
void defaultProcessor_shouldProcessWithdrawalsUpdatingEmptyAccountsBalance() {
void shouldProcessWithdrawalsUpdatingEmptyAccountsBalance() {
final MutableWorldState worldState = createWorldStateWithAccounts(Collections.emptyList());
final WorldUpdater updater = worldState.updater();

Expand All @@ -104,14 +104,35 @@ void defaultProcessor_shouldProcessWithdrawalsUpdatingEmptyAccountsBalance() {
.isEqualTo(GWei.of(200).getAsWei());
}

@Test
void shouldDeleteEmptyAccounts() {
final MutableWorldState worldState = createWorldStateWithAccounts(List.of(entry("0x1", 0)));
final WorldUpdater updater = worldState.updater();

final List<Withdrawal> withdrawals =
List.of(
new Withdrawal(
UInt64.valueOf(100), UInt64.valueOf(1000), Address.fromHexString("0x1"), GWei.ZERO),
new Withdrawal(
UInt64.valueOf(200),
UInt64.valueOf(2000),
Address.fromHexString("0x2"),
GWei.ZERO));
final WithdrawalsProcessor withdrawalsProcessor = new WithdrawalsProcessor();
withdrawalsProcessor.processWithdrawals(withdrawals, updater);

assertThat(worldState.get(Address.fromHexString("0x1"))).isNull();
assertThat(worldState.get(Address.fromHexString("0x2"))).isNull();
}

private MutableWorldState createWorldStateWithAccounts(
final List<Map.Entry<String, Integer>> accountBalances) {
final MutableWorldState worldState = InMemoryKeyValueStorageProvider.createInMemoryWorldState();
final WorldUpdater updater = worldState.updater();
accountBalances.forEach(
entry ->
updater.createAccount(
Address.fromHexString(entry.getKey()), 1, Wei.of(entry.getValue())));
Address.fromHexString(entry.getKey()), 0, Wei.of(entry.getValue())));
updater.commit();
return worldState;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.frame.MessageFrame;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Optional;

Expand Down Expand Up @@ -145,4 +146,10 @@ default EvmAccount getSenderAccount(final MessageFrame frame) {
* @return The parent WorldUpdater if this wraps another one, empty otherwise
*/
Optional<WorldUpdater> parentUpdater();

/** Clears any accounts that are empty */
default void clearAccountsThatAreEmpty() {
new ArrayList<>(getTouchedAccounts())
.stream().filter(Account::isEmpty).forEach(a -> deleteAccount(a.getAddress()));
}
}

0 comments on commit 4c678a1

Please sign in to comment.