@ -1,5 +1,5 @@
/ *
/ *
* Copyright ConsenSys AG .
* Copyright Hyperledger Besu Contributors .
*
*
* Licensed under the Apache License , Version 2 . 0 ( the "License" ) ; you may not use this file except in compliance with
* 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
* the License . You may obtain a copy of the License at
@ -11,10 +11,9 @@
* specific language governing permissions and limitations under the License .
* specific language governing permissions and limitations under the License .
*
*
* SPDX - License - Identifier : Apache - 2 . 0
* SPDX - License - Identifier : Apache - 2 . 0
*
* /
* /
package org.hyperledger.besu.ethereum.trie.bonsai .worldview ;
package org.hyperledger.besu.ethereum.trie.diff based.comm on.worldview.accumulator ;
import org.hyperledger.besu.datatypes.AccountValue ;
import org.hyperledger.besu.datatypes.AccountValue ;
import org.hyperledger.besu.datatypes.Address ;
import org.hyperledger.besu.datatypes.Address ;
@ -23,9 +22,14 @@ import org.hyperledger.besu.datatypes.StorageSlotKey;
import org.hyperledger.besu.datatypes.Wei ;
import org.hyperledger.besu.datatypes.Wei ;
import org.hyperledger.besu.ethereum.rlp.RLP ;
import org.hyperledger.besu.ethereum.rlp.RLP ;
import org.hyperledger.besu.ethereum.trie.MerkleTrieException ;
import org.hyperledger.besu.ethereum.trie.MerkleTrieException ;
import org.hyperledger.besu.ethereum.trie.bonsai.BonsaiAccount ;
import org.hyperledger.besu.ethereum.trie.diffbased.common.DiffBasedAccount ;
import org.hyperledger.besu.ethereum.trie.bonsai.BonsaiValue ;
import org.hyperledger.besu.ethereum.trie.diffbased.common.DiffBasedValue ;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage ;
import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage ;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldState ;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldView ;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.preload.AccountConsumingMap ;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.preload.Consumer ;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.preload.StorageConsumingMap ;
import org.hyperledger.besu.evm.account.Account ;
import org.hyperledger.besu.evm.account.Account ;
import org.hyperledger.besu.evm.account.MutableAccount ;
import org.hyperledger.besu.evm.account.MutableAccount ;
import org.hyperledger.besu.evm.internal.EvmConfiguration ;
import org.hyperledger.besu.evm.internal.EvmConfiguration ;
@ -44,42 +48,40 @@ import java.util.Optional;
import java.util.Set ;
import java.util.Set ;
import java.util.TreeSet ;
import java.util.TreeSet ;
import java.util.concurrent.ConcurrentHashMap ;
import java.util.concurrent.ConcurrentHashMap ;
import java.util.concurrent.ConcurrentMap ;
import java.util.function.Function ;
import java.util.function.Function ;
import javax.annotation.Nonnull ;
import com.google.common.collect.ForwardingMap ;
import org.apache.tuweni.bytes.Bytes ;
import org.apache.tuweni.bytes.Bytes ;
import org.apache.tuweni.bytes.Bytes32 ;
import org.apache.tuweni.bytes.Bytes32 ;
import org.apache.tuweni.units.bigints.UInt256 ;
import org.apache.tuweni.units.bigints.UInt256 ;
import org.slf4j.Logger ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
import org.slf4j.LoggerFactory ;
public class BonsaiWorldStateUpdateAccumulator
@SuppressWarnings ( "unchecked" )
extends AbstractWorldUpdater < BonsaiWorldView , BonsaiAccount >
public abstract class DiffBasedWorldStateUpdateAccumulator < ACCOUNT extends DiffBasedAccount >
implements BonsaiWorldView , TrieLogAccumulator {
extends AbstractWorldUpdater < DiffBasedWorldView , ACCOUNT >
implements DiffBasedWorldView , TrieLogAccumulator {
private static final Logger LOG =
private static final Logger LOG =
LoggerFactory . getLogger ( Bonsai WorldStateUpdateAccumulator. class ) ;
LoggerFactory . getLogger ( DiffBased WorldStateUpdateAccumulator. class ) ;
protected final Consumer < BonsaiValue < BonsaiAccount > > accountPreloader ;
protected final Consumer < DiffBasedValue < ACCOUNT > > accountPreloader ;
protected final Consumer < StorageSlotKey > storagePreloader ;
protected final Consumer < StorageSlotKey > storagePreloader ;
private final AccountConsumingMap < BonsaiValue < BonsaiAccount > > accountsToUpdate ;
private final AccountConsumingMap < DiffBasedValue < ACCOUNT > > accountsToUpdate ;
private final Map < Address , Bonsai Value< Bytes > > codeToUpdate = new ConcurrentHashMap < > ( ) ;
private final Map < Address , DiffBased Value< Bytes > > codeToUpdate = new ConcurrentHashMap < > ( ) ;
private final Set < Address > storageToClear = Collections . synchronizedSet ( new HashSet < > ( ) ) ;
private final Set < Address > storageToClear = Collections . synchronizedSet ( new HashSet < > ( ) ) ;
protected final EvmConfiguration evmConfiguration ;
protected final EvmConfiguration evmConfiguration ;
// storage sub mapped by _hashed_ key. This is because in self_destruct calls we need to
// storage sub mapped by _hashed_ key. This is because in self_destruct calls we need to
// enumerate the old storage and delete it. Those are trie stored by hashed key by spec and the
// enumerate the old storage and delete it. Those are trie stored by hashed key by spec and the
// alternative was to keep a giant pre-image cache of the entire trie.
// alternative was to keep a giant pre-image cache of the entire trie.
private final Map < Address , StorageConsumingMap < StorageSlotKey , Bonsai Value< UInt256 > > >
private final Map < Address , StorageConsumingMap < StorageSlotKey , DiffBased Value< UInt256 > > >
storageToUpdate = new ConcurrentHashMap < > ( ) ;
storageToUpdate = new ConcurrentHashMap < > ( ) ;
private final Map < UInt256 , Hash > storageKeyHashLookup = new ConcurrentHashMap < > ( ) ;
private final Map < UInt256 , Hash > storageKeyHashLookup = new ConcurrentHashMap < > ( ) ;
protected boolean isAccumulatorStateChanged ;
protected boolean isAccumulatorStateChanged ;
public Bonsai WorldStateUpdateAccumulator(
public DiffBased WorldStateUpdateAccumulator(
final Bonsai WorldView world ,
final DiffBased WorldView world ,
final Consumer < BonsaiValue < BonsaiAccount > > accountPreloader ,
final Consumer < DiffBasedValue < ACCOUNT > > accountPreloader ,
final Consumer < StorageSlotKey > storagePreloader ,
final Consumer < StorageSlotKey > storagePreloader ,
final EvmConfiguration evmConfiguration ) {
final EvmConfiguration evmConfiguration ) {
super ( world , evmConfiguration ) ;
super ( world , evmConfiguration ) ;
@ -90,15 +92,7 @@ public class BonsaiWorldStateUpdateAccumulator
this . evmConfiguration = evmConfiguration ;
this . evmConfiguration = evmConfiguration ;
}
}
public BonsaiWorldStateUpdateAccumulator copy ( ) {
protected void cloneFromUpdater ( final DiffBasedWorldStateUpdateAccumulator < ACCOUNT > source ) {
final BonsaiWorldStateUpdateAccumulator copy =
new BonsaiWorldStateUpdateAccumulator (
wrappedWorldView ( ) , accountPreloader , storagePreloader , evmConfiguration ) ;
copy . cloneFromUpdater ( this ) ;
return copy ;
}
void cloneFromUpdater ( final BonsaiWorldStateUpdateAccumulator source ) {
accountsToUpdate . putAll ( source . getAccountsToUpdate ( ) ) ;
accountsToUpdate . putAll ( source . getAccountsToUpdate ( ) ) ;
codeToUpdate . putAll ( source . codeToUpdate ) ;
codeToUpdate . putAll ( source . codeToUpdate ) ;
storageToClear . addAll ( source . storageToClear ) ;
storageToClear . addAll ( source . storageToClear ) ;
@ -108,14 +102,25 @@ public class BonsaiWorldStateUpdateAccumulator
this . isAccumulatorStateChanged = true ;
this . isAccumulatorStateChanged = true ;
}
}
protected Consumer < DiffBasedValue < ACCOUNT > > getAccountPreloader ( ) {
return accountPreloader ;
}
protected Consumer < StorageSlotKey > getStoragePreloader ( ) {
return storagePreloader ;
}
protected EvmConfiguration getEvmConfiguration ( ) {
return evmConfiguration ;
}
@Override
@Override
public Account get ( final Address address ) {
public Account get ( final Address address ) {
return super . get ( address ) ;
return super . get ( address ) ;
}
}
@Override
@Override
protected UpdateTrackingAccount < BonsaiAccount > track (
protected UpdateTrackingAccount < ACCOUNT > track ( final UpdateTrackingAccount < ACCOUNT > account ) {
final UpdateTrackingAccount < BonsaiAccount > account ) {
return super . track ( account ) ;
return super . track ( account ) ;
}
}
@ -126,21 +131,21 @@ public class BonsaiWorldStateUpdateAccumulator
@Override
@Override
public MutableAccount createAccount ( final Address address , final long nonce , final Wei balance ) {
public MutableAccount createAccount ( final Address address , final long nonce , final Wei balance ) {
BonsaiValue < BonsaiAccount > bonsai Value = accountsToUpdate . get ( address ) ;
DiffBasedValue < ACCOUNT > diffBased Value = accountsToUpdate . get ( address ) ;
if ( bonsai Value = = null ) {
if ( diffBased Value = = null ) {
bonsaiValue = new Bonsai Value< > ( null , null ) ;
diffBasedValue = new DiffBased Value< > ( null , null ) ;
accountsToUpdate . put ( address , bonsai Value) ;
accountsToUpdate . put ( address , diffBased Value) ;
} else if ( bonsai Value. getUpdated ( ) ! = null ) {
} else if ( diffBased Value. getUpdated ( ) ! = null ) {
if ( bonsai Value. getUpdated ( ) . isEmpty ( ) ) {
if ( diffBased Value. getUpdated ( ) . isEmpty ( ) ) {
return track ( new UpdateTrackingAccount < > ( bonsai Value. getUpdated ( ) ) ) ;
return track ( new UpdateTrackingAccount < > ( diffBased Value. getUpdated ( ) ) ) ;
} else {
} else {
throw new IllegalStateException ( "Cannot create an account when one already exists" ) ;
throw new IllegalStateException ( "Cannot create an account when one already exists" ) ;
}
}
}
}
final BonsaiAccount newAccount =
final ACCOUNT newAccount =
new Bonsai Account(
create Account(
this ,
this ,
address ,
address ,
hashAndSaveAccountPreImage ( address ) ,
hashAndSaveAccountPreImage ( address ) ,
@ -149,17 +154,17 @@ public class BonsaiWorldStateUpdateAccumulator
Hash . EMPTY_TRIE_HASH ,
Hash . EMPTY_TRIE_HASH ,
Hash . EMPTY ,
Hash . EMPTY ,
true ) ;
true ) ;
bonsai Value. setUpdated ( newAccount ) ;
diffBased Value. setUpdated ( newAccount ) ;
return track ( new UpdateTrackingAccount < > ( newAccount ) ) ;
return track ( new UpdateTrackingAccount < > ( newAccount ) ) ;
}
}
@Override
@Override
public Map < Address , BonsaiValue < BonsaiAccount > > getAccountsToUpdate ( ) {
public Map < Address , DiffBasedValue < ACCOUNT > > getAccountsToUpdate ( ) {
return accountsToUpdate ;
return accountsToUpdate ;
}
}
@Override
@Override
public Map < Address , Bonsai Value< Bytes > > getCodeToUpdate ( ) {
public Map < Address , DiffBased Value< Bytes > > getCodeToUpdate ( ) {
return codeToUpdate ;
return codeToUpdate ;
}
}
@ -168,40 +173,41 @@ public class BonsaiWorldStateUpdateAccumulator
}
}
@Override
@Override
public Map < Address , StorageConsumingMap < StorageSlotKey , Bonsai Value< UInt256 > > >
public Map < Address , StorageConsumingMap < StorageSlotKey , DiffBased Value< UInt256 > > >
getStorageToUpdate ( ) {
getStorageToUpdate ( ) {
return storageToUpdate ;
return storageToUpdate ;
}
}
@Override
@Override
protected BonsaiAccount getForMutation ( final Address address ) {
protected ACCOUNT getForMutation ( final Address address ) {
return loadAccount ( address , Bonsai Value: : getUpdated ) ;
return loadAccount ( address , DiffBased Value: : getUpdated ) ;
}
}
protected BonsaiAccount loadAccount (
protected ACCOUNT loadAccount (
final Address address ,
final Address address , final Function < DiffBasedValue < ACCOUNT > , ACCOUNT > accountFunction ) {
final Function < BonsaiValue < BonsaiAccount > , BonsaiAccount > bonsaiAccountFunction ) {
try {
try {
final BonsaiValue < BonsaiAccount > bonsai Value = accountsToUpdate . get ( address ) ;
final DiffBasedValue < ACCOUNT > diffBased Value = accountsToUpdate . get ( address ) ;
if ( bonsai Value = = null ) {
if ( diffBased Value = = null ) {
final Account account ;
final Account account ;
if ( wrappedWorldView ( )
if ( wrappedWorldView ( ) instanceof DiffBasedWorldStateUpdateAccumulator ) {
instanceof BonsaiWorldStateUpdateAccumulator bonsaiWorldStateUpdateAccumulator ) {
final DiffBasedWorldStateUpdateAccumulator < ACCOUNT > worldStateUpdateAccumulator =
account = bonsaiWorldStateUpdateAccumulator . loadAccount ( address , bonsaiAccountFunction ) ;
( DiffBasedWorldStateUpdateAccumulator < ACCOUNT > ) wrappedWorldView ( ) ;
account = worldStateUpdateAccumulator . loadAccount ( address , accountFunction ) ;
} else {
} else {
account = wrappedWorldView ( ) . get ( address ) ;
account = wrappedWorldView ( ) . get ( address ) ;
}
}
if ( account instanceof BonsaiAccount bonsaiAccount ) {
if ( account instanceof DiffBasedAccount diffBasedAccount ) {
BonsaiAccount mutableAccount = new BonsaiAccount ( bonsaiAccount , this , true ) ;
ACCOUNT mutableAccount = copyAccount ( ( ACCOUNT ) diffBasedAccount , this , true ) ;
accountsToUpdate . put ( address , new BonsaiValue < > ( bonsaiAccount , mutableAccount ) ) ;
accountsToUpdate . put (
address , new DiffBasedValue < > ( ( ACCOUNT ) diffBasedAccount , mutableAccount ) ) ;
return mutableAccount ;
return mutableAccount ;
} else {
} else {
// add the empty read in accountsToUpdate
// add the empty read in accountsToUpdate
accountsToUpdate . put ( address , new Bonsai Value< > ( null , null ) ) ;
accountsToUpdate . put ( address , new DiffBased Value< > ( null , null ) ) ;
return null ;
return null ;
}
}
} else {
} else {
return bons aiA ccountFunction. apply ( bonsai Value) ;
return accountFunction . apply ( diffBased Value) ;
}
}
} catch ( MerkleTrieException e ) {
} catch ( MerkleTrieException e ) {
// need to throw to trigger the heal
// need to throw to trigger the heal
@ -229,12 +235,12 @@ public class BonsaiWorldStateUpdateAccumulator
public void commit ( ) {
public void commit ( ) {
this . isAccumulatorStateChanged = true ;
this . isAccumulatorStateChanged = true ;
for ( final Address deletedAddress : getDeletedAccounts ( ) ) {
for ( final Address deletedAddress : getDeletedAccounts ( ) ) {
final BonsaiValue < BonsaiAccount > accountValue =
final DiffBasedValue < ACCOUNT > accountValue =
accountsToUpdate . computeIfAbsent (
accountsToUpdate . computeIfAbsent (
deletedAddress ,
deletedAddress ,
__ - > loadAccountFromParent ( deletedAddress , new Bonsai Value< > ( null , null , true ) ) ) ;
__ - > loadAccountFromParent ( deletedAddress , new DiffBased Value< > ( null , null , true ) ) ) ;
storageToClear . add ( deletedAddress ) ;
storageToClear . add ( deletedAddress ) ;
final Bonsai Value< Bytes > codeValue = codeToUpdate . get ( deletedAddress ) ;
final DiffBased Value< Bytes > codeValue = codeToUpdate . get ( deletedAddress ) ;
if ( codeValue ! = null ) {
if ( codeValue ! = null ) {
codeValue . setUpdated ( null ) . setCleared ( ) ;
codeValue . setUpdated ( null ) . setCleared ( ) ;
} else {
} else {
@ -242,26 +248,27 @@ public class BonsaiWorldStateUpdateAccumulator
. getCode (
. getCode (
deletedAddress ,
deletedAddress ,
Optional . ofNullable ( accountValue )
Optional . ofNullable ( accountValue )
. map ( Bonsai Value: : getPrior )
. map ( DiffBased Value: : getPrior )
. map ( Bonsai Account: : getCodeHash )
. map ( DiffBased Account: : getCodeHash )
. orElse ( Hash . EMPTY ) )
. orElse ( Hash . EMPTY ) )
. ifPresent (
. ifPresent (
deletedCode - >
deletedCode - >
codeToUpdate . put ( deletedAddress , new BonsaiValue < > ( deletedCode , null , true ) ) ) ;
codeToUpdate . put (
deletedAddress , new DiffBasedValue < > ( deletedCode , null , true ) ) ) ;
}
}
// mark all updated storage as to be cleared
// mark all updated storage as to be cleared
final Map < StorageSlotKey , Bonsai Value< UInt256 > > deletedStorageUpdates =
final Map < StorageSlotKey , DiffBased Value< UInt256 > > deletedStorageUpdates =
storageToUpdate . computeIfAbsent (
storageToUpdate . computeIfAbsent (
deletedAddress ,
deletedAddress ,
k - >
k - >
new StorageConsumingMap < > (
new StorageConsumingMap < > (
deletedAddress , new ConcurrentHashMap < > ( ) , storagePreloader ) ) ;
deletedAddress , new ConcurrentHashMap < > ( ) , storagePreloader ) ) ;
final Iterator < Map . Entry < StorageSlotKey , Bonsai Value< UInt256 > > > iter =
final Iterator < Map . Entry < StorageSlotKey , DiffBased Value< UInt256 > > > iter =
deletedStorageUpdates . entrySet ( ) . iterator ( ) ;
deletedStorageUpdates . entrySet ( ) . iterator ( ) ;
while ( iter . hasNext ( ) ) {
while ( iter . hasNext ( ) ) {
final Map . Entry < StorageSlotKey , Bonsai Value< UInt256 > > updateEntry = iter . next ( ) ;
final Map . Entry < StorageSlotKey , DiffBased Value< UInt256 > > updateEntry = iter . next ( ) ;
final Bonsai Value< UInt256 > updatedSlot = updateEntry . getValue ( ) ;
final DiffBased Value< UInt256 > updatedSlot = updateEntry . getValue ( ) ;
if ( updatedSlot . getPrior ( ) = = null | | updatedSlot . getPrior ( ) . isZero ( ) ) {
if ( updatedSlot . getPrior ( ) = = null | | updatedSlot . getPrior ( ) . isZero ( ) ) {
iter . remove ( ) ;
iter . remove ( ) ;
} else {
} else {
@ -269,7 +276,7 @@ public class BonsaiWorldStateUpdateAccumulator
}
}
}
}
final BonsaiAccount originalValue = accountValue . getPrior ( ) ;
final ACCOUNT originalValue = accountValue . getPrior ( ) ;
if ( originalValue ! = null ) {
if ( originalValue ! = null ) {
// Enumerate and delete addresses not updated
// Enumerate and delete addresses not updated
wrappedWorldView ( )
wrappedWorldView ( )
@ -280,7 +287,8 @@ public class BonsaiWorldStateUpdateAccumulator
new StorageSlotKey ( Hash . wrap ( keyHash ) , Optional . empty ( ) ) ;
new StorageSlotKey ( Hash . wrap ( keyHash ) , Optional . empty ( ) ) ;
if ( ! deletedStorageUpdates . containsKey ( storageSlotKey ) ) {
if ( ! deletedStorageUpdates . containsKey ( storageSlotKey ) ) {
final UInt256 value = UInt256 . fromBytes ( RLP . decodeOne ( entryValue ) ) ;
final UInt256 value = UInt256 . fromBytes ( RLP . decodeOne ( entryValue ) ) ;
deletedStorageUpdates . put ( storageSlotKey , new BonsaiValue < > ( value , null , true ) ) ;
deletedStorageUpdates . put (
storageSlotKey , new DiffBasedValue < > ( value , null , true ) ) ;
}
}
} ) ;
} ) ;
}
}
@ -294,11 +302,11 @@ public class BonsaiWorldStateUpdateAccumulator
. forEach (
. forEach (
tracked - > {
tracked - > {
final Address updatedAddress = tracked . getAddress ( ) ;
final Address updatedAddress = tracked . getAddress ( ) ;
final BonsaiAccount updatedAccount ;
final ACCOUNT updatedAccount ;
final BonsaiValue < BonsaiAccount > updatedAccountValue =
final DiffBasedValue < ACCOUNT > updatedAccountValue =
accountsToUpdate . get ( updatedAddress ) ;
accountsToUpdate . get ( updatedAddress ) ;
final Map < StorageSlotKey , Bonsai Value< UInt256 > > pendingStorageUpdates =
final Map < StorageSlotKey , DiffBased Value< UInt256 > > pendingStorageUpdates =
storageToUpdate . computeIfAbsent (
storageToUpdate . computeIfAbsent (
updatedAddress ,
updatedAddress ,
k - >
k - >
@ -311,12 +319,12 @@ public class BonsaiWorldStateUpdateAccumulator
}
}
if ( tracked . getWrappedAccount ( ) = = null ) {
if ( tracked . getWrappedAccount ( ) = = null ) {
updatedAccount = new Bonsai Account( this , tracked ) ;
updatedAccount = create Account( this , tracked ) ;
tracked . setWrappedAccount ( updatedAccount ) ;
tracked . setWrappedAccount ( updatedAccount ) ;
if ( updatedAccountValue = = null ) {
if ( updatedAccountValue = = null ) {
accountsToUpdate . put ( updatedAddress , new Bonsai Value< > ( null , updatedAccount ) ) ;
accountsToUpdate . put ( updatedAddress , new DiffBased Value< > ( null , updatedAccount ) ) ;
codeToUpdate . put (
codeToUpdate . put (
updatedAddress , new Bonsai Value< > ( null , updatedAccount . getCode ( ) ) ) ;
updatedAddress , new DiffBased Value< > ( null , updatedAccount . getCode ( ) ) ) ;
} else {
} else {
updatedAccountValue . setUpdated ( updatedAccount ) ;
updatedAccountValue . setUpdated ( updatedAccount ) ;
}
}
@ -334,17 +342,17 @@ public class BonsaiWorldStateUpdateAccumulator
}
}
if ( tracked . codeWasUpdated ( ) ) {
if ( tracked . codeWasUpdated ( ) ) {
final Bonsai Value< Bytes > pendingCode =
final DiffBased Value< Bytes > pendingCode =
codeToUpdate . computeIfAbsent (
codeToUpdate . computeIfAbsent (
updatedAddress ,
updatedAddress ,
addr - >
addr - >
new Bonsai Value< > (
new DiffBased Value< > (
wrappedWorldView ( )
wrappedWorldView ( )
. getCode (
. getCode (
addr ,
addr ,
Optional . ofNullable ( updatedAccountValue )
Optional . ofNullable ( updatedAccountValue )
. map ( Bonsai Value: : getPrior )
. map ( DiffBased Value: : getPrior )
. map ( Bonsai Account: : getCodeHash )
. map ( DiffBased Account: : getCodeHash )
. orElse ( Hash . EMPTY ) )
. orElse ( Hash . EMPTY ) )
. orElse ( null ) ,
. orElse ( null ) ,
null ) ) ;
null ) ) ;
@ -368,12 +376,11 @@ public class BonsaiWorldStateUpdateAccumulator
final StorageSlotKey slotKey =
final StorageSlotKey slotKey =
new StorageSlotKey ( hashAndSaveSlotPreImage ( keyUInt ) , Optional . of ( keyUInt ) ) ;
new StorageSlotKey ( hashAndSaveSlotPreImage ( keyUInt ) , Optional . of ( keyUInt ) ) ;
final UInt256 value = storageUpdate . getValue ( ) ;
final UInt256 value = storageUpdate . getValue ( ) ;
final BonsaiValue < UInt256 > pendingValue = pendingStorageUpdates . get ( slotKey ) ;
final DiffBasedValue < UInt256 > pendingValue = pendingStorageUpdates . get ( slotKey ) ;
if ( pendingValue = = null ) {
if ( pendingValue = = null ) {
pendingStorageUpdates . put (
pendingStorageUpdates . put (
slotKey ,
slotKey ,
new Bonsai Value< > (
new DiffBased Value< > (
updatedAccount . getOriginalStorageValue ( keyUInt ) , value ) ) ;
updatedAccount . getOriginalStorageValue ( keyUInt ) , value ) ) ;
} else {
} else {
pendingValue . setUpdated ( value ) ;
pendingValue . setUpdated ( value ) ;
@ -394,7 +401,7 @@ public class BonsaiWorldStateUpdateAccumulator
@Override
@Override
public Optional < Bytes > getCode ( final Address address , final Hash codeHash ) {
public Optional < Bytes > getCode ( final Address address , final Hash codeHash ) {
final Bonsai Value< Bytes > localCode = codeToUpdate . get ( address ) ;
final DiffBased Value< Bytes > localCode = codeToUpdate . get ( address ) ;
if ( localCode = = null ) {
if ( localCode = = null ) {
final Optional < Bytes > code = wrappedWorldView ( ) . getCode ( address , codeHash ) ;
final Optional < Bytes > code = wrappedWorldView ( ) . getCode ( address , codeHash ) ;
if ( code . isEmpty ( ) & & ! codeHash . equals ( Hash . EMPTY ) ) {
if ( code . isEmpty ( ) & & ! codeHash . equals ( Hash . EMPTY ) ) {
@ -417,31 +424,26 @@ public class BonsaiWorldStateUpdateAccumulator
@Override
@Override
public Optional < UInt256 > getStorageValueByStorageSlotKey (
public Optional < UInt256 > getStorageValueByStorageSlotKey (
final Address address , final StorageSlotKey storageSlotKey ) {
final Address address , final StorageSlotKey storageSlotKey ) {
final Map < StorageSlotKey , Bonsai Value< UInt256 > > localAccountStorage =
final Map < StorageSlotKey , DiffBased Value< UInt256 > > localAccountStorage =
storageToUpdate . get ( address ) ;
storageToUpdate . get ( address ) ;
if ( localAccountStorage ! = null ) {
if ( localAccountStorage ! = null ) {
final Bonsai Value< UInt256 > value = localAccountStorage . get ( storageSlotKey ) ;
final DiffBased Value< UInt256 > value = localAccountStorage . get ( storageSlotKey ) ;
if ( value ! = null ) {
if ( value ! = null ) {
return Optional . ofNullable ( value . getUpdated ( ) ) ;
return Optional . ofNullable ( value . getUpdated ( ) ) ;
}
}
}
}
try {
try {
final Optional < UInt256 > valueUInt =
final Optional < UInt256 > valueUInt =
( wrappedWorldView ( ) instanceof BonsaiWorldState bonsaiWorldState )
( wrappedWorldView ( ) instanceof DiffBasedWorldState worldState )
? bonsaiWorldState . getStorageValueByStorageSlotKey (
? worldState . getStorageValueByStorageSlotKey ( address , storageSlotKey )
( ) - >
Optional . ofNullable ( loadAccount ( address , BonsaiValue : : getPrior ) )
. map ( BonsaiAccount : : getStorageRoot ) ,
address ,
storageSlotKey )
: wrappedWorldView ( ) . getStorageValueByStorageSlotKey ( address , storageSlotKey ) ;
: wrappedWorldView ( ) . getStorageValueByStorageSlotKey ( address , storageSlotKey ) ;
storageToUpdate
storageToUpdate
. computeIfAbsent (
. computeIfAbsent (
address ,
address ,
key - >
key - >
new StorageConsumingMap < > ( address , new ConcurrentHashMap < > ( ) , storagePreloader ) )
new StorageConsumingMap < > ( address , new ConcurrentHashMap < > ( ) , storagePreloader ) )
. put ( storageSlotKey , new BonsaiValue < > ( valueUInt . orElse ( null ) , valueUInt . orElse ( null ) ) ) ;
. put (
storageSlotKey , new DiffBasedValue < > ( valueUInt . orElse ( null ) , valueUInt . orElse ( null ) ) ) ;
return valueUInt ;
return valueUInt ;
} catch ( MerkleTrieException e ) {
} catch ( MerkleTrieException e ) {
// need to throw to trigger the heal
// need to throw to trigger the heal
@ -455,10 +457,10 @@ public class BonsaiWorldStateUpdateAccumulator
// TODO maybe log the read into the trie layer?
// TODO maybe log the read into the trie layer?
StorageSlotKey storageSlotKey =
StorageSlotKey storageSlotKey =
new StorageSlotKey ( hashAndSaveSlotPreImage ( storageKey ) , Optional . of ( storageKey ) ) ;
new StorageSlotKey ( hashAndSaveSlotPreImage ( storageKey ) , Optional . of ( storageKey ) ) ;
final Map < StorageSlotKey , Bonsai Value< UInt256 > > localAccountStorage =
final Map < StorageSlotKey , DiffBased Value< UInt256 > > localAccountStorage =
storageToUpdate . get ( address ) ;
storageToUpdate . get ( address ) ;
if ( localAccountStorage ! = null ) {
if ( localAccountStorage ! = null ) {
final Bonsai Value< UInt256 > value = localAccountStorage . get ( storageSlotKey ) ;
final DiffBased Value< UInt256 > value = localAccountStorage . get ( storageSlotKey ) ;
if ( value ! = null ) {
if ( value ! = null ) {
if ( value . isLastStepCleared ( ) ) {
if ( value . isLastStepCleared ( ) ) {
return UInt256 . ZERO ;
return UInt256 . ZERO ;
@ -482,11 +484,11 @@ public class BonsaiWorldStateUpdateAccumulator
@Override
@Override
public Map < Bytes32 , Bytes > getAllAccountStorage ( final Address address , final Hash rootHash ) {
public Map < Bytes32 , Bytes > getAllAccountStorage ( final Address address , final Hash rootHash ) {
final Map < Bytes32 , Bytes > results = wrappedWorldView ( ) . getAllAccountStorage ( address , rootHash ) ;
final Map < Bytes32 , Bytes > results = wrappedWorldView ( ) . getAllAccountStorage ( address , rootHash ) ;
final StorageConsumingMap < StorageSlotKey , Bonsai Value< UInt256 > > bonsai ValueStorage =
final StorageConsumingMap < StorageSlotKey , DiffBased Value< UInt256 > > diffBased ValueStorage =
storageToUpdate . get ( address ) ;
storageToUpdate . get ( address ) ;
if ( bonsai ValueStorage ! = null ) {
if ( diffBased ValueStorage ! = null ) {
// hash the key to match the implied storage interface of hashed slotKey
// hash the key to match the implied storage interface of hashed slotKey
bonsai ValueStorage. forEach (
diffBased ValueStorage. forEach (
( key , value ) - > results . put ( key . getSlotHash ( ) , value . getUpdated ( ) ) ) ;
( key , value ) - > results . put ( key . getSlotHash ( ) , value . getUpdated ( ) ) ) ;
}
}
return results ;
return results ;
@ -498,7 +500,7 @@ public class BonsaiWorldStateUpdateAccumulator
}
}
@Override
@Override
public Bonsai WorldStateKeyValueStorage getWorldStateStorage ( ) {
public DiffBased WorldStateKeyValueStorage getWorldStateStorage ( ) {
return wrappedWorldView ( ) . getWorldStateStorage ( ) ;
return wrappedWorldView ( ) . getWorldStateStorage ( ) ;
}
}
@ -550,7 +552,7 @@ public class BonsaiWorldStateUpdateAccumulator
// non-change, a cached read.
// non-change, a cached read.
return ;
return ;
}
}
BonsaiValue < BonsaiAccount > accountValue = accountsToUpdate . get ( address ) ;
DiffBasedValue < ACCOUNT > accountValue = accountsToUpdate . get ( address ) ;
if ( accountValue = = null ) {
if ( accountValue = = null ) {
accountValue = loadAccountFromParent ( address , accountValue ) ;
accountValue = loadAccountFromParent ( address , accountValue ) ;
}
}
@ -558,7 +560,7 @@ public class BonsaiWorldStateUpdateAccumulator
if ( expectedValue = = null & & replacementValue ! = null ) {
if ( expectedValue = = null & & replacementValue ! = null ) {
accountsToUpdate . put (
accountsToUpdate . put (
address ,
address ,
new Bonsai Value< > ( null , new Bonsai Account( this , address , replacementValue , true ) ) ) ;
new DiffBased Value< > ( null , create Account( this , address , replacementValue , true ) ) ) ;
} else {
} else {
throw new IllegalStateException (
throw new IllegalStateException (
String . format (
String . format (
@ -572,7 +574,7 @@ public class BonsaiWorldStateUpdateAccumulator
"Expected to create account, but the account exists. Address=%s" , address ) ) ;
"Expected to create account, but the account exists. Address=%s" , address ) ) ;
}
}
} else {
} else {
BonsaiAccount . assertCloseEnoughForDiffing (
assertCloseEnoughForDiffing (
accountValue . getUpdated ( ) ,
accountValue . getUpdated ( ) ,
expectedValue ,
expectedValue ,
"Address=" + address + " Prior Value in Rolling Change" ) ;
"Address=" + address + " Prior Value in Rolling Change" ) ;
@ -586,19 +588,18 @@ public class BonsaiWorldStateUpdateAccumulator
accountValue . setUpdated ( null ) ;
accountValue . setUpdated ( null ) ;
}
}
} else {
} else {
accountValue . setUpdated (
accountValue . setUpdated ( createAccount ( wrappedWorldView ( ) , address , replacementValue , true ) ) ;
new BonsaiAccount ( wrappedWorldView ( ) , address , replacementValue , true ) ) ;
}
}
}
}
}
}
private BonsaiValue < BonsaiAccount > loadAccountFromParent (
private DiffBasedValue < ACCOUNT > loadAccountFromParent (
final Address address , final BonsaiValue < BonsaiAccount > defaultValue ) {
final Address address , final DiffBasedValue < ACCOUNT > defaultValue ) {
try {
try {
final Account parentAccount = wrappedWorldView ( ) . get ( address ) ;
final Account parentAccount = wrappedWorldView ( ) . get ( address ) ;
if ( parentAccount instanceof Bonsai Account account ) {
if ( parentAccount instanceof DiffBased Account account ) {
final BonsaiValue < BonsaiAccount > loadedAccountValue =
final DiffBasedValue < ACCOUNT > loadedAccountValue =
new Bonsai Value< > ( new BonsaiAccount ( account ) , account ) ;
new DiffBased Value< > ( copyAccount ( ( ACCOUNT ) account ) , ( ( ACCOUNT ) account ) ) ;
accountsToUpdate . put ( address , loadedAccountValue ) ;
accountsToUpdate . put ( address , loadedAccountValue ) ;
return loadedAccountValue ;
return loadedAccountValue ;
} else {
} else {
@ -617,7 +618,7 @@ public class BonsaiWorldStateUpdateAccumulator
// non-change, a cached read.
// non-change, a cached read.
return ;
return ;
}
}
Bonsai Value< Bytes > codeValue = codeToUpdate . get ( address ) ;
DiffBased Value< Bytes > codeValue = codeToUpdate . get ( address ) ;
if ( codeValue = = null ) {
if ( codeValue = = null ) {
final Bytes storedCode =
final Bytes storedCode =
wrappedWorldView ( )
wrappedWorldView ( )
@ -625,14 +626,14 @@ public class BonsaiWorldStateUpdateAccumulator
address , Optional . ofNullable ( expectedCode ) . map ( Hash : : hash ) . orElse ( Hash . EMPTY ) )
address , Optional . ofNullable ( expectedCode ) . map ( Hash : : hash ) . orElse ( Hash . EMPTY ) )
. orElse ( Bytes . EMPTY ) ;
. orElse ( Bytes . EMPTY ) ;
if ( ! storedCode . isEmpty ( ) ) {
if ( ! storedCode . isEmpty ( ) ) {
codeValue = new Bonsai Value< > ( storedCode , storedCode ) ;
codeValue = new DiffBased Value< > ( storedCode , storedCode ) ;
codeToUpdate . put ( address , codeValue ) ;
codeToUpdate . put ( address , codeValue ) ;
}
}
}
}
if ( codeValue = = null ) {
if ( codeValue = = null ) {
if ( ( expectedCode = = null | | expectedCode . isEmpty ( ) ) & & replacementCode ! = null ) {
if ( ( expectedCode = = null | | expectedCode . isEmpty ( ) ) & & replacementCode ! = null ) {
codeToUpdate . put ( address , new Bonsai Value< > ( null , replacementCode ) ) ;
codeToUpdate . put ( address , new DiffBased Value< > ( null , replacementCode ) ) ;
} else {
} else {
throw new IllegalStateException (
throw new IllegalStateException (
String . format (
String . format (
@ -660,10 +661,10 @@ public class BonsaiWorldStateUpdateAccumulator
}
}
}
}
private Map < StorageSlotKey , Bonsai Value< UInt256 > > maybeCreateStorageMap (
private Map < StorageSlotKey , DiffBased Value< UInt256 > > maybeCreateStorageMap (
final Map < StorageSlotKey , Bonsai Value< UInt256 > > storageMap , final Address address ) {
final Map < StorageSlotKey , DiffBased Value< UInt256 > > storageMap , final Address address ) {
if ( storageMap = = null ) {
if ( storageMap = = null ) {
final StorageConsumingMap < StorageSlotKey , Bonsai Value< UInt256 > > newMap =
final StorageConsumingMap < StorageSlotKey , DiffBased Value< UInt256 > > newMap =
new StorageConsumingMap < > ( address , new ConcurrentHashMap < > ( ) , storagePreloader ) ;
new StorageConsumingMap < > ( address , new ConcurrentHashMap < > ( ) , storagePreloader ) ;
storageToUpdate . put ( address , newMap ) ;
storageToUpdate . put ( address , newMap ) ;
return newMap ;
return newMap ;
@ -685,13 +686,13 @@ public class BonsaiWorldStateUpdateAccumulator
// corner case on deletes, non-change
// corner case on deletes, non-change
return ;
return ;
}
}
final Map < StorageSlotKey , Bonsai Value< UInt256 > > storageMap = storageToUpdate . get ( address ) ;
final Map < StorageSlotKey , DiffBased Value< UInt256 > > storageMap = storageToUpdate . get ( address ) ;
Bonsai Value< UInt256 > slotValue = storageMap = = null ? null : storageMap . get ( storageSlotKey ) ;
DiffBased Value< UInt256 > slotValue = storageMap = = null ? null : storageMap . get ( storageSlotKey ) ;
if ( slotValue = = null ) {
if ( slotValue = = null ) {
final Optional < UInt256 > storageValue =
final Optional < UInt256 > storageValue =
wrappedWorldView ( ) . getStorageValueByStorageSlotKey ( address , storageSlotKey ) ;
wrappedWorldView ( ) . getStorageValueByStorageSlotKey ( address , storageSlotKey ) ;
if ( storageValue . isPresent ( ) ) {
if ( storageValue . isPresent ( ) ) {
slotValue = new Bonsai Value< > ( storageValue . get ( ) , storageValue . get ( ) ) ;
slotValue = new DiffBased Value< > ( storageValue . get ( ) , storageValue . get ( ) ) ;
storageToUpdate
storageToUpdate
. computeIfAbsent (
. computeIfAbsent (
address ,
address ,
@ -703,7 +704,7 @@ public class BonsaiWorldStateUpdateAccumulator
if ( slotValue = = null ) {
if ( slotValue = = null ) {
if ( ( expectedValue = = null | | expectedValue . isZero ( ) ) & & replacementValue ! = null ) {
if ( ( expectedValue = = null | | expectedValue . isZero ( ) ) & & replacementValue ! = null ) {
maybeCreateStorageMap ( storageMap , address )
maybeCreateStorageMap ( storageMap , address )
. put ( storageSlotKey , new Bonsai Value< > ( null , replacementValue ) ) ;
. put ( storageSlotKey , new DiffBased Value< > ( null , replacementValue ) ) ;
} else {
} else {
throw new IllegalStateException (
throw new IllegalStateException (
String . format (
String . format (
@ -730,7 +731,7 @@ public class BonsaiWorldStateUpdateAccumulator
existingSlotValue = = null ? "null" : existingSlotValue . toShortHexString ( ) ) ) ;
existingSlotValue = = null ? "null" : existingSlotValue . toShortHexString ( ) ) ) ;
}
}
if ( replacementValue = = null & & slotValue . getPrior ( ) = = null ) {
if ( replacementValue = = null & & slotValue . getPrior ( ) = = null ) {
final Map < StorageSlotKey , Bonsai Value< UInt256 > > thisStorageUpdate =
final Map < StorageSlotKey , DiffBased Value< UInt256 > > thisStorageUpdate =
maybeCreateStorageMap ( storageMap , address ) ;
maybeCreateStorageMap ( storageMap , address ) ;
thisStorageUpdate . remove ( storageSlotKey ) ;
thisStorageUpdate . remove ( storageSlotKey ) ;
if ( thisStorageUpdate . isEmpty ( ) ) {
if ( thisStorageUpdate . isEmpty ( ) ) {
@ -769,67 +770,6 @@ public class BonsaiWorldStateUpdateAccumulator
storageKeyHashLookup . clear ( ) ;
storageKeyHashLookup . clear ( ) ;
}
}
public static class AccountConsumingMap < T > extends ForwardingMap < Address , T > {
private final ConcurrentMap < Address , T > accounts ;
private final Consumer < T > consumer ;
public AccountConsumingMap (
final ConcurrentMap < Address , T > accounts , final Consumer < T > consumer ) {
this . accounts = accounts ;
this . consumer = consumer ;
}
@Override
public T put ( @Nonnull final Address address , @Nonnull final T value ) {
consumer . process ( address , value ) ;
return accounts . put ( address , value ) ;
}
public Consumer < T > getConsumer ( ) {
return consumer ;
}
@Override
protected Map < Address , T > delegate ( ) {
return accounts ;
}
}
public static class StorageConsumingMap < K , T > extends ForwardingMap < K , T > {
private final Address address ;
private final ConcurrentMap < K , T > storages ;
private final Consumer < K > consumer ;
public StorageConsumingMap (
final Address address , final ConcurrentMap < K , T > storages , final Consumer < K > consumer ) {
this . address = address ;
this . storages = storages ;
this . consumer = consumer ;
}
@Override
public T put ( @Nonnull final K slotKey , @Nonnull final T value ) {
consumer . process ( address , slotKey ) ;
return storages . put ( slotKey , value ) ;
}
public Consumer < K > getConsumer ( ) {
return consumer ;
}
@Override
protected Map < K , T > delegate ( ) {
return storages ;
}
}
public interface Consumer < T > {
void process ( final Address address , T value ) ;
}
protected Hash hashAndSaveAccountPreImage ( final Address address ) {
protected Hash hashAndSaveAccountPreImage ( final Address address ) {
// no need to save account preimage by default
// no need to save account preimage by default
return Hash . hash ( address ) ;
return Hash . hash ( address ) ;
@ -843,4 +783,33 @@ public class BonsaiWorldStateUpdateAccumulator
}
}
return hash ;
return hash ;
}
}
public abstract DiffBasedWorldStateUpdateAccumulator < ACCOUNT > copy ( ) ;
protected abstract ACCOUNT copyAccount ( final ACCOUNT account ) ;
protected abstract ACCOUNT copyAccount (
final ACCOUNT toCopy , final DiffBasedWorldView context , final boolean mutable ) ;
protected abstract ACCOUNT createAccount (
final DiffBasedWorldView context ,
final Address address ,
final AccountValue stateTrieAccount ,
final boolean mutable ) ;
protected abstract ACCOUNT createAccount (
final DiffBasedWorldView context ,
final Address address ,
final Hash addressHash ,
final long nonce ,
final Wei balance ,
final Hash storageRoot ,
final Hash codeHash ,
final boolean mutable ) ;
protected abstract ACCOUNT createAccount (
final DiffBasedWorldView context , final UpdateTrackingAccount < ACCOUNT > tracked ) ;
protected abstract void assertCloseEnoughForDiffing (
final ACCOUNT source , final AccountValue account , final String context ) ;
}
}