mirror of https://github.com/hyperledger/besu
commit
bc11e0c8bb
@ -0,0 +1,49 @@ |
|||||||
|
#!/bin/bash |
||||||
|
## |
||||||
|
## 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 |
||||||
|
## |
||||||
|
|
||||||
|
# Run Besu first to get paths needing permission adjustment |
||||||
|
output=$(/opt/besu/bin/besu --print-paths-and-exit $BESU_USER_NAME "$@") |
||||||
|
|
||||||
|
# Parse the output to find the paths and their required access types |
||||||
|
echo "$output" | while IFS=: read -r prefix path accessType; do |
||||||
|
if [[ "$prefix" == "PERMISSION_CHECK_PATH" ]]; then |
||||||
|
# Change ownership to besu user and group |
||||||
|
chown -R $BESU_USER_NAME:$BESU_USER_NAME $path |
||||||
|
|
||||||
|
# Ensure read/write permissions for besu user |
||||||
|
|
||||||
|
echo "Setting permissions for: $path with access: $accessType" |
||||||
|
|
||||||
|
if [[ "$accessType" == "READ" ]]; then |
||||||
|
# Set read-only permissions for besu user |
||||||
|
# Add execute for directories to allow access |
||||||
|
find $path -type d -exec chmod u+rx {} \; |
||||||
|
find $path -type f -exec chmod u+r {} \; |
||||||
|
elif [[ "$accessType" == "READ_WRITE" ]]; then |
||||||
|
# Set read/write permissions for besu user |
||||||
|
# Add execute for directories to allow access |
||||||
|
find $path -type d -exec chmod u+rwx {} \; |
||||||
|
find $path -type f -exec chmod u+rw {} \; |
||||||
|
fi |
||||||
|
fi |
||||||
|
done |
||||||
|
|
||||||
|
# Finally, run Besu with the actual arguments passed to the container |
||||||
|
# Construct the command as a single string |
||||||
|
COMMAND="/opt/besu/bin/besu $@" |
||||||
|
|
||||||
|
# Switch to the besu user and execute the command |
||||||
|
exec su -s /bin/bash $BESU_USER_NAME -c "$COMMAND" |
@ -0,0 +1,10 @@ |
|||||||
|
--- |
||||||
|
# runtime docker tests |
||||||
|
file: |
||||||
|
/var/lib/besu: |
||||||
|
exists: true |
||||||
|
owner: besu |
||||||
|
mode: "0755" |
||||||
|
process: |
||||||
|
java: |
||||||
|
running: true |
@ -0,0 +1,495 @@ |
|||||||
|
/* |
||||||
|
* 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 org.assertj.core.api.AssertionsForClassTypes.assertThat; |
||||||
|
|
||||||
|
import org.hyperledger.besu.datatypes.Hash; |
||||||
|
import org.hyperledger.besu.ethereum.ProtocolContext; |
||||||
|
import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; |
||||||
|
import org.hyperledger.besu.ethereum.eth.manager.EthMessages; |
||||||
|
import org.hyperledger.besu.ethereum.eth.messages.snap.AccountRangeMessage; |
||||||
|
import org.hyperledger.besu.ethereum.eth.messages.snap.GetAccountRangeMessage; |
||||||
|
import org.hyperledger.besu.ethereum.eth.sync.snapsync.ImmutableSnapSyncConfiguration; |
||||||
|
import org.hyperledger.besu.ethereum.eth.sync.snapsync.SnapSyncConfiguration; |
||||||
|
import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; |
||||||
|
import org.hyperledger.besu.ethereum.trie.diffbased.common.DiffBasedWorldStateProvider; |
||||||
|
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; |
||||||
|
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; |
||||||
|
|
||||||
|
import java.math.BigInteger; |
||||||
|
import java.util.NavigableMap; |
||||||
|
|
||||||
|
import org.apache.tuweni.bytes.Bytes; |
||||||
|
import org.apache.tuweni.bytes.Bytes32; |
||||||
|
import org.junit.jupiter.api.BeforeAll; |
||||||
|
import org.junit.jupiter.api.BeforeEach; |
||||||
|
import org.junit.jupiter.api.Test; |
||||||
|
|
||||||
|
public class SnapServerGetAccountRangeTest { |
||||||
|
private Hash rootHash; |
||||||
|
public Bytes32 firstAccount; |
||||||
|
public Bytes32 secondAccount; |
||||||
|
private SnapServer snapServer; |
||||||
|
private static ProtocolContext protocolContext; |
||||||
|
|
||||||
|
@BeforeAll |
||||||
|
public static void setup() { |
||||||
|
// Setup local blockchain for testing
|
||||||
|
BlockchainSetupUtil localBlockchainSetup = |
||||||
|
BlockchainSetupUtil.forSnapTesting(DataStorageFormat.BONSAI); |
||||||
|
localBlockchainSetup.importAllBlocks( |
||||||
|
HeaderValidationMode.LIGHT_DETACHED_ONLY, HeaderValidationMode.LIGHT); |
||||||
|
|
||||||
|
protocolContext = localBlockchainSetup.getProtocolContext(); |
||||||
|
} |
||||||
|
|
||||||
|
@BeforeEach |
||||||
|
public void setupTest() { |
||||||
|
WorldStateStorageCoordinator worldStateStorageCoordinator = |
||||||
|
new WorldStateStorageCoordinator( |
||||||
|
((DiffBasedWorldStateProvider) protocolContext.getWorldStateArchive()) |
||||||
|
.getWorldStateKeyValueStorage()); |
||||||
|
|
||||||
|
SnapSyncConfiguration snapSyncConfiguration = |
||||||
|
ImmutableSnapSyncConfiguration.builder().isSnapServerEnabled(true).build(); |
||||||
|
snapServer = |
||||||
|
new SnapServer( |
||||||
|
snapSyncConfiguration, |
||||||
|
new EthMessages(), |
||||||
|
worldStateStorageCoordinator, |
||||||
|
protocolContext) |
||||||
|
.start(); |
||||||
|
initAccounts(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* In this test, we request the entire state range, but limit the response to 4000 bytes. |
||||||
|
* Expected: 86 accounts. |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void test0_RequestEntireStateRangeWith4000BytesLimit() { |
||||||
|
testAccountRangeRequest( |
||||||
|
new AccountRangeRequestParams.Builder() |
||||||
|
.rootHash(rootHash) |
||||||
|
.responseBytes(4000) |
||||||
|
.expectedAccounts(86) |
||||||
|
.expectedFirstAccount(firstAccount) |
||||||
|
.expectedLastAccount( |
||||||
|
Bytes32.fromHexString( |
||||||
|
"0x445cb5c1278fdce2f9cbdb681bdd76c52f8e50e41dbd9e220242a69ba99ac099")) |
||||||
|
.build()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* In this test, we request the entire state range, but limit the response to 3000 bytes. |
||||||
|
* Expected: 65 accounts. |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void test1_RequestEntireStateRangeWith3000BytesLimit() { |
||||||
|
testAccountRangeRequest( |
||||||
|
new AccountRangeRequestParams.Builder() |
||||||
|
.rootHash(rootHash) |
||||||
|
.responseBytes(3000) |
||||||
|
.expectedAccounts(65) |
||||||
|
.expectedFirstAccount(firstAccount) |
||||||
|
.expectedLastAccount( |
||||||
|
Bytes32.fromHexString( |
||||||
|
"0x2e6fe1362b3e388184fd7bf08e99e74170b26361624ffd1c5f646da7067b58b6")) |
||||||
|
.build()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* In this test, we request the entire state range, but limit the response to 2000 bytes. |
||||||
|
* Expected: 44 accounts. |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void test2_RequestEntireStateRangeWith2000BytesLimit() { |
||||||
|
testAccountRangeRequest( |
||||||
|
new AccountRangeRequestParams.Builder() |
||||||
|
.rootHash(rootHash) |
||||||
|
.responseBytes(2000) |
||||||
|
.expectedAccounts(44) |
||||||
|
.expectedFirstAccount(firstAccount) |
||||||
|
.expectedLastAccount( |
||||||
|
Bytes32.fromHexString( |
||||||
|
"0x1c3f74249a4892081ba0634a819aec9ed25f34c7653f5719b9098487e65ab595")) |
||||||
|
.build()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* In this test, we request the entire state range, but limit the response to 1 byte. The server |
||||||
|
* should return the first account of the state. Expected: 1 account. |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void test3_RequestEntireStateRangeWith1ByteLimit() { |
||||||
|
testAccountRangeRequest( |
||||||
|
new AccountRangeRequestParams.Builder() |
||||||
|
.rootHash(rootHash) |
||||||
|
.responseBytes(1) |
||||||
|
.expectedAccounts(1) |
||||||
|
.expectedFirstAccount(firstAccount) |
||||||
|
.expectedLastAccount(firstAccount) |
||||||
|
.build()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Here we request with a responseBytes limit of zero. The server should return one account. |
||||||
|
* Expected: 1 account. |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void test4_RequestEntireStateRangeWithZeroBytesLimit() { |
||||||
|
testAccountRangeRequest( |
||||||
|
new AccountRangeRequestParams.Builder() |
||||||
|
.rootHash(rootHash) |
||||||
|
.responseBytes(0) |
||||||
|
.expectedAccounts(1) |
||||||
|
.expectedFirstAccount(firstAccount) |
||||||
|
.expectedLastAccount(firstAccount) |
||||||
|
.build()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* In this test, we request a range where startingHash is before the first available account key, |
||||||
|
* and limitHash is after. The server should return the first and second account of the state |
||||||
|
* (because the second account is the 'next available'). Expected: 2 accounts. |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void test5_RequestRangeBeforeFirstAccountKey() { |
||||||
|
testAccountRangeRequest( |
||||||
|
new AccountRangeRequestParams.Builder() |
||||||
|
.rootHash(rootHash) |
||||||
|
.startHash(hashAdd(firstAccount, -500)) |
||||||
|
.limitHash(hashAdd(firstAccount, 1)) |
||||||
|
.expectedAccounts(2) |
||||||
|
.expectedFirstAccount(firstAccount) |
||||||
|
.expectedLastAccount(secondAccount) |
||||||
|
.build()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Here we request range where both bounds are before the first available account key. This should |
||||||
|
* return the first account (even though it's out of bounds). Expected: 1 account. |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void test6_RequestRangeBothBoundsBeforeFirstAccountKey() { |
||||||
|
testAccountRangeRequest( |
||||||
|
new AccountRangeRequestParams.Builder() |
||||||
|
.rootHash(rootHash) |
||||||
|
.startHash(hashAdd(firstAccount, -500)) |
||||||
|
.limitHash(hashAdd(firstAccount, -400)) |
||||||
|
.expectedAccounts(1) |
||||||
|
.expectedFirstAccount(firstAccount) |
||||||
|
.expectedLastAccount(firstAccount) |
||||||
|
.build()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* In this test, both startingHash and limitHash are zero. The server should return the first |
||||||
|
* available account. Expected: 1 account. |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void test7_RequestBothBoundsZero() { |
||||||
|
testAccountRangeRequest( |
||||||
|
new AccountRangeRequestParams.Builder() |
||||||
|
.rootHash(rootHash) |
||||||
|
.startHash(Hash.ZERO) |
||||||
|
.limitHash(Hash.ZERO) |
||||||
|
.expectedAccounts(1) |
||||||
|
.expectedFirstAccount(firstAccount) |
||||||
|
.expectedLastAccount(firstAccount) |
||||||
|
.build()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* In this test, startingHash is exactly the first available account key. The server should return |
||||||
|
* the first available account of the state as the first item. Expected: 86 accounts. |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void test8_RequestStartingHashFirstAvailableAccountKey() { |
||||||
|
testAccountRangeRequest( |
||||||
|
new AccountRangeRequestParams.Builder() |
||||||
|
.rootHash(rootHash) |
||||||
|
.startHash(firstAccount) |
||||||
|
.responseBytes(4000) |
||||||
|
.expectedAccounts(86) |
||||||
|
.expectedFirstAccount(firstAccount) |
||||||
|
.expectedLastAccount( |
||||||
|
Bytes32.fromHexString( |
||||||
|
"0x445cb5c1278fdce2f9cbdb681bdd76c52f8e50e41dbd9e220242a69ba99ac099")) |
||||||
|
.build()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* In this test, startingHash is after the first available key. The server should return the |
||||||
|
* second account of the state as the first item. Expected: 86 accounts. |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void test9_RequestStartingHashAfterFirstAvailableKey() { |
||||||
|
testAccountRangeRequest( |
||||||
|
new AccountRangeRequestParams.Builder() |
||||||
|
.rootHash(rootHash) |
||||||
|
.startHash(secondAccount) |
||||||
|
.responseBytes(4000) |
||||||
|
.expectedAccounts(86) |
||||||
|
.expectedFirstAccount(secondAccount) |
||||||
|
.expectedLastAccount( |
||||||
|
Bytes32.fromHexString( |
||||||
|
"0x4615e5f5df5b25349a00ad313c6cd0436b6c08ee5826e33a018661997f85ebaa")) |
||||||
|
.build()); |
||||||
|
} |
||||||
|
|
||||||
|
/** This test requests a non-existent state root. Expected: 0 accounts. */ |
||||||
|
@Test |
||||||
|
public void test10_RequestNonExistentStateRoot() { |
||||||
|
Hash rootHash = |
||||||
|
Hash.fromHexString("1337000000000000000000000000000000000000000000000000000000000000"); |
||||||
|
testAccountRangeRequest( |
||||||
|
new AccountRangeRequestParams.Builder().rootHash(rootHash).expectedAccounts(0).build()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This test requests data at a state root that is 127 blocks old. We expect the server to have |
||||||
|
* this state available. Expected: 84 accounts. |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void test12_RequestStateRoot127BlocksOld() { |
||||||
|
|
||||||
|
Hash rootHash = |
||||||
|
protocolContext |
||||||
|
.getBlockchain() |
||||||
|
.getBlockHeader((protocolContext.getBlockchain().getChainHeadBlockNumber() - 127)) |
||||||
|
.orElseThrow() |
||||||
|
.getStateRoot(); |
||||||
|
testAccountRangeRequest( |
||||||
|
new AccountRangeRequestParams.Builder() |
||||||
|
.rootHash(rootHash) |
||||||
|
.expectedAccounts(84) |
||||||
|
.responseBytes(4000) |
||||||
|
.expectedFirstAccount(firstAccount) |
||||||
|
.expectedLastAccount( |
||||||
|
Bytes32.fromHexString( |
||||||
|
"0x580aa878e2f92d113a12c0a3ce3c21972b03dbe80786858d49a72097e2c491a3")) |
||||||
|
.build()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This test requests data at a state root that is actually the storage root of an existing |
||||||
|
* account. The server is supposed to ignore this request. Expected: 0 accounts. |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void test13_RequestStateRootIsStorageRoot() { |
||||||
|
Hash rootHash = |
||||||
|
Hash.fromHexString("df97f94bc47471870606f626fb7a0b42eed2d45fcc84dc1200ce62f7831da990"); |
||||||
|
testAccountRangeRequest( |
||||||
|
new AccountRangeRequestParams.Builder().rootHash(rootHash).expectedAccounts(0).build()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* In this test, the startingHash is after limitHash (wrong order). The server should ignore this |
||||||
|
* invalid request. Expected: 0 accounts. |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void test14_RequestStartingHashAfterLimitHash() { |
||||||
|
testAccountRangeRequest( |
||||||
|
new AccountRangeRequestParams.Builder() |
||||||
|
.rootHash(rootHash) |
||||||
|
.startHash(Hash.LAST) |
||||||
|
.limitHash(Hash.ZERO) |
||||||
|
.expectedAccounts(0) |
||||||
|
.build()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* In this test, the startingHash is the first available key, and limitHash is a key before |
||||||
|
* startingHash (wrong order). The server should return the first available key. Expected: 1 |
||||||
|
* account. |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void test15_RequestStartingHashFirstAvailableKeyAndLimitHashBefore() { |
||||||
|
testAccountRangeRequest( |
||||||
|
new AccountRangeRequestParams.Builder() |
||||||
|
.rootHash(rootHash) |
||||||
|
.startHash(firstAccount) |
||||||
|
.limitHash(hashAdd(firstAccount, -1)) |
||||||
|
.expectedAccounts(1) |
||||||
|
.expectedFirstAccount(firstAccount) |
||||||
|
.expectedLastAccount(firstAccount) |
||||||
|
.build()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* In this test, the startingHash is the first available key and limitHash is zero. (wrong order). |
||||||
|
* The server should return the first available key. Expected: 1 account. |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void test16_RequestStartingHashFirstAvailableKeyAndLimitHashZero() { |
||||||
|
testAccountRangeRequest( |
||||||
|
new AccountRangeRequestParams.Builder() |
||||||
|
.rootHash(rootHash) |
||||||
|
.startHash(firstAccount) |
||||||
|
.limitHash(Hash.ZERO) |
||||||
|
.expectedAccounts(1) |
||||||
|
.expectedFirstAccount(firstAccount) |
||||||
|
.expectedLastAccount(firstAccount) |
||||||
|
.build()); |
||||||
|
} |
||||||
|
|
||||||
|
private void testAccountRangeRequest(final AccountRangeRequestParams params) { |
||||||
|
NavigableMap<Bytes32, Bytes> accounts = getAccountRange(params); |
||||||
|
assertThat(accounts.size()).isEqualTo(params.getExpectedAccounts()); |
||||||
|
|
||||||
|
if (params.getExpectedAccounts() > 0) { |
||||||
|
assertThat(accounts.firstKey()).isEqualTo(params.getExpectedFirstAccount()); |
||||||
|
assertThat(accounts.lastKey()).isEqualTo(params.getExpectedLastAccount()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private NavigableMap<Bytes32, Bytes> getAccountRange(final AccountRangeRequestParams params) { |
||||||
|
Hash rootHash = params.getRootHash(); |
||||||
|
Bytes32 startHash = params.getStartHash(); |
||||||
|
Bytes32 limitHash = params.getLimitHash(); |
||||||
|
BigInteger sizeRequest = BigInteger.valueOf(params.getResponseBytes()); |
||||||
|
|
||||||
|
GetAccountRangeMessage requestMessage = |
||||||
|
GetAccountRangeMessage.create(rootHash, startHash, limitHash, sizeRequest); |
||||||
|
|
||||||
|
AccountRangeMessage resultMessage = |
||||||
|
AccountRangeMessage.readFrom( |
||||||
|
snapServer.constructGetAccountRangeResponse( |
||||||
|
requestMessage.wrapMessageData(BigInteger.ONE))); |
||||||
|
NavigableMap<Bytes32, Bytes> accounts = resultMessage.accountData(false).accounts(); |
||||||
|
return accounts; |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressWarnings("UnusedVariable") |
||||||
|
private void initAccounts() { |
||||||
|
rootHash = protocolContext.getWorldStateArchive().getMutable().rootHash(); |
||||||
|
GetAccountRangeMessage requestMessage = |
||||||
|
GetAccountRangeMessage.create(rootHash, Hash.ZERO, Hash.LAST, BigInteger.valueOf(4000)); |
||||||
|
AccountRangeMessage resultMessage = |
||||||
|
AccountRangeMessage.readFrom( |
||||||
|
snapServer.constructGetAccountRangeResponse( |
||||||
|
requestMessage.wrapMessageData(BigInteger.ONE))); |
||||||
|
NavigableMap<Bytes32, Bytes> accounts = resultMessage.accountData(false).accounts(); |
||||||
|
firstAccount = accounts.firstEntry().getKey(); |
||||||
|
secondAccount = |
||||||
|
accounts.entrySet().stream().skip(1).findFirst().orElse(accounts.firstEntry()).getKey(); |
||||||
|
} |
||||||
|
|
||||||
|
private Bytes32 hashAdd(final Bytes32 hash, final int value) { |
||||||
|
var result = Hash.wrap(hash).toBigInteger().add(BigInteger.valueOf(value)); |
||||||
|
Bytes resultBytes = Bytes.wrap(result.toByteArray()); |
||||||
|
return Bytes32.leftPad(resultBytes); |
||||||
|
} |
||||||
|
|
||||||
|
public static class AccountRangeRequestParams { |
||||||
|
private final Hash rootHash; |
||||||
|
private final Bytes32 startHash; |
||||||
|
private final Bytes32 limitHash; |
||||||
|
private final int responseBytes; |
||||||
|
private final int expectedAccounts; |
||||||
|
private final Bytes32 expectedFirstAccount; |
||||||
|
private final Bytes32 expectedLastAccount; |
||||||
|
|
||||||
|
private AccountRangeRequestParams(final Builder builder) { |
||||||
|
this.rootHash = builder.rootHash; |
||||||
|
this.startHash = builder.startHash; |
||||||
|
this.limitHash = builder.limitHash; |
||||||
|
this.responseBytes = builder.responseBytes; |
||||||
|
this.expectedAccounts = builder.expectedAccounts; |
||||||
|
this.expectedFirstAccount = builder.expectedFirstAccount; |
||||||
|
this.expectedLastAccount = builder.expectedLastAccount; |
||||||
|
} |
||||||
|
|
||||||
|
public static class Builder { |
||||||
|
private Hash rootHash = null; |
||||||
|
private Bytes32 startHash = Bytes32.ZERO; |
||||||
|
private Bytes32 limitHash = Hash.LAST; |
||||||
|
private int responseBytes = Integer.MAX_VALUE; |
||||||
|
private int expectedAccounts = 0; |
||||||
|
private Bytes32 expectedFirstAccount = null; |
||||||
|
private Bytes32 expectedLastAccount = null; |
||||||
|
|
||||||
|
public Builder rootHash(final Hash rootHashHex) { |
||||||
|
this.rootHash = rootHashHex; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public Builder startHash(final Bytes32 startHashHex) { |
||||||
|
this.startHash = startHashHex; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public Builder limitHash(final Bytes32 limitHashHex) { |
||||||
|
this.limitHash = limitHashHex; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public Builder responseBytes(final int responseBytes) { |
||||||
|
this.responseBytes = responseBytes; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public Builder expectedAccounts(final int expectedAccounts) { |
||||||
|
this.expectedAccounts = expectedAccounts; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public Builder expectedFirstAccount(final Bytes32 expectedFirstAccount) { |
||||||
|
this.expectedFirstAccount = expectedFirstAccount; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public Builder expectedLastAccount(final Bytes32 expectedLastAccount) { |
||||||
|
this.expectedLastAccount = expectedLastAccount; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public AccountRangeRequestParams build() { |
||||||
|
return new AccountRangeRequestParams(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Getters for each field
|
||||||
|
public Hash getRootHash() { |
||||||
|
return rootHash; |
||||||
|
} |
||||||
|
|
||||||
|
public Bytes32 getStartHash() { |
||||||
|
return startHash; |
||||||
|
} |
||||||
|
|
||||||
|
public Bytes32 getLimitHash() { |
||||||
|
return limitHash; |
||||||
|
} |
||||||
|
|
||||||
|
public int getResponseBytes() { |
||||||
|
return responseBytes; |
||||||
|
} |
||||||
|
|
||||||
|
public int getExpectedAccounts() { |
||||||
|
return expectedAccounts; |
||||||
|
} |
||||||
|
|
||||||
|
public Bytes32 getExpectedFirstAccount() { |
||||||
|
return expectedFirstAccount; |
||||||
|
} |
||||||
|
|
||||||
|
public Bytes32 getExpectedLastAccount() { |
||||||
|
return expectedLastAccount; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,111 @@ |
|||||||
|
{ |
||||||
|
"config": { |
||||||
|
"ethash": {}, |
||||||
|
"chainID": 3503995874084926, |
||||||
|
"homesteadBlock": 0, |
||||||
|
"eip150Block": 6, |
||||||
|
"eip155Block": 12, |
||||||
|
"eip158Block": 12, |
||||||
|
"byzantiumBlock": 18, |
||||||
|
"constantinopleBlock": 24, |
||||||
|
"constantinopleFixBlock": 30, |
||||||
|
"istanbulBlock": 36, |
||||||
|
"muirGlacierBlock": 42, |
||||||
|
"berlinBlock": 48, |
||||||
|
"londonBlock": 54, |
||||||
|
"arrowGlacierBlock": 60, |
||||||
|
"grayGlacierBlock": 66, |
||||||
|
"mergeNetsplitBlock": 72, |
||||||
|
"terminalTotalDifficulty": 9454784, |
||||||
|
"shanghaiTime": 780, |
||||||
|
"cancunTime": 840 |
||||||
|
}, |
||||||
|
"nonce": "0x0", |
||||||
|
"timestamp": "0x0", |
||||||
|
"extraData": "0x68697665636861696e", |
||||||
|
"gasLimit": "0x23f3e20", |
||||||
|
"difficulty": "0x20000", |
||||||
|
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", |
||||||
|
"coinbase": "0x0000000000000000000000000000000000000000", |
||||||
|
"alloc": { |
||||||
|
"000f3df6d732807ef1319fb7b8bb8522d0beac02": { |
||||||
|
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500", |
||||||
|
"balance": "0x2a" |
||||||
|
}, |
||||||
|
"0c2c51a0990aee1d73c1228de158688341557508": { |
||||||
|
"balance": "0xc097ce7bc90715b34b9f1000000000" |
||||||
|
}, |
||||||
|
"14e46043e63d0e3cdcf2530519f4cfaf35058cb2": { |
||||||
|
"balance": "0xc097ce7bc90715b34b9f1000000000" |
||||||
|
}, |
||||||
|
"16c57edf7fa9d9525378b0b81bf8a3ced0620c1c": { |
||||||
|
"balance": "0xc097ce7bc90715b34b9f1000000000" |
||||||
|
}, |
||||||
|
"1f4924b14f34e24159387c0a4cdbaa32f3ddb0cf": { |
||||||
|
"balance": "0xc097ce7bc90715b34b9f1000000000" |
||||||
|
}, |
||||||
|
"1f5bde34b4afc686f136c7a3cb6ec376f7357759": { |
||||||
|
"balance": "0xc097ce7bc90715b34b9f1000000000" |
||||||
|
}, |
||||||
|
"2d389075be5be9f2246ad654ce152cf05990b209": { |
||||||
|
"balance": "0xc097ce7bc90715b34b9f1000000000" |
||||||
|
}, |
||||||
|
"3ae75c08b4c907eb63a8960c45b86e1e9ab6123c": { |
||||||
|
"balance": "0xc097ce7bc90715b34b9f1000000000" |
||||||
|
}, |
||||||
|
"4340ee1b812acb40a1eb561c019c327b243b92df": { |
||||||
|
"balance": "0xc097ce7bc90715b34b9f1000000000" |
||||||
|
}, |
||||||
|
"4a0f1452281bcec5bd90c3dce6162a5995bfe9df": { |
||||||
|
"balance": "0xc097ce7bc90715b34b9f1000000000" |
||||||
|
}, |
||||||
|
"4dde844b71bcdf95512fb4dc94e84fb67b512ed8": { |
||||||
|
"balance": "0xc097ce7bc90715b34b9f1000000000" |
||||||
|
}, |
||||||
|
"5f552da00dfb4d3749d9e62dcee3c918855a86a0": { |
||||||
|
"balance": "0xc097ce7bc90715b34b9f1000000000" |
||||||
|
}, |
||||||
|
"654aa64f5fbefb84c270ec74211b81ca8c44a72e": { |
||||||
|
"balance": "0xc097ce7bc90715b34b9f1000000000" |
||||||
|
}, |
||||||
|
"717f8aa2b982bee0e29f573d31df288663e1ce16": { |
||||||
|
"balance": "0xc097ce7bc90715b34b9f1000000000" |
||||||
|
}, |
||||||
|
"7435ed30a8b4aeb0877cef0c6e8cffe834eb865f": { |
||||||
|
"balance": "0xc097ce7bc90715b34b9f1000000000" |
||||||
|
}, |
||||||
|
"83c7e323d189f18725ac510004fdc2941f8c4a78": { |
||||||
|
"balance": "0xc097ce7bc90715b34b9f1000000000" |
||||||
|
}, |
||||||
|
"84e75c28348fb86acea1a93a39426d7d60f4cc46": { |
||||||
|
"balance": "0xc097ce7bc90715b34b9f1000000000" |
||||||
|
}, |
||||||
|
"8bebc8ba651aee624937e7d897853ac30c95a067": { |
||||||
|
"storage": { |
||||||
|
"0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", |
||||||
|
"0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000000000000000000000000002", |
||||||
|
"0x0000000000000000000000000000000000000000000000000000000000000003": "0x0000000000000000000000000000000000000000000000000000000000000003" |
||||||
|
}, |
||||||
|
"balance": "0x1", |
||||||
|
"nonce": "0x1" |
||||||
|
}, |
||||||
|
"c7b99a164efd027a93f147376cc7da7c67c6bbe0": { |
||||||
|
"balance": "0xc097ce7bc90715b34b9f1000000000" |
||||||
|
}, |
||||||
|
"d803681e487e6ac18053afc5a6cd813c86ec3e4d": { |
||||||
|
"balance": "0xc097ce7bc90715b34b9f1000000000" |
||||||
|
}, |
||||||
|
"e7d13f7aa2a838d24c59b40186a0aca1e21cffcc": { |
||||||
|
"balance": "0xc097ce7bc90715b34b9f1000000000" |
||||||
|
}, |
||||||
|
"eda8645ba6948855e3b3cd596bbb07596d59c603": { |
||||||
|
"balance": "0xc097ce7bc90715b34b9f1000000000" |
||||||
|
} |
||||||
|
}, |
||||||
|
"number": "0x0", |
||||||
|
"gasUsed": "0x0", |
||||||
|
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", |
||||||
|
"baseFeePerGas": null, |
||||||
|
"excessBlobGas": null, |
||||||
|
"blobGasUsed": null |
||||||
|
} |
Binary file not shown.
Loading…
Reference in new issue