mirror of https://github.com/hyperledger/besu
SNAPSYNC add request task (#3601)
PR that adds the different request tasks necessary for the snapsync as well as a utility to manage the ranges of requests Signed-off-by: Karim TAAM <karim.t2am@gmail.com>pull/3629/head
parent
1aec566c35
commit
0d182b80ae
@ -0,0 +1,95 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.core; |
||||
|
||||
import org.hyperledger.besu.datatypes.Hash; |
||||
import org.hyperledger.besu.datatypes.Wei; |
||||
import org.hyperledger.besu.ethereum.rlp.RLP; |
||||
import org.hyperledger.besu.ethereum.trie.MerklePatriciaTrie; |
||||
import org.hyperledger.besu.ethereum.trie.StoredMerklePatriciaTrie; |
||||
import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; |
||||
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes; |
||||
import org.apache.tuweni.bytes.Bytes32; |
||||
import org.apache.tuweni.units.bigints.UInt256; |
||||
|
||||
public class TrieGenerator { |
||||
|
||||
public static MerklePatriciaTrie<Bytes32, Bytes> generateTrie( |
||||
final WorldStateStorage worldStateStorage, final int nbAccounts) { |
||||
final List<Hash> accountHash = new ArrayList<>(); |
||||
final MerklePatriciaTrie<Bytes32, Bytes> accountStateTrie = |
||||
emptyAccountStateTrie(worldStateStorage); |
||||
// Add some storage values
|
||||
for (int i = 0; i < nbAccounts; i++) { |
||||
final WorldStateStorage.Updater updater = worldStateStorage.updater(); |
||||
|
||||
accountHash.add(Hash.wrap(Bytes32.leftPad(Bytes.of(i + 1)))); |
||||
final MerklePatriciaTrie<Bytes32, Bytes> storageTrie = |
||||
emptyStorageTrie(worldStateStorage, accountHash.get(i)); |
||||
writeStorageValue(storageTrie, UInt256.ONE, UInt256.valueOf(2L)); |
||||
writeStorageValue(storageTrie, UInt256.valueOf(2L), UInt256.valueOf(4L)); |
||||
writeStorageValue(storageTrie, UInt256.valueOf(3L), UInt256.valueOf(6L)); |
||||
int accountIndex = i; |
||||
storageTrie.commit( |
||||
(location, hash, value) -> |
||||
updater.putAccountStorageTrieNode( |
||||
accountHash.get(accountIndex), location, hash, value)); |
||||
final Hash codeHash = Hash.hash(Bytes32.leftPad(Bytes.of(i + 10))); |
||||
final StateTrieAccountValue accountValue = |
||||
new StateTrieAccountValue(1L, Wei.of(2L), Hash.wrap(storageTrie.getRootHash()), codeHash); |
||||
accountStateTrie.put(accountHash.get(i), RLP.encode(accountValue::writeTo)); |
||||
accountStateTrie.commit(updater::putAccountStateTrieNode); |
||||
|
||||
// Persist updates
|
||||
updater.commit(); |
||||
} |
||||
return accountStateTrie; |
||||
} |
||||
|
||||
private static void writeStorageValue( |
||||
final MerklePatriciaTrie<Bytes32, Bytes> storageTrie, |
||||
final UInt256 key, |
||||
final UInt256 value) { |
||||
storageTrie.put(storageKeyHash(key), encodeStorageValue(value)); |
||||
} |
||||
|
||||
private static Bytes32 storageKeyHash(final UInt256 storageKey) { |
||||
return Hash.hash(storageKey); |
||||
} |
||||
|
||||
private static Bytes encodeStorageValue(final UInt256 storageValue) { |
||||
return RLP.encode(out -> out.writeBytes(storageValue.toMinimalBytes())); |
||||
} |
||||
|
||||
public static MerklePatriciaTrie<Bytes32, Bytes> emptyStorageTrie( |
||||
final WorldStateStorage worldStateStorage, final Hash accountHash) { |
||||
return new StoredMerklePatriciaTrie<>( |
||||
(location, hash) -> |
||||
worldStateStorage.getAccountStorageTrieNode(accountHash, location, hash), |
||||
b -> b, |
||||
b -> b); |
||||
} |
||||
|
||||
public static MerklePatriciaTrie<Bytes32, Bytes> emptyAccountStateTrie( |
||||
final WorldStateStorage worldStateStorage) { |
||||
return new StoredMerklePatriciaTrie<>( |
||||
worldStateStorage::getAccountStateTrieNode, b -> b, b -> b); |
||||
} |
||||
} |
@ -0,0 +1,93 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.eth.manager.snap; |
||||
|
||||
import org.hyperledger.besu.ethereum.core.BlockHeader; |
||||
import org.hyperledger.besu.ethereum.eth.manager.EthContext; |
||||
import org.hyperledger.besu.ethereum.eth.manager.EthPeer; |
||||
import org.hyperledger.besu.ethereum.eth.manager.PendingPeerRequest; |
||||
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractPeerRequestTask; |
||||
import org.hyperledger.besu.ethereum.eth.messages.snap.AccountRangeMessage; |
||||
import org.hyperledger.besu.ethereum.eth.messages.snap.SnapV1; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; |
||||
import org.hyperledger.besu.plugin.services.MetricsSystem; |
||||
|
||||
import java.util.Optional; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes32; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
public class GetAccountRangeFromPeerTask |
||||
extends AbstractPeerRequestTask<AccountRangeMessage.AccountRangeData> { |
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(GetAccountRangeFromPeerTask.class); |
||||
|
||||
private final Bytes32 startKeyHash; |
||||
private final Bytes32 endKeyHash; |
||||
private final BlockHeader blockHeader; |
||||
|
||||
private GetAccountRangeFromPeerTask( |
||||
final EthContext ethContext, |
||||
final Bytes32 startKeyHash, |
||||
final Bytes32 endKeyHash, |
||||
final BlockHeader blockHeader, |
||||
final MetricsSystem metricsSystem) { |
||||
super(ethContext, SnapV1.ACCOUNT_RANGE, metricsSystem); |
||||
this.startKeyHash = startKeyHash; |
||||
this.endKeyHash = endKeyHash; |
||||
this.blockHeader = blockHeader; |
||||
} |
||||
|
||||
public static GetAccountRangeFromPeerTask forAccountRange( |
||||
final EthContext ethContext, |
||||
final Bytes32 startKeyHash, |
||||
final Bytes32 endKeyHash, |
||||
final BlockHeader blockHeader, |
||||
final MetricsSystem metricsSystem) { |
||||
return new GetAccountRangeFromPeerTask( |
||||
ethContext, startKeyHash, endKeyHash, blockHeader, metricsSystem); |
||||
} |
||||
|
||||
@Override |
||||
protected PendingPeerRequest sendRequest() { |
||||
return sendRequestToPeer( |
||||
peer -> { |
||||
LOG.trace( |
||||
"Requesting account range [{} ,{}] for state root {} from peer {} .", |
||||
startKeyHash, |
||||
endKeyHash, |
||||
blockHeader.getStateRoot(), |
||||
peer); |
||||
return peer.getSnapAccountRange(blockHeader.getStateRoot(), startKeyHash, endKeyHash); |
||||
}, |
||||
blockHeader.getNumber()); |
||||
} |
||||
|
||||
@Override |
||||
protected Optional<AccountRangeMessage.AccountRangeData> processResponse( |
||||
final boolean streamClosed, final MessageData message, final EthPeer peer) { |
||||
|
||||
if (streamClosed) { |
||||
// We don't record this as a useless response because it's impossible to know if a peer has
|
||||
// the data we're requesting.
|
||||
return Optional.empty(); |
||||
} |
||||
final AccountRangeMessage accountRangeMessage = AccountRangeMessage.readFrom(message); |
||||
final AccountRangeMessage.AccountRangeData accountRangeData = |
||||
accountRangeMessage.accountData(true); |
||||
return Optional.of(accountRangeData); |
||||
} |
||||
} |
@ -0,0 +1,104 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.eth.manager.snap; |
||||
|
||||
import static java.util.Collections.emptyMap; |
||||
import static org.slf4j.LoggerFactory.getLogger; |
||||
|
||||
import org.hyperledger.besu.datatypes.Hash; |
||||
import org.hyperledger.besu.ethereum.core.BlockHeader; |
||||
import org.hyperledger.besu.ethereum.eth.manager.EthContext; |
||||
import org.hyperledger.besu.ethereum.eth.manager.EthPeer; |
||||
import org.hyperledger.besu.ethereum.eth.manager.PendingPeerRequest; |
||||
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractPeerRequestTask; |
||||
import org.hyperledger.besu.ethereum.eth.messages.snap.ByteCodesMessage; |
||||
import org.hyperledger.besu.ethereum.eth.messages.snap.SnapV1; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; |
||||
import org.hyperledger.besu.plugin.services.MetricsSystem; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Optional; |
||||
|
||||
import kotlin.collections.ArrayDeque; |
||||
import org.apache.tuweni.bytes.Bytes; |
||||
import org.apache.tuweni.bytes.Bytes32; |
||||
import org.slf4j.Logger; |
||||
|
||||
public class GetBytecodeFromPeerTask extends AbstractPeerRequestTask<Map<Bytes32, Bytes>> { |
||||
|
||||
private static final Logger LOG = getLogger(GetBytecodeFromPeerTask.class); |
||||
|
||||
private final List<Bytes32> codeHashes; |
||||
private final BlockHeader blockHeader; |
||||
|
||||
private GetBytecodeFromPeerTask( |
||||
final EthContext ethContext, |
||||
final List<Bytes32> codeHashes, |
||||
final BlockHeader blockHeader, |
||||
final MetricsSystem metricsSystem) { |
||||
super(ethContext, SnapV1.STORAGE_RANGE, metricsSystem); |
||||
this.codeHashes = codeHashes; |
||||
this.blockHeader = blockHeader; |
||||
} |
||||
|
||||
public static GetBytecodeFromPeerTask forBytecode( |
||||
final EthContext ethContext, |
||||
final List<Bytes32> codeHashes, |
||||
final BlockHeader blockHeader, |
||||
final MetricsSystem metricsSystem) { |
||||
return new GetBytecodeFromPeerTask(ethContext, codeHashes, blockHeader, metricsSystem); |
||||
} |
||||
|
||||
@Override |
||||
protected PendingPeerRequest sendRequest() { |
||||
return sendRequestToPeer( |
||||
peer -> { |
||||
LOG.trace("Requesting {} Bytecodes from {} .", codeHashes.size(), peer); |
||||
return peer.getSnapBytecode(blockHeader.getStateRoot(), codeHashes); |
||||
}, |
||||
blockHeader.getNumber()); |
||||
} |
||||
|
||||
@Override |
||||
protected Optional<Map<Bytes32, Bytes>> processResponse( |
||||
final boolean streamClosed, final MessageData message, final EthPeer peer) { |
||||
|
||||
if (streamClosed) { |
||||
// We don't record this as a useless response because it's impossible to know if a peer has
|
||||
// the data we're requesting.
|
||||
return Optional.of(emptyMap()); |
||||
} |
||||
final ByteCodesMessage byteCodesMessage = ByteCodesMessage.readFrom(message); |
||||
final ArrayDeque<Bytes> bytecodes = byteCodesMessage.bytecodes(true).codes(); |
||||
if (bytecodes.size() > codeHashes.size()) { |
||||
// Can't be the response to our request
|
||||
return Optional.empty(); |
||||
} |
||||
return mapCodeByHash(bytecodes); |
||||
} |
||||
|
||||
private Optional<Map<Bytes32, Bytes>> mapCodeByHash(final ArrayDeque<Bytes> bytecodes) { |
||||
final Map<Bytes32, Bytes> codeByHash = new HashMap<>(); |
||||
for (int i = 0; i < bytecodes.size(); i++) { |
||||
final Hash hash = Hash.hash(bytecodes.get(i)); |
||||
if (codeHashes.get(i).equals(hash)) { |
||||
codeByHash.put(hash, bytecodes.get(i)); |
||||
} |
||||
} |
||||
return Optional.of(codeByHash); |
||||
} |
||||
} |
@ -0,0 +1,97 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.eth.manager.snap; |
||||
|
||||
import org.hyperledger.besu.ethereum.core.BlockHeader; |
||||
import org.hyperledger.besu.ethereum.eth.manager.EthContext; |
||||
import org.hyperledger.besu.ethereum.eth.manager.EthPeer; |
||||
import org.hyperledger.besu.ethereum.eth.manager.PendingPeerRequest; |
||||
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractPeerRequestTask; |
||||
import org.hyperledger.besu.ethereum.eth.messages.snap.SnapV1; |
||||
import org.hyperledger.besu.ethereum.eth.messages.snap.StorageRangeMessage; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; |
||||
import org.hyperledger.besu.plugin.services.MetricsSystem; |
||||
|
||||
import java.util.List; |
||||
import java.util.Optional; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes32; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
public class GetStorageRangeFromPeerTask |
||||
extends AbstractPeerRequestTask<StorageRangeMessage.SlotRangeData> { |
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(GetStorageRangeFromPeerTask.class); |
||||
|
||||
private final List<Bytes32> accountHashes; |
||||
private final Bytes32 startKeyHash; |
||||
private final Bytes32 endKeyHash; |
||||
private final BlockHeader blockHeader; |
||||
|
||||
private GetStorageRangeFromPeerTask( |
||||
final EthContext ethContext, |
||||
final List<Bytes32> accountHashes, |
||||
final Bytes32 startKeyHash, |
||||
final Bytes32 endKeyHash, |
||||
final BlockHeader blockHeader, |
||||
final MetricsSystem metricsSystem) { |
||||
super(ethContext, SnapV1.STORAGE_RANGE, metricsSystem); |
||||
this.accountHashes = accountHashes; |
||||
this.startKeyHash = startKeyHash; |
||||
this.endKeyHash = endKeyHash; |
||||
this.blockHeader = blockHeader; |
||||
} |
||||
|
||||
public static GetStorageRangeFromPeerTask forStorageRange( |
||||
final EthContext ethContext, |
||||
final List<Bytes32> accountHashes, |
||||
final Bytes32 startKeyHash, |
||||
final Bytes32 endKeyHash, |
||||
final BlockHeader blockHeader, |
||||
final MetricsSystem metricsSystem) { |
||||
return new GetStorageRangeFromPeerTask( |
||||
ethContext, accountHashes, startKeyHash, endKeyHash, blockHeader, metricsSystem); |
||||
} |
||||
|
||||
@Override |
||||
protected PendingPeerRequest sendRequest() { |
||||
return sendRequestToPeer( |
||||
peer -> { |
||||
LOG.trace( |
||||
"Requesting storage range [{} ,{}] for {} accounts from peer {} .", |
||||
startKeyHash, |
||||
endKeyHash, |
||||
accountHashes.size(), |
||||
peer); |
||||
return peer.getSnapStorageRange( |
||||
blockHeader.getStateRoot(), accountHashes, startKeyHash, endKeyHash); |
||||
}, |
||||
blockHeader.getNumber()); |
||||
} |
||||
|
||||
@Override |
||||
protected Optional<StorageRangeMessage.SlotRangeData> processResponse( |
||||
final boolean streamClosed, final MessageData message, final EthPeer peer) { |
||||
|
||||
if (streamClosed) { |
||||
// We don't record this as a useless response because it's impossible to know if a peer has
|
||||
// the data we're requesting.
|
||||
return Optional.empty(); |
||||
} |
||||
|
||||
return Optional.of(StorageRangeMessage.readFrom(message).slotsData(true)); |
||||
} |
||||
} |
@ -0,0 +1,113 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.eth.manager.snap; |
||||
|
||||
import static java.util.Collections.emptyMap; |
||||
import static org.slf4j.LoggerFactory.getLogger; |
||||
|
||||
import org.hyperledger.besu.ethereum.core.BlockHeader; |
||||
import org.hyperledger.besu.ethereum.eth.manager.EthContext; |
||||
import org.hyperledger.besu.ethereum.eth.manager.EthPeer; |
||||
import org.hyperledger.besu.ethereum.eth.manager.PendingPeerRequest; |
||||
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractPeerRequestTask; |
||||
import org.hyperledger.besu.ethereum.eth.messages.snap.SnapV1; |
||||
import org.hyperledger.besu.ethereum.eth.messages.snap.TrieNodesMessage; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; |
||||
import org.hyperledger.besu.plugin.services.MetricsSystem; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Optional; |
||||
import java.util.stream.Collectors; |
||||
|
||||
import com.google.common.collect.Lists; |
||||
import kotlin.collections.ArrayDeque; |
||||
import org.apache.tuweni.bytes.Bytes; |
||||
import org.slf4j.Logger; |
||||
|
||||
public class GetTrieNodeFromPeerTask extends AbstractPeerRequestTask<Map<Bytes, Bytes>> { |
||||
|
||||
private static final Logger LOG = getLogger(GetTrieNodeFromPeerTask.class); |
||||
|
||||
private final List<List<Bytes>> paths; |
||||
private final BlockHeader blockHeader; |
||||
|
||||
private GetTrieNodeFromPeerTask( |
||||
final EthContext ethContext, |
||||
final List<List<Bytes>> paths, |
||||
final BlockHeader blockHeader, |
||||
final MetricsSystem metricsSystem) { |
||||
super(ethContext, SnapV1.TRIE_NODES, metricsSystem); |
||||
this.paths = paths; |
||||
this.blockHeader = blockHeader; |
||||
} |
||||
|
||||
public static GetTrieNodeFromPeerTask forTrieNodes( |
||||
final EthContext ethContext, |
||||
final Map<Bytes, List<Bytes>> paths, |
||||
final BlockHeader blockHeader, |
||||
final MetricsSystem metricsSystem) { |
||||
return new GetTrieNodeFromPeerTask( |
||||
ethContext, |
||||
paths.entrySet().stream() |
||||
.map(entry -> Lists.asList(entry.getKey(), entry.getValue().toArray(new Bytes[0]))) |
||||
.collect(Collectors.toList()), |
||||
blockHeader, |
||||
metricsSystem); |
||||
} |
||||
|
||||
@Override |
||||
protected PendingPeerRequest sendRequest() { |
||||
return sendRequestToPeer( |
||||
peer -> { |
||||
LOG.trace("Requesting {} trie nodes from peer {}", paths.size(), peer); |
||||
return peer.getSnapTrieNode(blockHeader.getStateRoot(), paths); |
||||
}, |
||||
blockHeader.getNumber()); |
||||
} |
||||
|
||||
@Override |
||||
protected Optional<Map<Bytes, Bytes>> processResponse( |
||||
final boolean streamClosed, final MessageData message, final EthPeer peer) { |
||||
if (streamClosed) { |
||||
// We don't record this as a useless response because it's impossible to know if a peer has
|
||||
// the data we're requesting.
|
||||
return Optional.of(emptyMap()); |
||||
} |
||||
final TrieNodesMessage trieNodes = TrieNodesMessage.readFrom(message); |
||||
final ArrayDeque<Bytes> nodes = trieNodes.nodes(true); |
||||
return mapNodeDataByPath(nodes); |
||||
} |
||||
|
||||
private Optional<Map<Bytes, Bytes>> mapNodeDataByPath(final ArrayDeque<Bytes> nodeData) { |
||||
final Map<Bytes, Bytes> nodeDataByPath = new HashMap<>(); |
||||
paths.forEach( |
||||
list -> { |
||||
int i = 1; |
||||
if (!nodeData.isEmpty() && i == list.size()) { |
||||
Bytes bytes = nodeData.removeFirst(); |
||||
nodeDataByPath.put(list.get(0), bytes); |
||||
} else { |
||||
while (!nodeData.isEmpty() && i < list.size()) { |
||||
Bytes bytes = nodeData.removeFirst(); |
||||
nodeDataByPath.put(Bytes.concatenate(list.get(0), list.get(i)), bytes); |
||||
i++; |
||||
} |
||||
} |
||||
}); |
||||
return Optional.of(nodeDataByPath); |
||||
} |
||||
} |
@ -0,0 +1,78 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.eth.manager.snap; |
||||
|
||||
import org.hyperledger.besu.ethereum.core.BlockHeader; |
||||
import org.hyperledger.besu.ethereum.eth.manager.EthContext; |
||||
import org.hyperledger.besu.ethereum.eth.manager.EthPeer; |
||||
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractRetryingPeerTask; |
||||
import org.hyperledger.besu.ethereum.eth.manager.task.EthTask; |
||||
import org.hyperledger.besu.ethereum.eth.messages.snap.AccountRangeMessage; |
||||
import org.hyperledger.besu.plugin.services.MetricsSystem; |
||||
|
||||
import java.util.Optional; |
||||
import java.util.concurrent.CompletableFuture; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes32; |
||||
|
||||
public class RetryingGetAccountRangeFromPeerTask |
||||
extends AbstractRetryingPeerTask<AccountRangeMessage.AccountRangeData> { |
||||
|
||||
private final EthContext ethContext; |
||||
private final Bytes32 startKeyHash; |
||||
private final Bytes32 endKeyHash; |
||||
private final BlockHeader blockHeader; |
||||
private final MetricsSystem metricsSystem; |
||||
|
||||
private RetryingGetAccountRangeFromPeerTask( |
||||
final EthContext ethContext, |
||||
final Bytes32 startKeyHash, |
||||
final Bytes32 endKeyHash, |
||||
final BlockHeader blockHeader, |
||||
final MetricsSystem metricsSystem) { |
||||
super( |
||||
ethContext, 3, data -> data.accounts().isEmpty() && data.proofs().isEmpty(), metricsSystem); |
||||
this.ethContext = ethContext; |
||||
this.startKeyHash = startKeyHash; |
||||
this.endKeyHash = endKeyHash; |
||||
this.blockHeader = blockHeader; |
||||
this.metricsSystem = metricsSystem; |
||||
} |
||||
|
||||
public static EthTask<AccountRangeMessage.AccountRangeData> forAccountRange( |
||||
final EthContext ethContext, |
||||
final Bytes32 startKeyHash, |
||||
final Bytes32 endKeyHash, |
||||
final BlockHeader blockHeader, |
||||
final MetricsSystem metricsSystem) { |
||||
return new RetryingGetAccountRangeFromPeerTask( |
||||
ethContext, startKeyHash, endKeyHash, blockHeader, metricsSystem); |
||||
} |
||||
|
||||
@Override |
||||
protected CompletableFuture<AccountRangeMessage.AccountRangeData> executePeerTask( |
||||
final Optional<EthPeer> assignedPeer) { |
||||
final GetAccountRangeFromPeerTask task = |
||||
GetAccountRangeFromPeerTask.forAccountRange( |
||||
ethContext, startKeyHash, endKeyHash, blockHeader, metricsSystem); |
||||
assignedPeer.ifPresent(task::assignPeer); |
||||
return executeSubTask(task::run) |
||||
.thenApply( |
||||
peerResult -> { |
||||
result.complete(peerResult.getResult()); |
||||
return peerResult.getResult(); |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,72 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.eth.manager.snap; |
||||
|
||||
import org.hyperledger.besu.ethereum.core.BlockHeader; |
||||
import org.hyperledger.besu.ethereum.eth.manager.EthContext; |
||||
import org.hyperledger.besu.ethereum.eth.manager.EthPeer; |
||||
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractRetryingPeerTask; |
||||
import org.hyperledger.besu.ethereum.eth.manager.task.EthTask; |
||||
import org.hyperledger.besu.plugin.services.MetricsSystem; |
||||
|
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Optional; |
||||
import java.util.concurrent.CompletableFuture; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes; |
||||
import org.apache.tuweni.bytes.Bytes32; |
||||
|
||||
public class RetryingGetBytecodeFromPeerTask extends AbstractRetryingPeerTask<Map<Bytes32, Bytes>> { |
||||
|
||||
private final EthContext ethContext; |
||||
private final List<Bytes32> codeHashes; |
||||
private final BlockHeader blockHeader; |
||||
private final MetricsSystem metricsSystem; |
||||
|
||||
private RetryingGetBytecodeFromPeerTask( |
||||
final EthContext ethContext, |
||||
final List<Bytes32> codeHashes, |
||||
final BlockHeader blockHeader, |
||||
final MetricsSystem metricsSystem) { |
||||
super(ethContext, 3, Map::isEmpty, metricsSystem); |
||||
this.ethContext = ethContext; |
||||
this.codeHashes = codeHashes; |
||||
this.blockHeader = blockHeader; |
||||
this.metricsSystem = metricsSystem; |
||||
} |
||||
|
||||
public static EthTask<Map<Bytes32, Bytes>> forByteCode( |
||||
final EthContext ethContext, |
||||
final List<Bytes32> codeHashes, |
||||
final BlockHeader blockHeader, |
||||
final MetricsSystem metricsSystem) { |
||||
return new RetryingGetBytecodeFromPeerTask(ethContext, codeHashes, blockHeader, metricsSystem); |
||||
} |
||||
|
||||
@Override |
||||
protected CompletableFuture<Map<Bytes32, Bytes>> executePeerTask( |
||||
final Optional<EthPeer> assignedPeer) { |
||||
final GetBytecodeFromPeerTask task = |
||||
GetBytecodeFromPeerTask.forBytecode(ethContext, codeHashes, blockHeader, metricsSystem); |
||||
assignedPeer.ifPresent(task::assignPeer); |
||||
return executeSubTask(task::run) |
||||
.thenApply( |
||||
peerResult -> { |
||||
result.complete(peerResult.getResult()); |
||||
return peerResult.getResult(); |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,82 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.eth.manager.snap; |
||||
|
||||
import org.hyperledger.besu.ethereum.core.BlockHeader; |
||||
import org.hyperledger.besu.ethereum.eth.manager.EthContext; |
||||
import org.hyperledger.besu.ethereum.eth.manager.EthPeer; |
||||
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractRetryingPeerTask; |
||||
import org.hyperledger.besu.ethereum.eth.manager.task.EthTask; |
||||
import org.hyperledger.besu.ethereum.eth.messages.snap.StorageRangeMessage; |
||||
import org.hyperledger.besu.plugin.services.MetricsSystem; |
||||
|
||||
import java.util.List; |
||||
import java.util.Optional; |
||||
import java.util.concurrent.CompletableFuture; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes32; |
||||
|
||||
public class RetryingGetStorageRangeFromPeerTask |
||||
extends AbstractRetryingPeerTask<StorageRangeMessage.SlotRangeData> { |
||||
|
||||
private final EthContext ethContext; |
||||
private final List<Bytes32> accountHashes; |
||||
private final Bytes32 startKeyHash; |
||||
private final Bytes32 endKeyHash; |
||||
private final BlockHeader blockHeader; |
||||
private final MetricsSystem metricsSystem; |
||||
|
||||
private RetryingGetStorageRangeFromPeerTask( |
||||
final EthContext ethContext, |
||||
final List<Bytes32> accountHashes, |
||||
final Bytes32 startKeyHash, |
||||
final Bytes32 endKeyHash, |
||||
final BlockHeader blockHeader, |
||||
final MetricsSystem metricsSystem) { |
||||
super(ethContext, 3, data -> data.proofs().isEmpty() && data.slots().isEmpty(), metricsSystem); |
||||
this.ethContext = ethContext; |
||||
this.accountHashes = accountHashes; |
||||
this.startKeyHash = startKeyHash; |
||||
this.endKeyHash = endKeyHash; |
||||
this.blockHeader = blockHeader; |
||||
this.metricsSystem = metricsSystem; |
||||
} |
||||
|
||||
public static EthTask<StorageRangeMessage.SlotRangeData> forStorageRange( |
||||
final EthContext ethContext, |
||||
final List<Bytes32> accountHashes, |
||||
final Bytes32 startKeyHash, |
||||
final Bytes32 endKeyHash, |
||||
final BlockHeader blockHeader, |
||||
final MetricsSystem metricsSystem) { |
||||
return new RetryingGetStorageRangeFromPeerTask( |
||||
ethContext, accountHashes, startKeyHash, endKeyHash, blockHeader, metricsSystem); |
||||
} |
||||
|
||||
@Override |
||||
protected CompletableFuture<StorageRangeMessage.SlotRangeData> executePeerTask( |
||||
final Optional<EthPeer> assignedPeer) { |
||||
final GetStorageRangeFromPeerTask task = |
||||
GetStorageRangeFromPeerTask.forStorageRange( |
||||
ethContext, accountHashes, startKeyHash, endKeyHash, blockHeader, metricsSystem); |
||||
assignedPeer.ifPresent(task::assignPeer); |
||||
return executeSubTask(task::run) |
||||
.thenApply( |
||||
peerResult -> { |
||||
result.complete(peerResult.getResult()); |
||||
return peerResult.getResult(); |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,71 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.eth.manager.snap; |
||||
|
||||
import org.hyperledger.besu.ethereum.core.BlockHeader; |
||||
import org.hyperledger.besu.ethereum.eth.manager.EthContext; |
||||
import org.hyperledger.besu.ethereum.eth.manager.EthPeer; |
||||
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractRetryingPeerTask; |
||||
import org.hyperledger.besu.ethereum.eth.manager.task.EthTask; |
||||
import org.hyperledger.besu.plugin.services.MetricsSystem; |
||||
|
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Optional; |
||||
import java.util.concurrent.CompletableFuture; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes; |
||||
|
||||
public class RetryingGetTrieNodeFromPeerTask extends AbstractRetryingPeerTask<Map<Bytes, Bytes>> { |
||||
|
||||
private final EthContext ethContext; |
||||
private final Map<Bytes, List<Bytes>> paths; |
||||
private final BlockHeader blockHeader; |
||||
private final MetricsSystem metricsSystem; |
||||
|
||||
private RetryingGetTrieNodeFromPeerTask( |
||||
final EthContext ethContext, |
||||
final Map<Bytes, List<Bytes>> paths, |
||||
final BlockHeader blockHeader, |
||||
final MetricsSystem metricsSystem) { |
||||
super(ethContext, 3, Map::isEmpty, metricsSystem); |
||||
this.ethContext = ethContext; |
||||
this.paths = paths; |
||||
this.blockHeader = blockHeader; |
||||
this.metricsSystem = metricsSystem; |
||||
} |
||||
|
||||
public static EthTask<Map<Bytes, Bytes>> forTrieNodes( |
||||
final EthContext ethContext, |
||||
final Map<Bytes, List<Bytes>> paths, |
||||
final BlockHeader blockHeader, |
||||
final MetricsSystem metricsSystem) { |
||||
return new RetryingGetTrieNodeFromPeerTask(ethContext, paths, blockHeader, metricsSystem); |
||||
} |
||||
|
||||
@Override |
||||
protected CompletableFuture<Map<Bytes, Bytes>> executePeerTask( |
||||
final Optional<EthPeer> assignedPeer) { |
||||
final GetTrieNodeFromPeerTask task = |
||||
GetTrieNodeFromPeerTask.forTrieNodes(ethContext, paths, blockHeader, metricsSystem); |
||||
assignedPeer.ifPresent(task::assignPeer); |
||||
return executeSubTask(task::run) |
||||
.thenApply( |
||||
peerResult -> { |
||||
result.complete(peerResult.getResult()); |
||||
return peerResult.getResult(); |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,142 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.eth.sync.snapsync; |
||||
|
||||
import org.hyperledger.besu.datatypes.Hash; |
||||
import org.hyperledger.besu.ethereum.trie.InnerNodeDiscoveryManager; |
||||
import org.hyperledger.besu.ethereum.trie.MerkleTrieException; |
||||
import org.hyperledger.besu.ethereum.trie.StoredMerklePatriciaTrie; |
||||
|
||||
import java.math.BigInteger; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Optional; |
||||
import java.util.TreeMap; |
||||
import java.util.function.Function; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes; |
||||
import org.apache.tuweni.bytes.Bytes32; |
||||
|
||||
/** |
||||
* This class helps to generate ranges according to several parameters (the start and the end of the |
||||
* range, its size) |
||||
*/ |
||||
public class RangeManager { |
||||
|
||||
public static final Hash MIN_RANGE = |
||||
Hash.fromHexString("0x0000000000000000000000000000000000000000000000000000000000000000"); |
||||
public static final Hash MAX_RANGE = |
||||
Hash.fromHexString("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); |
||||
|
||||
private RangeManager() {} |
||||
|
||||
public static Map<Bytes32, Bytes32> generateAllRanges(final int sizeRange) { |
||||
if (sizeRange == 1) { |
||||
return Map.ofEntries(Map.entry(MIN_RANGE, MAX_RANGE)); |
||||
} |
||||
return generateRanges( |
||||
MIN_RANGE.toUnsignedBigInteger(), MAX_RANGE.toUnsignedBigInteger(), sizeRange); |
||||
} |
||||
|
||||
/** |
||||
* Generate a range |
||||
* |
||||
* @param min start of the range in bytes |
||||
* @param max the max end of the range in bytes |
||||
* @param nbRange number of ranges |
||||
* @return the start and end of the generated range |
||||
*/ |
||||
public static Map<Bytes32, Bytes32> generateRanges( |
||||
final Bytes32 min, final Bytes32 max, final int nbRange) { |
||||
return generateRanges(min.toUnsignedBigInteger(), max.toUnsignedBigInteger(), nbRange); |
||||
} |
||||
|
||||
/** |
||||
* Generate a range |
||||
* |
||||
* @param min start of the range |
||||
* @param max the max end of the range |
||||
* @param nbRange number of ranges |
||||
* @return the start and end of the generated range |
||||
*/ |
||||
public static Map<Bytes32, Bytes32> generateRanges( |
||||
final BigInteger min, final BigInteger max, final int nbRange) { |
||||
final BigInteger rangeSize = max.subtract(min).divide(BigInteger.valueOf(nbRange)); |
||||
final TreeMap<Bytes32, Bytes32> ranges = new TreeMap<>(); |
||||
if (min.equals(max) || nbRange == 1) { |
||||
ranges.put(format(min), format(max)); |
||||
return ranges; |
||||
} |
||||
BigInteger currentStart = min; |
||||
BigInteger currentEnd = min; |
||||
while (max.subtract(currentEnd).compareTo(rangeSize) > 0) { |
||||
currentEnd = currentStart.add(rangeSize); |
||||
ranges.put(format(currentStart), format(currentEnd)); |
||||
currentStart = currentStart.add(rangeSize).add(BigInteger.ONE); |
||||
} |
||||
if (max.subtract(currentEnd).compareTo(BigInteger.ZERO) > 0) { |
||||
currentEnd = currentStart.add(max.subtract(currentEnd)).subtract(BigInteger.ONE); |
||||
ranges.put(format(currentStart), format(currentEnd)); |
||||
} |
||||
return ranges; |
||||
} |
||||
|
||||
/** |
||||
* Helps to create a new range according to the last data obtained. This happens when a peer |
||||
* doesn't return all of the data in a range. |
||||
* |
||||
* @param worldstateRootHash the root hash |
||||
* @param proofs proof received |
||||
* @param endKeyHash the end of the range initially wanted |
||||
* @param receivedKeys the last key received |
||||
* @return begin of the new range |
||||
*/ |
||||
public static Optional<Bytes32> findNewBeginElementInRange( |
||||
final Bytes32 worldstateRootHash, |
||||
final List<Bytes> proofs, |
||||
final TreeMap<Bytes32, Bytes> receivedKeys, |
||||
final Bytes32 endKeyHash) { |
||||
if (receivedKeys.isEmpty() || receivedKeys.lastKey().compareTo(endKeyHash) >= 0) { |
||||
return Optional.empty(); |
||||
} else { |
||||
final Map<Bytes32, Bytes> proofsEntries = new HashMap<>(); |
||||
for (Bytes proof : proofs) { |
||||
proofsEntries.put(Hash.hash(proof), proof); |
||||
} |
||||
final StoredMerklePatriciaTrie<Bytes, Bytes> storageTrie = |
||||
new StoredMerklePatriciaTrie<>( |
||||
new InnerNodeDiscoveryManager<>( |
||||
(location, key) -> Optional.ofNullable(proofsEntries.get(key)), |
||||
Function.identity(), |
||||
Function.identity(), |
||||
receivedKeys.lastKey(), |
||||
endKeyHash, |
||||
false), |
||||
worldstateRootHash); |
||||
|
||||
try { |
||||
storageTrie.visitAll(bytesNode -> {}); |
||||
} catch (MerkleTrieException e) { |
||||
return Optional.of(InnerNodeDiscoveryManager.decodePath(e.getLocation())); |
||||
} |
||||
return Optional.empty(); |
||||
} |
||||
} |
||||
|
||||
private static Bytes32 format(final BigInteger data) { |
||||
return Bytes32.leftPad(Bytes.of(data.toByteArray()).trimLeadingZeros()); |
||||
} |
||||
} |
@ -0,0 +1,57 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.eth.messages.snap; |
||||
|
||||
import org.hyperledger.besu.datatypes.Hash; |
||||
import org.hyperledger.besu.datatypes.Wei; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.RawMessage; |
||||
import org.hyperledger.besu.ethereum.rlp.RLP; |
||||
import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes; |
||||
import org.apache.tuweni.bytes.Bytes32; |
||||
import org.assertj.core.api.Assertions; |
||||
import org.junit.Test; |
||||
|
||||
public final class AccountRangeMessageTest { |
||||
|
||||
@Test |
||||
public void roundTripTest() { |
||||
final Map<Bytes32, Bytes> keys = new HashMap<>(); |
||||
final StateTrieAccountValue accountValue = |
||||
new StateTrieAccountValue(1L, Wei.of(2L), Hash.EMPTY_TRIE_HASH, Hash.EMPTY); |
||||
keys.put(Hash.wrap(Bytes32.leftPad(Bytes.of(1))), RLP.encode(accountValue::writeTo)); |
||||
|
||||
final List<Bytes> proofs = new ArrayList<>(); |
||||
proofs.add(Bytes32.random()); |
||||
|
||||
// Perform round-trip transformation
|
||||
final MessageData initialMessage = AccountRangeMessage.create(keys, proofs); |
||||
final MessageData raw = new RawMessage(SnapV1.ACCOUNT_RANGE, initialMessage.getData()); |
||||
|
||||
final AccountRangeMessage message = AccountRangeMessage.readFrom(raw); |
||||
|
||||
// check match originals.
|
||||
final AccountRangeMessage.AccountRangeData range = message.accountData(false); |
||||
Assertions.assertThat(range.accounts()).isEqualTo(keys); |
||||
Assertions.assertThat(range.proofs()).isEqualTo(proofs); |
||||
} |
||||
} |
@ -0,0 +1,49 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.eth.messages.snap; |
||||
|
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.RawMessage; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes; |
||||
import org.apache.tuweni.bytes.Bytes32; |
||||
import org.assertj.core.api.Assertions; |
||||
import org.junit.Test; |
||||
|
||||
public final class BytecodeMessageTest { |
||||
|
||||
@Test |
||||
public void roundTripTest() { |
||||
|
||||
final List<Bytes> codes = new ArrayList<>(); |
||||
final int hashCount = 20; |
||||
for (int i = 0; i < hashCount; ++i) { |
||||
codes.add(Bytes32.random()); |
||||
} |
||||
|
||||
// Perform round-trip transformation
|
||||
final MessageData initialMessage = ByteCodesMessage.create(codes); |
||||
final MessageData raw = new RawMessage(SnapV1.BYTECODES, initialMessage.getData()); |
||||
|
||||
final ByteCodesMessage message = ByteCodesMessage.readFrom(raw); |
||||
|
||||
// check match originals.
|
||||
final ByteCodesMessage.ByteCodes response = message.bytecodes(false); |
||||
Assertions.assertThat(response.codes()).isEqualTo(codes); |
||||
} |
||||
} |
@ -0,0 +1,48 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.eth.messages.snap; |
||||
|
||||
import org.hyperledger.besu.datatypes.Hash; |
||||
import org.hyperledger.besu.ethereum.eth.sync.snapsync.RangeManager; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.AbstractSnapMessageData; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.RawMessage; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes32; |
||||
import org.assertj.core.api.Assertions; |
||||
import org.junit.Test; |
||||
|
||||
public final class GetAccountRangeMessageTest { |
||||
|
||||
@Test |
||||
public void roundTripTest() { |
||||
final Hash rootHash = Hash.wrap(Bytes32.random()); |
||||
final Hash startKeyHash = RangeManager.MIN_RANGE; |
||||
final Hash endKeyHash = RangeManager.MAX_RANGE; |
||||
|
||||
// Perform round-trip transformation
|
||||
final MessageData initialMessage = |
||||
GetAccountRangeMessage.create(rootHash, startKeyHash, endKeyHash); |
||||
final MessageData raw = new RawMessage(SnapV1.GET_ACCOUNT_RANGE, initialMessage.getData()); |
||||
|
||||
final GetAccountRangeMessage message = GetAccountRangeMessage.readFrom(raw); |
||||
|
||||
// check match originals.
|
||||
final GetAccountRangeMessage.Range range = message.range(false); |
||||
Assertions.assertThat(range.worldStateRootHash()).isEqualTo(rootHash); |
||||
Assertions.assertThat(range.startKeyHash()).isEqualTo(startKeyHash); |
||||
Assertions.assertThat(range.responseBytes()).isEqualTo(AbstractSnapMessageData.SIZE_REQUEST); |
||||
} |
||||
} |
@ -0,0 +1,51 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.eth.messages.snap; |
||||
|
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.AbstractSnapMessageData; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.RawMessage; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes32; |
||||
import org.assertj.core.api.Assertions; |
||||
import org.junit.Test; |
||||
|
||||
public final class GetBytecodeMessageTest { |
||||
|
||||
@Test |
||||
public void roundTripTest() { |
||||
|
||||
final List<Bytes32> hashes = new ArrayList<>(); |
||||
final int hashCount = 20; |
||||
for (int i = 0; i < hashCount; ++i) { |
||||
hashes.add(Bytes32.random()); |
||||
} |
||||
|
||||
// Perform round-trip transformation
|
||||
final MessageData initialMessage = GetByteCodesMessage.create(hashes); |
||||
final MessageData raw = new RawMessage(SnapV1.GET_BYTECODES, initialMessage.getData()); |
||||
|
||||
final GetByteCodesMessage message = GetByteCodesMessage.readFrom(raw); |
||||
|
||||
// check match originals.
|
||||
final GetByteCodesMessage.CodeHashes codeHashes = message.codeHashes(false); |
||||
Assertions.assertThat(codeHashes.hashes()).isEqualTo(hashes); |
||||
Assertions.assertThat(codeHashes.responseBytes()) |
||||
.isEqualTo(AbstractSnapMessageData.SIZE_REQUEST); |
||||
} |
||||
} |
@ -0,0 +1,52 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.eth.messages.snap; |
||||
|
||||
import org.hyperledger.besu.datatypes.Hash; |
||||
import org.hyperledger.besu.ethereum.eth.sync.snapsync.RangeManager; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.AbstractSnapMessageData; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.RawMessage; |
||||
|
||||
import java.util.List; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes32; |
||||
import org.assertj.core.api.Assertions; |
||||
import org.junit.Test; |
||||
|
||||
public final class GetStorageRangeMessageTest { |
||||
|
||||
@Test |
||||
public void roundTripTest() { |
||||
final Hash rootHash = Hash.wrap(Bytes32.random()); |
||||
final List<Bytes32> accountKeys = List.of(Bytes32.random()); |
||||
final Hash startKeyHash = RangeManager.MIN_RANGE; |
||||
final Hash endKeyHash = RangeManager.MAX_RANGE; |
||||
|
||||
// Perform round-trip transformation
|
||||
final MessageData initialMessage = |
||||
GetStorageRangeMessage.create(rootHash, accountKeys, startKeyHash, endKeyHash); |
||||
final MessageData raw = new RawMessage(SnapV1.GET_STORAGE_RANGE, initialMessage.getData()); |
||||
|
||||
final GetStorageRangeMessage message = GetStorageRangeMessage.readFrom(raw); |
||||
|
||||
// check match originals.
|
||||
final GetStorageRangeMessage.StorageRange range = message.range(false); |
||||
Assertions.assertThat(range.worldStateRootHash()).isEqualTo(rootHash); |
||||
Assertions.assertThat(range.hashes()).isEqualTo(accountKeys); |
||||
Assertions.assertThat(range.startKeyHash()).isEqualTo(startKeyHash); |
||||
Assertions.assertThat(range.responseBytes()).isEqualTo(AbstractSnapMessageData.SIZE_REQUEST); |
||||
} |
||||
} |
@ -0,0 +1,53 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.eth.messages.snap; |
||||
|
||||
import org.hyperledger.besu.datatypes.Hash; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.AbstractSnapMessageData; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.RawMessage; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes; |
||||
import org.apache.tuweni.bytes.Bytes32; |
||||
import org.assertj.core.api.Assertions; |
||||
import org.junit.Test; |
||||
|
||||
public final class GetTrieNodeMessageTest { |
||||
|
||||
@Test |
||||
public void roundTripTest() { |
||||
final Hash rootHash = Hash.wrap(Bytes32.random()); |
||||
final List<Bytes> paths = new ArrayList<>(); |
||||
final int hashCount = 20; |
||||
for (int i = 0; i < hashCount; ++i) { |
||||
paths.add(Bytes32.random()); |
||||
} |
||||
|
||||
// Perform round-trip transformation
|
||||
final MessageData initialMessage = GetTrieNodesMessage.create(rootHash, List.of(paths)); |
||||
final MessageData raw = new RawMessage(SnapV1.GET_TRIE_NODES, initialMessage.getData()); |
||||
|
||||
final GetTrieNodesMessage message = GetTrieNodesMessage.readFrom(raw); |
||||
|
||||
// check match originals.
|
||||
final GetTrieNodesMessage.TrieNodesPaths response = message.paths(false); |
||||
Assertions.assertThat(response.worldStateRootHash()).isEqualTo(rootHash); |
||||
Assertions.assertThat(response.paths()).contains(paths); |
||||
Assertions.assertThat(response.responseBytes()).isEqualTo(AbstractSnapMessageData.SIZE_REQUEST); |
||||
} |
||||
} |
@ -0,0 +1,56 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.eth.messages.snap; |
||||
|
||||
import org.hyperledger.besu.datatypes.Hash; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.RawMessage; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import kotlin.collections.ArrayDeque; |
||||
import org.apache.tuweni.bytes.Bytes; |
||||
import org.apache.tuweni.bytes.Bytes32; |
||||
import org.assertj.core.api.Assertions; |
||||
import org.junit.Test; |
||||
|
||||
public final class StorageRangeMessageTest { |
||||
|
||||
@Test |
||||
public void roundTripTest() { |
||||
|
||||
final ArrayDeque<Map<Bytes32, Bytes>> keys = new ArrayDeque<>(); |
||||
final Map<Bytes32, Bytes> storage = new HashMap<>(); |
||||
storage.put(Hash.wrap(Bytes32.leftPad(Bytes.of(1))), Bytes32.random()); |
||||
keys.add(storage); |
||||
|
||||
final List<Bytes> proofs = new ArrayList<>(); |
||||
proofs.add(Bytes32.random()); |
||||
|
||||
// Perform round-trip transformation
|
||||
final MessageData initialMessage = StorageRangeMessage.create(keys, proofs); |
||||
final MessageData raw = new RawMessage(SnapV1.STORAGE_RANGE, initialMessage.getData()); |
||||
|
||||
final StorageRangeMessage message = StorageRangeMessage.readFrom(raw); |
||||
|
||||
// check match originals.
|
||||
final StorageRangeMessage.SlotRangeData range = message.slotsData(false); |
||||
Assertions.assertThat(range.slots()).isEqualTo(keys); |
||||
Assertions.assertThat(range.proofs()).isEqualTo(proofs); |
||||
} |
||||
} |
@ -0,0 +1,49 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.eth.messages.snap; |
||||
|
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; |
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.RawMessage; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import kotlin.collections.ArrayDeque; |
||||
import org.apache.tuweni.bytes.Bytes; |
||||
import org.apache.tuweni.bytes.Bytes32; |
||||
import org.assertj.core.api.Assertions; |
||||
import org.junit.Test; |
||||
|
||||
public final class TrieNodeMessageTest { |
||||
|
||||
@Test |
||||
public void roundTripTest() { |
||||
final List<Bytes> nodes = new ArrayList<>(); |
||||
final int hashCount = 20; |
||||
for (int i = 0; i < hashCount; ++i) { |
||||
nodes.add(Bytes32.random()); |
||||
} |
||||
|
||||
// Perform round-trip transformation
|
||||
final MessageData initialMessage = TrieNodesMessage.create(nodes); |
||||
final MessageData raw = new RawMessage(SnapV1.TRIE_NODES, initialMessage.getData()); |
||||
|
||||
final TrieNodesMessage message = TrieNodesMessage.readFrom(raw); |
||||
|
||||
// check match originals.
|
||||
final ArrayDeque<Bytes> response = message.nodes(false); |
||||
Assertions.assertThat(response).isEqualTo(nodes); |
||||
} |
||||
} |
@ -0,0 +1,174 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.eth.sync.snapsync; |
||||
|
||||
import org.hyperledger.besu.datatypes.Hash; |
||||
import org.hyperledger.besu.ethereum.core.TrieGenerator; |
||||
import org.hyperledger.besu.ethereum.proof.WorldStateProofProvider; |
||||
import org.hyperledger.besu.ethereum.storage.keyvalue.WorldStateKeyValueStorage; |
||||
import org.hyperledger.besu.ethereum.trie.MerklePatriciaTrie; |
||||
import org.hyperledger.besu.ethereum.trie.RangeStorageEntriesCollector; |
||||
import org.hyperledger.besu.ethereum.trie.TrieIterator; |
||||
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; |
||||
import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Optional; |
||||
import java.util.TreeMap; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes; |
||||
import org.apache.tuweni.bytes.Bytes32; |
||||
import org.assertj.core.api.Assertions; |
||||
import org.junit.Test; |
||||
|
||||
public final class RangeManagerTest { |
||||
|
||||
@Test |
||||
public void testGenerateAllRangesWithSize1() { |
||||
final Map<Bytes32, Bytes32> expectedResult = new HashMap<>(); |
||||
expectedResult.put( |
||||
Bytes32.fromHexString("0x0000000000000000000000000000000000000000000000000000000000000000"), |
||||
Bytes32.fromHexString( |
||||
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); |
||||
final Map<Bytes32, Bytes32> ranges = RangeManager.generateAllRanges(1); |
||||
Assertions.assertThat(ranges.size()).isEqualTo(1); |
||||
Assertions.assertThat(ranges).isEqualTo(expectedResult); |
||||
} |
||||
|
||||
@Test |
||||
public void testGenerateAllRangesWithSize3() { |
||||
final Map<Bytes32, Bytes32> expectedResult = new HashMap<>(); |
||||
expectedResult.put( |
||||
Bytes32.fromHexString("0x0000000000000000000000000000000000000000000000000000000000000000"), |
||||
Bytes32.fromHexString( |
||||
"0x5555555555555555555555555555555555555555555555555555555555555555")); |
||||
expectedResult.put( |
||||
Bytes32.fromHexString("0x5555555555555555555555555555555555555555555555555555555555555556"), |
||||
Bytes32.fromHexString( |
||||
"0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab")); |
||||
expectedResult.put( |
||||
Bytes32.fromHexString("0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac"), |
||||
Bytes32.fromHexString( |
||||
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); |
||||
final Map<Bytes32, Bytes32> ranges = RangeManager.generateAllRanges(3); |
||||
Assertions.assertThat(ranges.size()).isEqualTo(3); |
||||
Assertions.assertThat(ranges).isEqualTo(expectedResult); |
||||
} |
||||
|
||||
@Test |
||||
public void testGenerateRangesWithSize3() { |
||||
final Map<Bytes32, Bytes32> expectedResult = new HashMap<>(); |
||||
expectedResult.put( |
||||
Bytes32.fromHexString("0x0000000000000000000000000000000000000000000000000000000000000000"), |
||||
Bytes32.fromHexString( |
||||
"0x5555555555555555555555555555555555555555555555555555555555555555")); |
||||
expectedResult.put( |
||||
Bytes32.fromHexString("0x5555555555555555555555555555555555555555555555555555555555555556"), |
||||
Bytes32.fromHexString( |
||||
"0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab")); |
||||
expectedResult.put( |
||||
Bytes32.fromHexString("0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac"), |
||||
Bytes32.fromHexString( |
||||
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); |
||||
final Map<Bytes32, Bytes32> ranges = |
||||
RangeManager.generateRanges( |
||||
Bytes32.fromHexString( |
||||
"0x0000000000000000000000000000000000000000000000000000000000000000"), |
||||
Bytes32.fromHexString( |
||||
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), |
||||
3); |
||||
Assertions.assertThat(ranges.size()).isEqualTo(3); |
||||
Assertions.assertThat(ranges).isEqualTo(expectedResult); |
||||
} |
||||
|
||||
@Test |
||||
public void testFindNewBeginElement() { |
||||
|
||||
final WorldStateStorage worldStateStorage = |
||||
new WorldStateKeyValueStorage(new InMemoryKeyValueStorage()); |
||||
|
||||
final MerklePatriciaTrie<Bytes32, Bytes> accountStateTrie = |
||||
TrieGenerator.generateTrie(worldStateStorage, 15); |
||||
|
||||
final RangeStorageEntriesCollector collector = |
||||
RangeStorageEntriesCollector.createCollector( |
||||
Hash.ZERO, RangeManager.MAX_RANGE, 10, Integer.MAX_VALUE); |
||||
final TrieIterator<Bytes> visitor = RangeStorageEntriesCollector.createVisitor(collector); |
||||
final TreeMap<Bytes32, Bytes> accounts = |
||||
(TreeMap<Bytes32, Bytes>) |
||||
accountStateTrie.entriesFrom( |
||||
root -> |
||||
RangeStorageEntriesCollector.collectEntries( |
||||
collector, visitor, root, Hash.ZERO)); |
||||
|
||||
final WorldStateProofProvider worldStateProofProvider = |
||||
new WorldStateProofProvider(worldStateStorage); |
||||
|
||||
// generate the proof
|
||||
final List<Bytes> proofs = |
||||
worldStateProofProvider.getAccountProofRelatedNodes( |
||||
Hash.wrap(accountStateTrie.getRootHash()), Hash.ZERO); |
||||
proofs.addAll( |
||||
worldStateProofProvider.getAccountProofRelatedNodes( |
||||
Hash.wrap(accountStateTrie.getRootHash()), accounts.lastKey())); |
||||
|
||||
final Optional<Bytes32> newBeginElementInRange = |
||||
RangeManager.findNewBeginElementInRange( |
||||
accountStateTrie.getRootHash(), proofs, accounts, RangeManager.MAX_RANGE); |
||||
|
||||
Assertions.assertThat(newBeginElementInRange) |
||||
.contains(Bytes32.leftPad(Bytes.wrap(Bytes.ofUnsignedShort(0x0b)))); |
||||
} |
||||
|
||||
@Test |
||||
public void testFindNewBeginElementWhenNothingIsMissing() { |
||||
|
||||
final WorldStateStorage worldStateStorage = |
||||
new WorldStateKeyValueStorage(new InMemoryKeyValueStorage()); |
||||
|
||||
final MerklePatriciaTrie<Bytes32, Bytes> accountStateTrie = |
||||
TrieGenerator.generateTrie(worldStateStorage, 15); |
||||
|
||||
final RangeStorageEntriesCollector collector = |
||||
RangeStorageEntriesCollector.createCollector( |
||||
Hash.ZERO, RangeManager.MAX_RANGE, 15, Integer.MAX_VALUE); |
||||
final TrieIterator<Bytes> visitor = RangeStorageEntriesCollector.createVisitor(collector); |
||||
final TreeMap<Bytes32, Bytes> accounts = |
||||
(TreeMap<Bytes32, Bytes>) |
||||
accountStateTrie.entriesFrom( |
||||
root -> |
||||
RangeStorageEntriesCollector.collectEntries( |
||||
collector, visitor, root, Hash.ZERO)); |
||||
|
||||
final WorldStateProofProvider worldStateProofProvider = |
||||
new WorldStateProofProvider(worldStateStorage); |
||||
|
||||
// generate the proof
|
||||
final List<Bytes> proofs = |
||||
worldStateProofProvider.getAccountProofRelatedNodes( |
||||
Hash.wrap(accountStateTrie.getRootHash()), Hash.ZERO); |
||||
proofs.addAll( |
||||
worldStateProofProvider.getAccountProofRelatedNodes( |
||||
Hash.wrap(accountStateTrie.getRootHash()), accounts.lastKey())); |
||||
|
||||
final Optional<Bytes32> newBeginElementInRange = |
||||
RangeManager.findNewBeginElementInRange( |
||||
accountStateTrie.getRootHash(), proofs, accounts, RangeManager.MAX_RANGE); |
||||
|
||||
Assertions.assertThat(newBeginElementInRange).isEmpty(); |
||||
} |
||||
} |
Loading…
Reference in new issue