@ -44,6 +44,7 @@ import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier;
import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction ;
import java.util.ArrayList ;
import java.util.HashSet ;
import java.util.List ;
import java.util.Map ;
import java.util.Optional ;
@ -51,7 +52,6 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap ;
import javax.annotation.Nonnull ;
import kotlin.Pair ;
import org.apache.tuweni.bytes.Bytes ;
import org.apache.tuweni.bytes.Bytes32 ;
import org.apache.tuweni.units.bigints.UInt256 ;
@ -120,13 +120,17 @@ public class VerkleWorldState extends DiffBasedWorldState {
final Map < Address , HasherContext > preloadedHashers = new ConcurrentHashMap < > ( ) ;
worldStateUpdater . getAccountsToUpdate ( ) . entrySet ( ) . parallelStream ( )
final Set < Address > addressesToPersist = getAddressesToPersist ( worldStateUpdater ) ;
addressesToPersist . parallelStream ( )
. forEach (
accountUpdate - > {
final Address accountKey = accountUpdate . getKey ( ) ;
accountKey - > {
final DiffBasedValue < VerkleAccount > accountUpdate =
worldStateUpdater . getAccountsToUpdate ( ) . get ( accountKey ) ;
// generate account triekeys
final List < Bytes32 > accountKeyIds =
new ArrayList < > ( trieKeyPreloader . generateAccountKeyIds ( ) ) ;
final List < Bytes32 > accountKeyIds = new ArrayList < > ( ) ;
if ( accountUpdate ! = null & & ! accountUpdate . isUnchanged ( ) ) {
accountKeyIds . add ( trieKeyPreloader . generateAccountKeyId ( ) ) ;
}
// generate storage triekeys
final List < Bytes32 > storageKeyIds = new ArrayList < > ( ) ;
@ -153,7 +157,7 @@ public class VerkleWorldState extends DiffBasedWorldState {
! codeUpdate . isUnchanged ( )
& & ! ( codeIsEmpty ( previousCode ) & & codeIsEmpty ( updatedCode ) ) ;
if ( isCodeUpdateNeeded ) {
accountKeyIds . add ( Parameters . CODE_SIZE _LEAF_KEY ) ;
accountKeyIds . add ( Parameters . CODE_HASH _LEAF_KEY ) ;
codeKeyIds . addAll (
trieKeyPreloader . generateCodeChunkKeyIds (
updatedCode = = null ? previousCode : updatedCode ) ) ;
@ -166,24 +170,13 @@ public class VerkleWorldState extends DiffBasedWorldState {
accountKey , accountKeyIds , storageKeyIds , codeKeyIds ) ) ;
} ) ;
for ( final Map . Entry < Address , DiffBasedValue < VerkleAccount > > accountUpdate :
worldStateUpdater . getAccountsToUpdate ( ) . entrySet ( ) ) {
final Address accountKey = accountUpdate . getKey ( ) ;
final HasherContext hasherContext = preloadedHashers . get ( accountKey ) ;
final VerkleEntryFactory verkleEntryFactory = new VerkleEntryFactory ( hasherContext . hasher ( ) ) ;
if ( hasherContext . hasStorageTrieKeys ( ) ) {
final StorageConsumingMap < StorageSlotKey , DiffBasedValue < UInt256 > > storageAccountUpdate =
worldStateUpdater . getStorageToUpdate ( ) . get ( accountKey ) ;
updateAccountStorageState (
accountKey , stateTrie , maybeStateUpdater , verkleEntryFactory , storageAccountUpdate ) ;
}
if ( hasherContext . hasCodeTrieKeys ( ) ) {
final DiffBasedValue < Bytes > codeUpdate =
worldStateUpdater . getCodeToUpdate ( ) . get ( accountKey ) ;
updateCode ( accountKey , stateTrie , maybeStateUpdater , verkleEntryFactory , codeUpdate ) ;
}
updateTheAccount (
accountKey , stateTrie , maybeStateUpdater , verkleEntryFactory , accountUpdate . getValue ( ) ) ;
for ( final Address accountKey : addressesToPersist ) {
updateState (
accountKey ,
stateTrie ,
maybeStateUpdater ,
preloadedHashers . get ( accountKey ) ,
worldStateUpdater ) ;
}
LOG . info ( "start commit " ) ;
@ -206,124 +199,72 @@ public class VerkleWorldState extends DiffBasedWorldState {
return Hash . wrap ( rootHash ) ;
}
private void updateTheAccount (
private static boolean codeIsEmpty ( final Bytes value ) {
return value = = null | | value . isEmpty ( ) ;
}
private void generateAccountValues (
final Address accountKey ,
final VerkleTrie stateTrie ,
final Optional < VerkleWorldStateKeyValueStorage . Updater > maybeStateUpdater ,
final VerkleEntryFactory verkleEntryFactory ,
final Optional < VerkleWorldStateKeyValueStorage . Updater > maybeStateUpdater ,
final DiffBasedValue < VerkleAccount > accountUpdate ) {
if ( ! accountUpdate . isUnchanged ( ) ) {
final VerkleAccount priorAccount = accountUpdate . getPrior ( ) ;
final VerkleAccount updatedAccount = accountUpdate . getUpdated ( ) ;
if ( updatedAccount = = null ) {
final Hash addressHash = hashAndSavePreImage ( accountKey ) ;
verkleEntryFactory
. generateKeysForAccount ( accountKey )
. forEach (
bytes - > {
System . out . println (
"remove "
+ accountKey
+ " "
+ bytes
+ " "
+ accountUpdate . getPrior ( )
+ " "
+ accountUpdate . getUpdated ( ) ) ;
stateTrie . remove ( bytes ) ;
} ) ;
maybeStateUpdater . ifPresent (
bonsaiUpdater - > bonsaiUpdater . removeAccountInfoState ( addressHash ) ) ;
} else {
final Bytes priorValue = priorAccount = = null ? null : priorAccount . serializeAccount ( ) ;
final Bytes accountValue = updatedAccount . serializeAccount ( ) ;
if ( ! accountValue . equals ( priorValue ) ) {
verkleEntryFactory
. generateKeyValuesForAccount (
accountKey ,
updatedAccount . getNonce ( ) ,
updatedAccount . getBalance ( ) ,
updatedAccount . getCodeHash ( ) )
. forEach (
( bytes , bytes2 ) - > {
System . out . println (
"add "
+ accountKey
+ " "
+ bytes
+ " "
+ bytes2
+ " "
+ updatedAccount . getBalance ( ) ) ;
stateTrie . put ( bytes , bytes2 ) ;
} ) ;
maybeStateUpdater . ifPresent (
bonsaiUpdater - >
bonsaiUpdater . putAccountInfoState ( hashAndSavePreImage ( accountKey ) , accountValue ) ) ;
}
}
if ( accountUpdate = = null | | accountUpdate . isUnchanged ( ) ) {
return ;
}
if ( accountUpdate . getUpdated ( ) = = null ) {
verkleEntryFactory . generateAccountKeysForRemoval ( accountKey ) ;
final Hash addressHash = hashAndSavePreImage ( accountKey ) ;
maybeStateUpdater . ifPresent (
bonsaiUpdater - > bonsaiUpdater . removeAccountInfoState ( addressHash ) ) ;
return ;
}
final VerkleAccount updatedAcount = accountUpdate . getUpdated ( ) ;
verkleEntryFactory . generateAccountKeyValueForUpdate (
accountKey , updatedAcount . getNonce ( ) , updatedAcount . getBalance ( ) ) ;
maybeStateUpdater . ifPresent (
bonsaiUpdater - >
bonsaiUpdater . putAccountInfoState (
hashAndSavePreImage ( accountKey ) , updatedAcount . serializeAccount ( ) ) ) ;
}
private void updateCode (
private void generateCodeValues (
final Address accountKey ,
final VerkleTrie stateTrie ,
final Optional < VerkleWorldStateKeyValueStorage . Updater > maybeStateUpdater ,
final VerkleEntryFactory verkleEntryFactory ,
final Optional < VerkleWorldStateKeyValueStorage . Updater > maybeStateUpdater ,
final DiffBasedValue < Bytes > codeUpdate ) {
final Bytes priorCode = codeUpdate . getPrior ( ) ;
final Bytes updatedCode = codeUpdate . getUpdated ( ) ;
final Hash accountHash = accountKey . addressHash ( ) ;
if ( updatedCode = = null ) {
final Hash priorCodeHash = Hash . hash ( priorCode ) ;
verkleEntryFactory
. generateKeysForCode ( accountKey , priorCode )
. forEach (
bytes - > {
System . out . println ( "remove code " + bytes ) ;
stateTrie . remove ( bytes ) ;
} ) ;
if ( codeUpdate = = null
| | codeUpdate . isUnchanged ( )
| | ( codeIsEmpty ( codeUpdate . getPrior ( ) ) & & codeIsEmpty ( codeUpdate . getUpdated ( ) ) ) ) {
return ;
}
if ( codeUpdate . getUpdated ( ) = = null ) {
final Hash priorCodeHash = Hash . hash ( codeUpdate . getPrior ( ) ) ;
verkleEntryFactory . generateCodeKeysForRemoval ( accountKey , codeUpdate . getPrior ( ) ) ;
final Hash accountHash = accountKey . addressHash ( ) ;
maybeStateUpdater . ifPresent (
bonsaiUpdater - > bonsaiUpdater . removeCode ( accountHash , priorCodeHash ) ) ;
return ;
}
final Hash accountHash = accountKey . addressHash ( ) ;
final Hash codeHash = Hash . hash ( codeUpdate . getUpdated ( ) ) ;
verkleEntryFactory . generateCodeKeyValuesForUpdate (
accountKey , codeUpdate . getUpdated ( ) , codeHash ) ;
if ( codeUpdate . getUpdated ( ) . isEmpty ( ) ) {
maybeStateUpdater . ifPresent ( bonsaiUpdater - > bonsaiUpdater . removeCode ( accountHash , codeHash ) ) ;
} else {
if ( updatedCode . isEmpty ( ) ) {
final Hash codeHash = Hash . hash ( updatedCode ) ;
verkleEntryFactory
. generateKeyValuesForCode ( accountKey , updatedCode )
. forEach (
( bytes , bytes2 ) - > {
// System.out.println("add code " + bytes + " " + bytes2);
stateTrie . put ( bytes , bytes2 ) ;
} ) ;
maybeStateUpdater . ifPresent (
bonsaiUpdater - > bonsaiUpdater . removeCode ( accountHash , codeHash ) ) ;
} else {
final Hash codeHash = Hash . hash ( updatedCode ) ;
verkleEntryFactory
. generateKeyValuesForCode ( accountKey , updatedCode )
. forEach (
( bytes , bytes2 ) - > {
System . out . println ( "add code " + bytes + " " + bytes2 ) ;
stateTrie . put ( bytes , bytes2 ) ;
} ) ;
maybeStateUpdater . ifPresent (
bonsaiUpdater - > bonsaiUpdater . putCode ( accountHash , codeHash , updatedCode ) ) ;
}
maybeStateUpdater . ifPresent (
bonsaiUpdater - > bonsaiUpdater . putCode ( accountHash , codeHash , codeUpdate . getUpdated ( ) ) ) ;
}
}
private boolean codeIsEmpty ( final Bytes value ) {
return value = = null | | value . isEmpty ( ) ;
}
private void updateAccountStorageState (
private void generateStorageValues (
final Address accountKey ,
final VerkleTrie stateTrie ,
final Optional < VerkleWorldStateKeyValueStorage . Updater > maybeStateUpdater ,
final VerkleEntryFactory verkleEntryFactory ,
final Optional < VerkleWorldStateKeyValueStorage . Updater > maybeStateUpdater ,
final StorageConsumingMap < StorageSlotKey , DiffBasedValue < UInt256 > > storageAccountUpdate ) {
if ( storageAccountUpdate = = null | | storageAccountUpdate . keySet ( ) . isEmpty ( ) ) {
return ;
}
final Hash updatedAddressHash = accountKey . addressHash ( ) ;
// for manicured tries and composting, collect branches here (not implemented)
for ( final Map . Entry < StorageSlotKey , DiffBasedValue < UInt256 > > storageUpdate :
@ -333,30 +274,13 @@ public class VerkleWorldState extends DiffBasedWorldState {
if ( ! storageUpdate . getValue ( ) . isUnchanged ( ) ) {
final UInt256 updatedStorage = storageUpdate . getValue ( ) . getUpdated ( ) ;
if ( updatedStorage = = null ) {
verkleEntryFactory
. generateKeysForStorage ( accountKey , storageUpdate . getKey ( ) )
. forEach (
bytes - > {
System . out . println ( "remove storage" + bytes ) ;
stateTrie . remove ( bytes ) ;
} ) ;
verkleEntryFactory . generateStorageKeysForRemoval ( accountKey , storageUpdate . getKey ( ) ) ;
maybeStateUpdater . ifPresent (
diffBasedUpdater - >
diffBasedUpdater . removeStorageValueBySlotHash ( updatedAddressHash , slotHash ) ) ;
} else {
final Pair < Bytes , Bytes > storage =
verkleEntryFactory . generateKeyValuesForStorage (
accountKey , storageUpdate . getKey ( ) , updatedStorage ) ;
System . out . println ( "add storage " + storage . getFirst ( ) + " " + storage . getSecond ( ) ) ;
stateTrie
. put ( storage . getFirst ( ) , storage . getSecond ( ) )
. ifPresentOrElse (
bytes - > {
storageUpdate . getValue ( ) . setPrior ( UInt256 . fromBytes ( bytes ) ) ;
} ,
( ) - > {
storageUpdate . getValue ( ) . setPrior ( null ) ;
} ) ;
verkleEntryFactory . generateStorageKeyValueForUpdate (
accountKey , storageUpdate . getKey ( ) , updatedStorage ) ;
maybeStateUpdater . ifPresent (
bonsaiUpdater - >
bonsaiUpdater . putStorageValueBySlotHash (
@ -366,6 +290,79 @@ public class VerkleWorldState extends DiffBasedWorldState {
}
}
private void updateState (
final Address accountKey ,
final VerkleTrie stateTrie ,
final Optional < VerkleWorldStateKeyValueStorage . Updater > maybeStateUpdater ,
final HasherContext hasherContext ,
final VerkleWorldStateUpdateAccumulator worldStateUpdater ) {
final VerkleEntryFactory verkleEntryFactory = new VerkleEntryFactory ( hasherContext . hasher ( ) ) ;
generateAccountValues (
accountKey ,
verkleEntryFactory ,
maybeStateUpdater ,
worldStateUpdater . getAccountsToUpdate ( ) . get ( accountKey ) ) ;
generateCodeValues (
accountKey ,
verkleEntryFactory ,
maybeStateUpdater ,
worldStateUpdater . getCodeToUpdate ( ) . get ( accountKey ) ) ;
generateStorageValues (
accountKey ,
verkleEntryFactory ,
maybeStateUpdater ,
worldStateUpdater . getStorageToUpdate ( ) . get ( accountKey ) ) ;
verkleEntryFactory
. getKeysForRemoval ( )
. forEach (
key - > {
System . out . println ( "remove key " + key ) ;
stateTrie . remove ( key ) ;
} ) ;
verkleEntryFactory
. getNonStorageKeyValuesForUpdate ( )
. forEach (
( key , value ) - > {
System . out . println ( "add key " + key + " leaf value " + value ) ;
stateTrie . put ( key , value ) ;
} ) ;
verkleEntryFactory
. getStorageKeyValuesForUpdate ( )
. forEach (
( storageSlotKey , pair ) - > {
var storageAccountUpdate = worldStateUpdater . getStorageToUpdate ( ) . get ( accountKey ) ;
if ( storageAccountUpdate = = null ) {
return ;
}
System . out . println (
"add storage key " + pair . getFirst ( ) + " value " + pair . getSecond ( ) ) ;
Optional < DiffBasedValue < UInt256 > > storageUpdate =
Optional . ofNullable ( storageAccountUpdate . get ( storageSlotKey ) ) ;
stateTrie
. put ( pair . getFirst ( ) , pair . getSecond ( ) )
. ifPresentOrElse (
bytes - >
storageUpdate . ifPresent (
storage - > storage . setPrior ( UInt256 . fromBytes ( bytes ) ) ) ,
( ) - > storageUpdate . ifPresent ( storage - > storage . setPrior ( null ) ) ) ;
} ) ;
}
public Set < Address > getAddressesToPersist (
final DiffBasedWorldStateUpdateAccumulator < ? > accumulator ) {
Set < Address > mergedAddresses =
new HashSet < > ( accumulator . getAccountsToUpdate ( ) . keySet ( ) ) ; // accountsToUpdate
mergedAddresses . addAll ( accumulator . getCodeToUpdate ( ) . keySet ( ) ) ; // codeToUpdate
mergedAddresses . addAll ( accumulator . getStorageToClear ( ) ) ; // storageToClear
mergedAddresses . addAll ( accumulator . getStorageToUpdate ( ) . keySet ( ) ) ; // storageToUpdate
return mergedAddresses ;
}
@Override
public MutableWorldState freeze ( ) {
this . worldStateConfig . setFrozen ( true ) ;