@ -29,7 +29,6 @@ import org.hyperledger.besu.evm.worldstate.WrappedEvmAccount;
import java.util.Collection ;
import java.util.Collections ;
import java.util.Comparator ;
import java.util.HashMap ;
import java.util.HashSet ;
import java.util.Iterator ;
@ -39,7 +38,6 @@ import java.util.Optional;
import java.util.Set ;
import java.util.TreeSet ;
import java.util.concurrent.ConcurrentHashMap ;
import java.util.function.Function ;
import org.apache.tuweni.bytes.Bytes ;
import org.apache.tuweni.bytes.Bytes32 ;
@ -186,7 +184,7 @@ public class BonsaiWorldStateUpdater extends AbstractWorldUpdater<BonsaiWorldVie
// mark all updated storage as to be cleared
final Map < Hash , BonsaiValue < UInt256 > > deletedStorageUpdates =
storageToUpdate . computeIfAbsent ( deletedAddress , k - > new HashMap < > ( ) ) ;
storageToUpdate . computeIfAbsent ( deletedAddress , k - > new Concurrent HashMap< > ( ) ) ;
final Iterator < Map . Entry < Hash , BonsaiValue < UInt256 > > > iter =
deletedStorageUpdates . entrySet ( ) . iterator ( ) ;
while ( iter . hasNext ( ) ) {
@ -219,76 +217,83 @@ public class BonsaiWorldStateUpdater extends AbstractWorldUpdater<BonsaiWorldVie
accountValue . setUpdated ( null ) ;
}
for ( final UpdateTrackingAccount < BonsaiAccount > tracked : getUpdatedAccounts ( ) ) {
final Address updatedAddress = tracked . getAddress ( ) ;
BonsaiAccount updatedAccount = tracked . getWrappedAccount ( ) ;
if ( updatedAccount = = null ) {
final BonsaiValue < BonsaiAccount > updatedAccountValue = accountsToUpdate . get ( updatedAddress ) ;
updatedAccount = new BonsaiAccount ( this , tracked ) ;
tracked . setWrappedAccount ( updatedAccount ) ;
if ( updatedAccountValue = = null ) {
accountsToUpdate . put ( updatedAddress , new BonsaiValue < > ( null , updatedAccount ) ) ;
codeToUpdate . put ( updatedAddress , new BonsaiValue < > ( null , updatedAccount . getCode ( ) ) ) ;
} else {
updatedAccountValue . setUpdated ( updatedAccount ) ;
}
} else {
updatedAccount . setBalance ( tracked . getBalance ( ) ) ;
updatedAccount . setNonce ( tracked . getNonce ( ) ) ;
if ( tracked . codeWasUpdated ( ) ) {
updatedAccount . setCode ( tracked . getCode ( ) ) ;
}
if ( tracked . getStorageWasCleared ( ) ) {
updatedAccount . clearStorage ( ) ;
}
tracked . getUpdatedStorage ( ) . forEach ( updatedAccount : : setStorageValue ) ;
}
if ( tracked . codeWasUpdated ( ) ) {
final BonsaiValue < Bytes > pendingCode =
codeToUpdate . computeIfAbsent (
updatedAddress ,
addr - > new BonsaiValue < > ( wrappedWorldView ( ) . getCode ( addr ) . orElse ( null ) , null ) ) ;
pendingCode . setUpdated ( updatedAccount . getCode ( ) ) ;
}
final Map < Hash , BonsaiValue < UInt256 > > pendingStorageUpdates =
storageToUpdate . computeIfAbsent ( updatedAddress , __ - > new HashMap < > ( ) ) ;
if ( tracked . getStorageWasCleared ( ) ) {
storageToClear . add ( updatedAddress ) ;
pendingStorageUpdates . clear ( ) ;
}
final TreeSet < Map . Entry < UInt256 , UInt256 > > entries =
new TreeSet < > (
Comparator . comparing (
( Function < Map . Entry < UInt256 , UInt256 > , UInt256 > ) Map . Entry : : getKey ) ) ;
entries . addAll ( updatedAccount . getUpdatedStorage ( ) . entrySet ( ) ) ;
for ( final Map . Entry < UInt256 , UInt256 > storageUpdate : entries ) {
final UInt256 keyUInt = storageUpdate . getKey ( ) ;
final Hash slotHash = Hash . hash ( keyUInt ) ;
final UInt256 value = storageUpdate . getValue ( ) ;
final BonsaiValue < UInt256 > pendingValue = pendingStorageUpdates . get ( slotHash ) ;
if ( pendingValue = = null ) {
pendingStorageUpdates . put (
slotHash , new BonsaiValue < > ( updatedAccount . getOriginalStorageValue ( keyUInt ) , value ) ) ;
} else {
pendingValue . setUpdated ( value ) ;
}
}
updatedAccount . getUpdatedStorage ( ) . clear ( ) ;
if ( pendingStorageUpdates . isEmpty ( ) ) {
storageToUpdate . remove ( updatedAddress ) ;
}
if ( tracked . getStorageWasCleared ( ) ) {
tracked . setStorageWasCleared ( false ) ; // storage already cleared for this transaction
}
// TODO maybe add address preimage?
}
getUpdatedAccounts ( ) . parallelStream ( )
. forEach (
tracked - > {
final Address updatedAddress = tracked . getAddress ( ) ;
final BonsaiAccount updatedAccount ;
if ( tracked . getWrappedAccount ( ) = = null ) {
final BonsaiValue < BonsaiAccount > updatedAccountValue =
accountsToUpdate . get ( updatedAddress ) ;
updatedAccount = new BonsaiAccount ( this , tracked ) ;
tracked . setWrappedAccount ( updatedAccount ) ;
if ( updatedAccountValue = = null ) {
accountsToUpdate . put ( updatedAddress , new BonsaiValue < > ( null , updatedAccount ) ) ;
codeToUpdate . put (
updatedAddress , new BonsaiValue < > ( null , updatedAccount . getCode ( ) ) ) ;
} else {
updatedAccountValue . setUpdated ( updatedAccount ) ;
}
} else {
updatedAccount = tracked . getWrappedAccount ( ) ;
updatedAccount . setBalance ( tracked . getBalance ( ) ) ;
updatedAccount . setNonce ( tracked . getNonce ( ) ) ;
if ( tracked . codeWasUpdated ( ) ) {
updatedAccount . setCode ( tracked . getCode ( ) ) ;
}
if ( tracked . getStorageWasCleared ( ) ) {
updatedAccount . clearStorage ( ) ;
}
tracked . getUpdatedStorage ( ) . forEach ( updatedAccount : : setStorageValue ) ;
}
if ( tracked . codeWasUpdated ( ) ) {
final BonsaiValue < Bytes > pendingCode =
codeToUpdate . computeIfAbsent (
updatedAddress ,
addr - >
new BonsaiValue < > ( wrappedWorldView ( ) . getCode ( addr ) . orElse ( null ) , null ) ) ;
pendingCode . setUpdated ( updatedAccount . getCode ( ) ) ;
}
final Map < Hash , BonsaiValue < UInt256 > > pendingStorageUpdates =
storageToUpdate . computeIfAbsent ( updatedAddress , __ - > new ConcurrentHashMap < > ( ) ) ;
if ( tracked . getStorageWasCleared ( ) ) {
storageToClear . add ( updatedAddress ) ;
pendingStorageUpdates . clear ( ) ;
}
final TreeSet < Map . Entry < UInt256 , UInt256 > > entries =
new TreeSet < > ( Map . Entry . comparingByKey ( ) ) ;
entries . addAll ( updatedAccount . getUpdatedStorage ( ) . entrySet ( ) ) ;
// parallel stream here may cause database corruption
entries . forEach (
storageUpdate - > {
final UInt256 keyUInt = storageUpdate . getKey ( ) ;
final Hash slotHash = Hash . hash ( keyUInt ) ;
final UInt256 value = storageUpdate . getValue ( ) ;
final BonsaiValue < UInt256 > pendingValue = pendingStorageUpdates . get ( slotHash ) ;
if ( pendingValue = = null ) {
pendingStorageUpdates . put (
slotHash ,
new BonsaiValue < > (
updatedAccount . getOriginalStorageValue ( keyUInt ) , value ) ) ;
} else {
pendingValue . setUpdated ( value ) ;
}
} ) ;
updatedAccount . getUpdatedStorage ( ) . clear ( ) ;
if ( pendingStorageUpdates . isEmpty ( ) ) {
storageToUpdate . remove ( updatedAddress ) ;
}
if ( tracked . getStorageWasCleared ( ) ) {
tracked . setStorageWasCleared ( false ) ; // storage already cleared for this transaction
}
} ) ;
}
@Override
@ -611,7 +616,9 @@ public class BonsaiWorldStateUpdater extends AbstractWorldUpdater<BonsaiWorldVie
wrappedWorldView ( ) . getStorageValueBySlotHash ( address , slotHash ) ;
if ( storageValue . isPresent ( ) ) {
slotValue = new BonsaiValue < > ( storageValue . get ( ) , storageValue . get ( ) ) ;
storageToUpdate . computeIfAbsent ( address , k - > new HashMap < > ( ) ) . put ( slotHash , slotValue ) ;
storageToUpdate
. computeIfAbsent ( address , k - > new ConcurrentHashMap < > ( ) )
. put ( slotHash , slotValue ) ;
}
}
if ( slotValue = = null ) {