mirror of https://github.com/hyperledger/besu
[PAN-2953] Track world state account key preimages (#1780)
Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>pull/2/head
parent
d48ca9e5a9
commit
a7d9bfdc0a
@ -1,176 +0,0 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* 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 |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.ethereum.worldstate; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Account; |
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.ethereum.core.MutableAccount; |
||||
import tech.pegasys.pantheon.ethereum.core.Wei; |
||||
import tech.pegasys.pantheon.ethereum.core.WorldState; |
||||
import tech.pegasys.pantheon.ethereum.core.WorldUpdater; |
||||
import tech.pegasys.pantheon.ethereum.storage.keyvalue.WorldStateKeyValueStorage; |
||||
import tech.pegasys.pantheon.ethereum.storage.keyvalue.WorldStatePreimageKeyValueStorage; |
||||
import tech.pegasys.pantheon.services.kvstore.InMemoryKeyValueStorage; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.HashSet; |
||||
import java.util.Objects; |
||||
import java.util.Set; |
||||
import java.util.stream.Stream; |
||||
|
||||
/** |
||||
* A simple extension of {@link DefaultMutableWorldState} that tracks in memory the mapping of hash |
||||
* to address for its accounts for debugging purposes. It also provides a full toString() method |
||||
* that display the content of the world state. It is obviously only mean for testing or debugging. |
||||
*/ |
||||
public class DebuggableMutableWorldState extends DefaultMutableWorldState { |
||||
|
||||
// TODO: This is more complex than it should due to DefaultMutableWorldState.accounts() not being
|
||||
// implmemented (pending NC-746). Once that is fixed, we won't need to keep the set of account
|
||||
// hashes at all, just the hashtoAddress map (this is also why things are separated this way,
|
||||
// it will make it easier to update later).
|
||||
|
||||
private static class DebugInfo { |
||||
private final Set<Address> accounts = new HashSet<>(); |
||||
|
||||
private void addAll(final DebugInfo other) { |
||||
this.accounts.addAll(other.accounts); |
||||
} |
||||
} |
||||
|
||||
private final DebugInfo info = new DebugInfo(); |
||||
|
||||
public DebuggableMutableWorldState() { |
||||
super( |
||||
new WorldStateKeyValueStorage(new InMemoryKeyValueStorage()), |
||||
new WorldStatePreimageKeyValueStorage(new InMemoryKeyValueStorage())); |
||||
} |
||||
|
||||
public DebuggableMutableWorldState(final WorldState worldState) { |
||||
super(worldState); |
||||
|
||||
if (worldState instanceof DebuggableMutableWorldState) { |
||||
final DebuggableMutableWorldState dws = ((DebuggableMutableWorldState) worldState); |
||||
info.addAll(dws.info); |
||||
} else { |
||||
// TODO: on NC-746 gets in, we can remove this. That is, post NC-746, we won't be relying
|
||||
// on info.accounts to know that accounts exists, so the only thing we will not have in
|
||||
// this branch is info.addressToHash, but that's not a huge deal.
|
||||
throw new RuntimeException(worldState + " is not a debuggable word state"); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public WorldUpdater updater() { |
||||
return new InfoCollectingUpdater(super.updater(), info); |
||||
} |
||||
|
||||
@Override |
||||
public Stream<Account> streamAccounts() { |
||||
return info.accounts.stream().map(this::get).filter(Objects::nonNull); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
final StringBuilder builder = new StringBuilder(); |
||||
builder.append(rootHash()).append(":\n"); |
||||
streamAccounts() |
||||
.forEach( |
||||
account -> { |
||||
final Address address = account.getAddress(); |
||||
builder |
||||
.append(" ") |
||||
.append(address == null ? "<unknown>" : address) |
||||
.append(" [") |
||||
.append(account.getAddressHash()) |
||||
.append("]:\n"); |
||||
builder.append(" nonce: ").append(account.getNonce()).append('\n'); |
||||
builder.append(" balance: ").append(account.getBalance()).append('\n'); |
||||
builder.append(" code: ").append(account.getCode()).append('\n'); |
||||
}); |
||||
return builder.toString(); |
||||
} |
||||
|
||||
private class InfoCollectingUpdater implements WorldUpdater { |
||||
private final WorldUpdater wrapped; |
||||
private final DebugInfo commitInfo; |
||||
private DebugInfo ownInfo = new DebugInfo(); |
||||
|
||||
InfoCollectingUpdater(final WorldUpdater wrapped, final DebugInfo info) { |
||||
this.wrapped = wrapped; |
||||
this.commitInfo = info; |
||||
} |
||||
|
||||
private void record(final Address address) { |
||||
ownInfo.accounts.add(address); |
||||
} |
||||
|
||||
@Override |
||||
public MutableAccount createAccount( |
||||
final Address address, final long nonce, final Wei balance) { |
||||
record(address); |
||||
return wrapped.createAccount(address, nonce, balance); |
||||
} |
||||
|
||||
@Override |
||||
public MutableAccount createAccount(final Address address) { |
||||
record(address); |
||||
return wrapped.createAccount(address); |
||||
} |
||||
|
||||
@Override |
||||
public MutableAccount getOrCreate(final Address address) { |
||||
record(address); |
||||
return wrapped.getOrCreate(address); |
||||
} |
||||
|
||||
@Override |
||||
public MutableAccount getMutable(final Address address) { |
||||
record(address); |
||||
return wrapped.getMutable(address); |
||||
} |
||||
|
||||
@Override |
||||
public void deleteAccount(final Address address) { |
||||
wrapped.deleteAccount(address); |
||||
} |
||||
|
||||
@Override |
||||
public Collection<Account> getTouchedAccounts() { |
||||
return wrapped.getTouchedAccounts(); |
||||
} |
||||
|
||||
@Override |
||||
public void revert() { |
||||
ownInfo = new DebugInfo(); |
||||
wrapped.revert(); |
||||
} |
||||
|
||||
@Override |
||||
public void commit() { |
||||
commitInfo.addAll(ownInfo); |
||||
wrapped.commit(); |
||||
} |
||||
|
||||
@Override |
||||
public WorldUpdater updater() { |
||||
return new InfoCollectingUpdater(wrapped.updater(), ownInfo); |
||||
} |
||||
|
||||
@Override |
||||
public Account get(final Address address) { |
||||
record(address); |
||||
return wrapped.get(address); |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue