|
|
@ -51,13 +51,19 @@ public class TrieLogLayer { |
|
|
|
private final Map<Address, BonsaiValue<StateTrieAccountValue>> accounts; |
|
|
|
private final Map<Address, BonsaiValue<StateTrieAccountValue>> accounts; |
|
|
|
private final Map<Address, BonsaiValue<Bytes>> code; |
|
|
|
private final Map<Address, BonsaiValue<Bytes>> code; |
|
|
|
private final Map<Address, Map<Hash, BonsaiValue<UInt256>>> storage; |
|
|
|
private final Map<Address, Map<Hash, BonsaiValue<UInt256>>> storage; |
|
|
|
|
|
|
|
private final Map<Address, Hash> contractCodeChangesHistory; |
|
|
|
private boolean frozen = false; |
|
|
|
private boolean frozen = false; |
|
|
|
|
|
|
|
|
|
|
|
TrieLogLayer() { |
|
|
|
TrieLogLayer() { |
|
|
|
// TODO when tuweni fixes zero length byte comparison consider TreeMap
|
|
|
|
// TODO when tuweni fixes zero length byte comparison consider TreeMap
|
|
|
|
accounts = new HashMap<>(); |
|
|
|
this(new HashMap<>()); |
|
|
|
code = new HashMap<>(); |
|
|
|
} |
|
|
|
storage = new HashMap<>(); |
|
|
|
|
|
|
|
|
|
|
|
public TrieLogLayer(final Map<Address, Hash> contractCodeChangesHistory) { |
|
|
|
|
|
|
|
this.accounts = new HashMap<>(); |
|
|
|
|
|
|
|
this.code = new HashMap<>(); |
|
|
|
|
|
|
|
this.storage = new HashMap<>(); |
|
|
|
|
|
|
|
this.contractCodeChangesHistory = contractCodeChangesHistory; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Locks the layer so no new changes can be added; */ |
|
|
|
/** Locks the layer so no new changes can be added; */ |
|
|
@ -82,12 +88,14 @@ public class TrieLogLayer { |
|
|
|
accounts.put(address, new BonsaiValue<>(oldValue, newValue)); |
|
|
|
accounts.put(address, new BonsaiValue<>(oldValue, newValue)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void addCodeChange(final Address address, final Bytes oldValue, final Bytes newValue) { |
|
|
|
void addCodeChange( |
|
|
|
|
|
|
|
final Address address, final Bytes oldValue, final Bytes newValue, final Hash blockHash) { |
|
|
|
checkState(!frozen, "Layer is Frozen"); |
|
|
|
checkState(!frozen, "Layer is Frozen"); |
|
|
|
code.put( |
|
|
|
code.put( |
|
|
|
address, |
|
|
|
address, |
|
|
|
new BonsaiValue<>( |
|
|
|
new BonsaiValue<>( |
|
|
|
oldValue == null ? Bytes.EMPTY : oldValue, newValue == null ? Bytes.EMPTY : newValue)); |
|
|
|
oldValue == null ? Bytes.EMPTY : oldValue, newValue == null ? Bytes.EMPTY : newValue)); |
|
|
|
|
|
|
|
contractCodeChangesHistory.put(address, blockHash); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void addStorageChange( |
|
|
|
void addStorageChange( |
|
|
@ -149,6 +157,12 @@ public class TrieLogLayer { |
|
|
|
newLayer.storage.put(address, storageChanges); |
|
|
|
newLayer.storage.put(address, storageChanges); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (input.nextIsNull()) { |
|
|
|
|
|
|
|
input.skipNext(); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
newLayer.contractCodeChangesHistory.put(address, Hash.wrap(input.readBytes32())); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// TODO add trie nodes
|
|
|
|
// TODO add trie nodes
|
|
|
|
|
|
|
|
|
|
|
|
// lenient leave list for forward compatible additions.
|
|
|
|
// lenient leave list for forward compatible additions.
|
|
|
@ -167,6 +181,7 @@ public class TrieLogLayer { |
|
|
|
addresses.addAll(accounts.keySet()); |
|
|
|
addresses.addAll(accounts.keySet()); |
|
|
|
addresses.addAll(code.keySet()); |
|
|
|
addresses.addAll(code.keySet()); |
|
|
|
addresses.addAll(storage.keySet()); |
|
|
|
addresses.addAll(storage.keySet()); |
|
|
|
|
|
|
|
addresses.addAll(contractCodeChangesHistory.keySet()); |
|
|
|
|
|
|
|
|
|
|
|
output.startList(); // container
|
|
|
|
output.startList(); // container
|
|
|
|
output.writeBytes(blockHash); |
|
|
|
output.writeBytes(blockHash); |
|
|
@ -204,6 +219,13 @@ public class TrieLogLayer { |
|
|
|
output.endList(); |
|
|
|
output.endList(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
final Hash blockHash = contractCodeChangesHistory.get(address); |
|
|
|
|
|
|
|
if (blockHash == null) { |
|
|
|
|
|
|
|
output.writeNull(); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
output.writeBytes(blockHash); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// TODO write trie nodes
|
|
|
|
// TODO write trie nodes
|
|
|
|
|
|
|
|
|
|
|
|
output.endList(); // this change
|
|
|
|
output.endList(); // this change
|
|
|
@ -223,6 +245,10 @@ public class TrieLogLayer { |
|
|
|
return storage.entrySet().stream(); |
|
|
|
return storage.entrySet().stream(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Map<Address, Hash> getContractCodeChangesHistory() { |
|
|
|
|
|
|
|
return contractCodeChangesHistory; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
boolean hasStorageChanges(final Address address) { |
|
|
|
boolean hasStorageChanges(final Address address) { |
|
|
|
return storage.containsKey(address); |
|
|
|
return storage.containsKey(address); |
|
|
|
} |
|
|
|
} |
|
|
@ -244,6 +270,14 @@ public class TrieLogLayer { |
|
|
|
return Optional.ofNullable(code.get(address)).map(BonsaiValue::getUpdated); |
|
|
|
return Optional.ofNullable(code.get(address)).map(BonsaiValue::getUpdated); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Optional<Hash> getLastChangedCodeLocation(final Address address) { |
|
|
|
|
|
|
|
if (contractCodeChangesHistory.containsKey(address) |
|
|
|
|
|
|
|
&& !contractCodeChangesHistory.get(address).isEmpty()) { |
|
|
|
|
|
|
|
return Optional.of(contractCodeChangesHistory.get(address)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return Optional.empty(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Optional<UInt256> getStorageBySlotHash(final Address address, final Hash slotHash) { |
|
|
|
Optional<UInt256> getStorageBySlotHash(final Address address, final Hash slotHash) { |
|
|
|
return Optional.ofNullable(storage.get(address)) |
|
|
|
return Optional.ofNullable(storage.get(address)) |
|
|
|
.map(i -> i.get(slotHash)) |
|
|
|
.map(i -> i.get(slotHash)) |
|
|
|