Withdrawals processor to clear empty accounts (#4995)

Signed-off-by: Jason Frame <jason.frame@consensys.net>
pull/5001/head
Jason Frame 2 years ago committed by GitHub
parent b22a52a88e
commit 4c678a1050
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java
  2. 1
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/WithdrawalsProcessor.java
  3. 29
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/WithdrawalsProcessorTest.java
  4. 7
      evm/src/main/java/org/hyperledger/besu/evm/worldstate/WorldUpdater.java

@ -45,7 +45,6 @@ import org.hyperledger.besu.evm.tracing.OperationTracer;
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;
@ -463,7 +462,7 @@ public class MainnetTransactionProcessor {
initialFrame.getSelfDestructs().forEach(worldState::deleteAccount);
if (clearEmptyAccounts) {
clearAccountsThatAreEmpty(worldState);
worldState.clearAccountsThatAreEmpty();
}
if (initialFrame.getState() == MessageFrame.State.COMPLETED_SUCCESS) {
@ -489,11 +488,6 @@ public class MainnetTransactionProcessor {
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());

@ -28,6 +28,7 @@ public class WithdrawalsProcessor {
final EvmAccount account = worldUpdater.getOrCreate(withdrawal.getAddress());
account.getMutable().incrementBalance(withdrawal.getAmount().getAsWei());
}
worldUpdater.clearAccountsThatAreEmpty();
worldUpdater.commit();
}
}

@ -35,7 +35,7 @@ import org.junit.jupiter.api.Test;
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();
@ -51,7 +51,7 @@ class WithdrawalsProcessorTest {
}
@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();
@ -79,7 +79,7 @@ class WithdrawalsProcessorTest {
}
@Test
void defaultProcessor_shouldProcessWithdrawalsUpdatingEmptyAccountsBalance() {
void shouldProcessWithdrawalsUpdatingEmptyAccountsBalance() {
final MutableWorldState worldState = createWorldStateWithAccounts(Collections.emptyList());
final WorldUpdater updater = worldState.updater();
@ -104,6 +104,27 @@ class WithdrawalsProcessorTest {
.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();
@ -111,7 +132,7 @@ class WithdrawalsProcessorTest {
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;
}

@ -21,6 +21,7 @@ import org.hyperledger.besu.evm.account.EvmAccount;
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;
@ -145,4 +146,10 @@ public interface WorldUpdater extends MutableWorldView {
* @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()));
}
}

Loading…
Cancel
Save