diff --git a/.github/workflows/hive-consensus-tests.yml b/.github/workflows/hive-consensus-tests.yml
index e507dd4c96d..65575337757 100644
--- a/.github/workflows/hive-consensus-tests.yml
+++ b/.github/workflows/hive-consensus-tests.yml
@@ -69,7 +69,7 @@ jobs:
# Output the variables
echo "skip_docker_build=$skip_docker_build" >> $GITHUB_OUTPUT
- echo "wait_for_docker=$wait_for_docker" >> $GITHUB_OUTPUT
+ echo "skip_wait_for_docker=$skip_wait_for_docker" >> $GITHUB_OUTPUT
- name: Trigger Docker Build Action with Cleaned Ref
if: steps.check_conditions.outputs.skip_docker_build != 'true'
diff --git a/.github/workflows/nethermind-tests.yml b/.github/workflows/nethermind-tests.yml
index afee5450960..3b9fba7070e 100644
--- a/.github/workflows/nethermind-tests.yml
+++ b/.github/workflows/nethermind-tests.yml
@@ -62,6 +62,7 @@ jobs:
- Nethermind.Network.Dns.Test
- Nethermind.Network.Enr.Test
- Nethermind.Network.Test
+ - Nethermind.Optimism.Test
- Nethermind.Overseer.Test
- Nethermind.Runner.Test
- Nethermind.Serialization.Ssz.Test
diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml
index 9773b4b600f..dd82250f539 100644
--- a/.github/workflows/publish-docker.yml
+++ b/.github/workflows/publish-docker.yml
@@ -23,9 +23,7 @@ on:
required: true
default: release
type: choice
- options:
- - release
- - debug
+ options: [release, debug]
jobs:
publish-docker:
@@ -46,14 +44,16 @@ jobs:
- name: Build and push image to Docker Hub (staging)
run: |
branch=$(echo "${{ github.ref }}" | sed -e "s/refs\/heads\///g")
- original_tag=${{ github.event.inputs.tag || '$branch' }}
- tag=$(echo "$original_tag" | sed 's/\//-/g') # replace '/' with '-' in tag name
+ tag=$(echo "${{ github.event.inputs.tag || '$branch' }}" | sed 's/\//-/g') # replace '/' with '-'
+ image_name=nethermindeth/${{ github.event.inputs.image-name || 'nethermind' }}
build_timestamp=$(date '+%s')
+
echo "Building image with tag $tag"
docker buildx build --platform=linux/amd64,linux/arm64 \
-f ${{ github.event.inputs.dockerfile || 'Dockerfile' }} \
- -t "nethermindeth/${{ github.event.inputs.image-name || 'nethermind' }}:$tag" \
+ -t "$image_name:$tag" \
+ ${{ endsWith(github.ref, '/master') && github.event_name == 'push' && '-t $image_name:master-${GITHUB_SHA:0:7}' || '' }} \
--build-arg BUILD_CONFIG=${{ github.event.inputs.build-config || 'release' }} \
--build-arg BUILD_TIMESTAMP=$build_timestamp \
--build-arg CI=$CI \
diff --git a/.github/workflows/rpc-comparison.yml b/.github/workflows/rpc-comparison.yml
index a9332ca13f7..4d7a65a87be 100644
--- a/.github/workflows/rpc-comparison.yml
+++ b/.github/workflows/rpc-comparison.yml
@@ -49,6 +49,8 @@ jobs:
verify_correctness_of_setup:
name: Verify if inputs are correct
runs-on: ubuntu-latest
+ outputs:
+ custom_machine_type: ${{ steps.compute_machine_type.outputs.custom_machine_type }}
steps:
- name: Verify if inputs are correctly applied
run: |
@@ -65,6 +67,21 @@ jobs:
IS_PERFORMANCE_CHECK: ${{ inputs.is_performance_check }}
BRANCH_TO_COMPARE: ${{ inputs.branch_to_compare }}
COMPARE_WITH: ${{ inputs.compare_with }}
+
+ - name: Compute Machine Type
+ id: compute_machine_type
+ run: |
+ convert_to_paprika="${{ github.event.inputs.convert_to_paprika }}"
+ is_performance_check="${{ github.event.inputs.is_performance_check }}"
+ machine_type=""
+ if [[ "$convert_to_paprika" == 'true' && "$is_performance_check" == 'true' ]]; then
+ machine_type="g7-premium-16"
+ elif [[ "$convert_to_paprika" == 'true' ]]; then
+ machine_type="g6-standard-8"
+ elif [[ "$is_performance_check" == 'true' ]]; then
+ machine_type="g7-premium-8"
+ fi
+ echo "custom_machine_type=$machine_type" >> $GITHUB_OUTPUT
create_main_node:
name: Create node from current branch
@@ -79,10 +96,10 @@ jobs:
"default_dockerfile_build_type": "release",
"ssh_keys": "",
"allowed_ips": "${{ inputs.allowed_ips }}",
- "custom_machine_type": "${{ (inputs.convert_to_paprika == 'true' && inputs.is_performance_check == 'true' && 'g7-premium-16') || (inputs.convert_to_paprika == 'true' && 'g6-standard-8') || (inputs.is_performance_check == 'true' && 'g7-premium-8') || '' }}"
+ "custom_machine_type": "${{ needs.verify_correctness_of_setup.outputs.custom_machine_type }}"
}
non_validator_mode: true
- additional_nethermind_flags: Pruning.Mode=None JsonRpc.EnabledModules=[Eth,Subscribe,Trace,TxPool,Web3,Personal,Proof,Net,Parity,Health,Rpc,Debug,Admin]
+ additional_nethermind_flags: JsonRpc.EnabledModules=[Eth,Subscribe,Trace,TxPool,Web3,Personal,Proof,Net,Parity,Health,Rpc,Debug,Admin] JsonRpc.Timeout=3600000 log=INFO
nethermind_repo_ref: ${{ github.ref }}
custom_run_id: ${{ github.run_id }}
network: "${{ inputs.network || 'mainnet' }}"
@@ -102,10 +119,10 @@ jobs:
"default_dockerfile_build_type": "release",
"ssh_keys": "",
"allowed_ips": "${{ inputs.allowed_ips }}",
- "custom_machine_type": "${{ (inputs.convert_to_paprika == 'true' && inputs.is_performance_check == 'true' && 'g7-premium-16') || (inputs.convert_to_paprika == 'true' && 'g6-standard-8') || (inputs.is_performance_check == 'true' && 'g7-premium-8') || '' }}"
+ "custom_machine_type": "${{ needs.verify_correctness_of_setup.outputs.custom_machine_type }}"
}
non_validator_mode: true
- additional_nethermind_flags: Pruning.Mode=None JsonRpc.EnabledModules=[Eth,Subscribe,Trace,TxPool,Web3,Personal,Proof,Net,Parity,Health,Rpc,Debug,Admin]
+ additional_nethermind_flags: JsonRpc.EnabledModules=[Eth,Subscribe,Trace,TxPool,Web3,Personal,Proof,Net,Parity,Health,Rpc,Debug,Admin] JsonRpc.Timeout=3600000 log=INFO
nethermind_repo_ref: ${{ inputs.branch_to_compare }}
custom_run_id: ${{ github.run_id }}
network: "${{ inputs.network || 'mainnet' }}"
@@ -302,6 +319,11 @@ jobs:
check_jsonrpc_responding "$url"
check_chain_head "$url"
fi
+
+ # Extra wait - nodes need to process a few new blocks - nice to have at least 128 of them after StateHealing
+ # Adding (128 - 32) * 12 seconds (-32 because we always keep 32 blocks to be processed after healing)
+ echo "Waiting for (128 - 32) blocks to be synced"
+ sleep 1152
compare:
name: Compare JSON-RPC responses between clients and versions
@@ -311,7 +333,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Install flood
- run: pip install git+https://github.com/kamilchodola/flood.git
+ run: pip install --force-reinstall --no-deps git+https://github.com/kamilchodola/flood.git
- name: Prepare Comparison Flags
id: prep_comparison
@@ -393,21 +415,21 @@ jobs:
flood "$TEST" ${compare_to_other_branch_params} --rates 10 50 100 500 1000 --output "$TEST_perf_result" --duration 30 --deep-check | tee -a "$TEST_perf_result.txt"
done
else
- echo "flood all ${compare_to_other_branch_params} --output equality_result_other --equality | tee output_other_branch.txt"
- flood all ${compare_to_other_branch_params} --output equality_result_other --equality | tee output_other_branch.txt
+ echo "flood all ${compare_to_other_branch_params} --equality | tee output_other_branch.txt"
+ flood all ${compare_to_other_branch_params} --equality | tee output_other_branch.txt
fi
- name: Compare to INFURA Endpoint
if: env.compare_to_infura == 'true' && inputs.is_performance_check != true
run: |
- echo "flood all ${compare_to_infura_params} --output equality_result_infura --equality | tee output_infura.txt"
- flood all ${compare_to_infura_params} --output equality_result_infura --equality | tee output_infura.txt
+ echo "flood all ${compare_to_infura_params} --equality | tee output_infura.txt"
+ flood all ${compare_to_infura_params} --equality | tee output_infura.txt
- name: Compare to Nethermind Archive Endpoint
if: env.compare_to_archive == 'true' && inputs.is_performance_check != true
run: |
- echo "flood all ${compare_to_archive_params} --output equality_result_archive --equality | tee output_archive.txt"
- flood all ${compare_to_archive_params} --output equality_result_archive --equality | tee output_archive.txt
+ echo "flood all ${compare_to_archive_params} --equality | tee output_archive.txt"
+ flood all ${compare_to_archive_params} --equality | tee output_archive.txt
- name: Generate report
run: |
diff --git a/.github/workflows/run-a-single-node-from-branch.yml b/.github/workflows/run-a-single-node-from-branch.yml
index 654dfc9f09c..e11cd1c8267 100644
--- a/.github/workflows/run-a-single-node-from-branch.yml
+++ b/.github/workflows/run-a-single-node-from-branch.yml
@@ -28,9 +28,10 @@ on:
options:
- lighthouse
- lodestar
- #- nimbus
- prysm
- teku
+ - nimbus
+ - nimbus_ws
cl_custom_image:
description: "In case of need to run non-default cl image (different than actually supported by Sedge) put it in there"
default: ""
diff --git a/.github/workflows/sync-testnets.yml b/.github/workflows/sync-testnets.yml
index 0a8b99b9773..3a5b0bdfcdf 100644
--- a/.github/workflows/sync-testnets.yml
+++ b/.github/workflows/sync-testnets.yml
@@ -20,17 +20,17 @@ jobs:
include:
- network: "holesky"
checkpoint-sync-url: "https://holesky.beaconstate.ethstaker.cc/"
- cl-client: "lighthouse:sigp/lighthouse:latest"
+ cl-client: "lodestar:chainsafe/lodestar:latest"
el-client: "nethermind:nethermindeth/nethermind:master"
- agent: ubuntu-latest
+ agent: sync-agent-80gb
- network: "chiado"
checkpoint-sync-url: "http://139.144.26.89:4000/"
- cl-client: "lighthouse:sigp/lighthouse:latest"
+ cl-client: "lodestar:chainsafe/lodestar:latest"
el-client: "nethermind:nethermindeth/nethermind:master"
agent: sync-agent-80gb
- network: "sepolia"
checkpoint-sync-url: "https://beaconstate-sepolia.chainsafe.io"
- cl-client: "lighthouse:sigp/lighthouse:latest"
+ cl-client: "lodestar:chainsafe/lodestar:latest"
el-client: "nethermind:nethermindeth/nethermind:master"
agent: sync-agent-160gb
name: "Run sync of ${{ matrix.network }} testnet"
@@ -41,15 +41,6 @@ jobs:
with:
clean: true
- - name: Configure settings
- id: settings
- run: |
- echo "BUILD_TIMESTAMP=$(date '+%s')" >> $GITHUB_OUTPUT
- echo "COMMIT_HASH=$(git describe --always --exclude=* --abbrev=40)" >> $GITHUB_OUTPUT
-
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v2
-
- name: Installing requirements
run: |
sudo apt-get update
@@ -82,6 +73,7 @@ jobs:
--el-extra-flag Sync.NonValidatorNode=true --el-extra-flag Sync.DownloadBodiesInFastSync=false \
--el-extra-flag Sync.DownloadReceiptsInFastSync=false \
--el-extra-flag JsonRpc.EnabledModules=[Eth,Subscribe,Trace,TxPool,Web3,Personal,Proof,Net,Parity,Health,Rpc,Debug] \
+ --el-extra-flag Sync.SnapSync=true \
--checkpoint-sync-url=${{ matrix.checkpoint-sync-url }}
echo 'Running sedge...'
./build/sedge run -p $GITHUB_WORKSPACE/sedge
@@ -90,29 +82,31 @@ jobs:
id: wait
timeout-minutes: 180
run: |
- set +e
-
declare -A bad_logs
bad_logs["Corrupt"]=1
bad_logs["Exception"]=1
-
+
declare -A good_logs
good_logs["Synced Chain Head"]=0
good_logs["Processed"]=0
-
+
declare -A required_count
required_count["Synced Chain Head"]=20
- required_count["Processed"]=20
-
+ required_count["Processed"]=20
+
counter=0
found_bad_log=false
-
- echo "Starting Docker logs monitoring..."
+
docker logs -f sedge-execution-client | while read -r line; do
echo "$line"
-
- if [[ $found_bad_log == true ]]; then
- ((counter++))
+
+ if [[ "$line" == *"All done"* ]]; then
+ echo "Unexpected termination detected: $line"
+ exit 1
+ fi
+
+ if [ "$found_bad_log" = true ]; then
+ counter=$((counter + 1))
if [ $counter -ge 100 ]; then
echo "Exiting after capturing extra logs due to error."
exit 1
@@ -120,21 +114,21 @@ jobs:
continue
fi
fi
-
+
for bad_log in "${!bad_logs[@]}"; do
if [[ "$line" == *"$bad_log"* ]]; then
echo "Error: $bad_log found in Docker logs."
- $found_bad_log=true
- continue 2
+ found_bad_log=true
+ break
fi
done
-
+
for good_log in "${!good_logs[@]}"; do
if [[ "$line" == *"$good_log"* ]]; then
- ((good_logs["$good_log"]++))
+ good_logs["$good_log"]=$((good_logs["$good_log"]+1))
fi
done
-
+
# Check if all good logs have reached the required count
all_reached_required_count=true
for good_log in "${!good_logs[@]}"; do
@@ -143,7 +137,7 @@ jobs:
break
fi
done
-
+
if $all_reached_required_count; then
echo "All required logs found."
exit 0
diff --git a/.github/workflows/update-docs.yml b/.github/workflows/update-docs.yml
index c4d8b8ad235..b6ceb554788 100644
--- a/.github/workflows/update-docs.yml
+++ b/.github/workflows/update-docs.yml
@@ -39,7 +39,9 @@ jobs:
mv d/docs/interacting/json-rpc-ns/eth_subscribe.md n/docgen/eth_subscribe.md
mv d/docs/interacting/json-rpc-ns/eth_unsubscribe.md n/docgen/eth_unsubscribe.md
mv d/docs/monitoring/metrics/metrics.md n/docgen/metrics.md
- cd n/docgen && ./DocGen && cd ../..
+ cd n/docgen
+ ./DocGen --config --jsonrpc --metrics
+ cd ../..
mv n/docgen/configuration.md d/docs/fundamentals/configuration.md
rm -f d/docs/interacting/json-rpc-ns/*.md
mv n/docgen/eth_subscribe.md d/docs/interacting/json-rpc-ns/eth_subscribe.md
diff --git a/Dockerfile b/Dockerfile
index 23fc81ca4ed..ccdea679109 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,7 +1,7 @@
# SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
# SPDX-License-Identifier: LGPL-3.0-only
-FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS build
+FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-noble AS build
ARG BUILD_CONFIG=release
ARG BUILD_TIMESTAMP
@@ -9,7 +9,6 @@ ARG CI
ARG COMMIT_HASH
ARG TARGETARCH
-COPY .git .git
COPY src/Nethermind src/Nethermind
RUN arch=$([ "$TARGETARCH" = "amd64" ] && echo "x64" || echo "$TARGETARCH") && \
@@ -19,7 +18,7 @@ RUN arch=$([ "$TARGETARCH" = "amd64" ] && echo "x64" || echo "$TARGETARCH") && \
# A temporary symlink to support the old executable name
RUN ln -s -r /publish/nethermind /publish/Nethermind.Runner
-FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/aspnet:8.0-jammy
+FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/aspnet:8.0-noble
WORKDIR /nethermind
diff --git a/Dockerfile.chiseled b/Dockerfile.chiseled
index 2a7185f1855..936c78877dc 100644
--- a/Dockerfile.chiseled
+++ b/Dockerfile.chiseled
@@ -1,7 +1,7 @@
# SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
# SPDX-License-Identifier: LGPL-3.0-only
-FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS build
+FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-noble AS build
ARG BUILD_CONFIG=release
ARG BUILD_TIMESTAMP
@@ -9,7 +9,6 @@ ARG CI
ARG COMMIT_HASH
ARG TARGETARCH
-COPY .git .git
COPY src/Nethermind src/Nethermind
RUN arch=$([ "$TARGETARCH" = "amd64" ] && echo "x64" || echo "$TARGETARCH") && \
@@ -22,7 +21,7 @@ RUN cd /publish && \
mkdir logs && \
mkdir nethermind_db
-FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/aspnet:8.0-jammy-chiseled
+FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/aspnet:8.0-noble-chiseled
WORKDIR /nethermind
diff --git a/Dockerfile.diag b/Dockerfile.diag
index 6fca05c60ff..768e8fa9c2e 100644
--- a/Dockerfile.diag
+++ b/Dockerfile.diag
@@ -1,7 +1,7 @@
# SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
# SPDX-License-Identifier: LGPL-3.0-only
-FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS build
+FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-noble AS build
ARG BUILD_CONFIG=release
ARG BUILD_TIMESTAMP
@@ -9,7 +9,6 @@ ARG CI
ARG COMMIT_HASH
ARG TARGETARCH
-COPY .git .git
COPY src/Nethermind src/Nethermind
RUN arch=$([ "$TARGETARCH" = "amd64" ] && echo "x64" || echo "$TARGETARCH") && \
@@ -23,7 +22,7 @@ RUN dotnet tool install -g dotnet-dump && \
dotnet tool install -g dotnet-trace && \
dotnet tool install -g JetBrains.dotTrace.GlobalTools
-FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/aspnet:8.0-jammy
+FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/aspnet:8.0-noble
WORKDIR /nethermind
diff --git a/src/Nethermind/Chains/base-mainnet.json b/src/Nethermind/Chains/base-mainnet.json
index c4de3a61e80..c0853d933aa 100644
--- a/src/Nethermind/Chains/base-mainnet.json
+++ b/src/Nethermind/Chains/base-mainnet.json
@@ -6,6 +6,8 @@
"params": {
"regolithTimestamp": "0x0",
"bedrockBlockNumber": "0x0",
+ "canyonTimestamp": "0x65a01e91",
+ "ecotoneTimestamp": "0x65f23e01",
"l1FeeRecipient": "0x420000000000000000000000000000000000001A",
"l1BlockAddress": "0x4200000000000000000000000000000000000015"
}
@@ -47,11 +49,16 @@
"eip3529Transition": "0x0",
"eip3541Transition": "0x0",
- "eip1153TransitionTimestamp": "0x65F23E01",
- "eip4788TransitionTimestamp": "0x65F23E01",
- "eip4844TransitionTimestamp": "0x65F23E01",
- "eip5656TransitionTimestamp": "0x65F23E01",
- "eip6780TransitionTimestamp": "0x65F23E01",
+ "eip4895TransitionTimestamp": "0x65a01e91",
+ "eip3651TransitionTimestamp": "0x65a01e91",
+ "eip3855TransitionTimestamp": "0x65a01e91",
+ "eip3860TransitionTimestamp": "0x65a01e91",
+
+ "eip1153TransitionTimestamp": "0x65f23e01",
+ "eip4788TransitionTimestamp": "0x65f23e01",
+ "eip4844TransitionTimestamp": "0x65f23e01",
+ "eip5656TransitionTimestamp": "0x65f23e01",
+ "eip6780TransitionTimestamp": "0x65f23e01",
"terminalTotalDifficulty": "0"
},
@@ -71,6 +78,16 @@
"baseFeePerGas": "0x3b9aca00",
"gasLimit": "0x1c9c380"
},
+ "nodes": [
+ "enode://ca2774c3c401325850b2477fd7d0f27911efbf79b1e8b335066516e2bd8c4c9e0ba9696a94b1cb030a88eac582305ff55e905e64fb77fe0edcd70a4e5296d3ec@34.65.175.185:30305",
+ "enode://dd751a9ef8912be1bfa7a5e34e2c3785cc5253110bd929f385e07ba7ac19929fb0e0c5d93f77827291f4da02b2232240fbc47ea7ce04c46e333e452f8656b667@34.65.107.0:30305",
+ "enode://c5d289b56a77b6a2342ca29956dfd07aadf45364dde8ab20d1dc4efd4d1bc6b4655d902501daea308f4d8950737a4e93a4dfedd17b49cd5760ffd127837ca965@34.65.202.239:30305",
+ "enode://87a32fd13bd596b2ffca97020e31aef4ddcc1bbd4b95bb633d16c1329f654f34049ed240a36b449fda5e5225d70fe40bc667f53c304b71f8e68fc9d448690b51@3.231.138.188:30301",
+ "enode://ca21ea8f176adb2e229ce2d700830c844af0ea941a1d8152a9513b966fe525e809c3a6c73a2c18a12b74ed6ec4380edf91662778fe0b79f6a591236e49e176f9@184.72.129.189:30301",
+ "enode://acf4507a211ba7c1e52cdf4eef62cdc3c32e7c9c47998954f7ba024026f9a6b2150cd3f0b734d9c78e507ab70d59ba61dfe5c45e1078c7ad0775fb251d7735a2@3.220.145.177:30301",
+ "enode://8a5a5006159bf079d06a04e5eceab2a1ce6e0f721875b2a9c96905336219dbe14203d38f70f3754686a6324f786c2f9852d8c0dd3adac2d080f4db35efc678c5@3.231.11.52:30301",
+ "enode://cdadbe835308ad3557f9a1de8db411da1a260a98f8421d62da90e71da66e55e98aaa8e90aa7ce01b408a54e4bd2253d701218081ded3dbe5efbbc7b41d7cef79@54.198.153.150:30301"
+ ],
"accounts": {
"0000000000000000000000000000000000000001": {
"builtin": {
diff --git a/src/Nethermind/Chains/base-sepolia.json b/src/Nethermind/Chains/base-sepolia.json
index e095bb3dd38..7faf0bda489 100644
--- a/src/Nethermind/Chains/base-sepolia.json
+++ b/src/Nethermind/Chains/base-sepolia.json
@@ -7,6 +7,7 @@
"regolithTimestamp": "0x0",
"bedrockBlockNumber": "0x0",
"canyonTimestamp": "0x6553a790",
+ "ecotoneTimestamp": "0x65d62c10",
"l1FeeRecipient": "0x420000000000000000000000000000000000001A",
"l1BlockAddress": "0x4200000000000000000000000000000000000015",
"canyonBaseFeeChangeDenominator": "250",
@@ -80,6 +81,13 @@
"baseFeePerGas": "0x3b9aca00",
"gasLimit": "0x17d7840"
},
+ "nodes": [
+ "enode://2bd2e657bb3c8efffb8ff6db9071d9eb7be70d7c6d7d980ff80fc93b2629675c5f750bc0a5ef27cd788c2e491b8795a7e9a4a6e72178c14acc6753c0e5d77ae4@34.65.205.244:30305",
+ "enode://db8e1cab24624cc62fc35dbb9e481b88a9ef0116114cd6e41034c55b5b4f18755983819252333509bd8e25f6b12aadd6465710cd2e956558faf17672cce7551f@34.65.173.88:30305",
+ "enode://bfda2e0110cfd0f4c9f7aa5bf5ec66e6bd18f71a2db028d36b8bf8b0d6fdb03125c1606a6017b31311d96a36f5ef7e1ad11604d7a166745e6075a715dfa67f8a@34.65.229.245:30305",
+ "enode://548f715f3fc388a7c917ba644a2f16270f1ede48a5d88a4d14ea287cc916068363f3092e39936f1a3e7885198bef0e5af951f1d7b1041ce8ba4010917777e71f@18.210.176.114:30301",
+ "enode://6f10052847a966a725c9f4adf6716f9141155b99a0fb487fea3f51498f4c2a2cb8d534e680ee678f9447db85b93ff7c74562762c3714783a7233ac448603b25f@107.21.251.55:30301"
+ ],
"accounts": {
"0000000000000000000000000000000000000001": {
"balance": "0x1",
diff --git a/src/Nethermind/Chains/chiado.json b/src/Nethermind/Chains/chiado.json
index e2cef850df4..5a61c9ef01e 100644
--- a/src/Nethermind/Chains/chiado.json
+++ b/src/Nethermind/Chains/chiado.json
@@ -98,11 +98,12 @@
"gasLimit": "0x989680"
},
"nodes": [
- "enode://7dd44af6138120f328bb031eb56e00985c149319d4f1e33275b30be7fddadd8ccd9f7b9c3b35a16136a61e85b2b2d1de073f30ec1d0ddf576a33be8ff48d88d0@139.144.26.89:30303",
- "enode://317b9cee65ccf1d747b00e604242bfa3ae367beee8f149e28c5b2b88820f855ea7b5a75eb5327cfc3d8ca97adbf71538468290a46592ed7009f3fb394ec752f1@139.144.26.115:30303",
- "enode://b77ae97906155ebbb83fd32c87ab0aa57372a24abbd8aa4bae679f048b726de4a195709f613be4981e44b24640bc89e4824427d94e9a37afc148da8250c8ab2d@139.144.26.101:30303",
- "enode://69f8abfa3b0221161f8c19014b90857a18742554af27af73fd779c486728750a0ff11b873975f104fc5276a3a7c3b5b68cb3c26c815e9f78462901895d652124@139.144.26.85:30303",
- "enode://ac7fc76f9b2ab343fb2d091365a7f46d17018e525cbedfbf24b247c76657e934ef4df61cc2f6dad6bfcf722425e03e1a8a6e4e4b52743acc2319cb8ebf27d742@170.187.154.239:30303",
+ "enode://3c9849b809dc34c914fcdf507ff59931942bdf5cd11510782a7d5695eacd622a281ae0b46aa53b8b893e1308f94867001d0fb0b52c854f96e7ecf43490f5b7bb@139.144.26.89:30303",
+ "enode://1556022f95f2910ed795b80df68466284b5a7de112cb00d5f4843b486392e7e790c9d27cf358bf1e3ceff3089df36dcadae593eda9730565a7221e40a96b8cd4@139.144.26.115:30303",
+ "enode://b39e929805542fb141ca6946931d06fdbbbd9ea8202eb1e72d7e7484877658b5baf0d8b0a6eb86a7f34b6f5c4b15b080c807c851692baef96c6a5aeca2cbf29a@139.144.26.101:30303",
+ "enode://5f7074a38a84e7ed7cbb207b9b1a54b4c537c5d06ebc955c892528f95927eb63a3373e344302cb1bcc2242451899c276a21e360a4347674cb97e0b9c251c2704@139.144.26.85:30303",
+ "enode://9ff64d021a83c72d68e7a3cefac5ea0661071cfdeed065782418ff2b0fccaace1072644118ed9fe6a304f451a2e75e2d4c69b502b3486ce16b4c50afc347cbff@170.187.154.239:30303",
+ "enode://4504f03b4773251188e80d2c36186de4c2dd0e1e83aadaa1164cdae2ebc510d47a3dba6c80972ea18a71177ab3aa9883e081f5a350e8979cb7127e63bb6b81ea@139.144.173.54:30303",
"enode://712144ac396fd2298b3e2559e2930d7f3a36fded3addd66955224958f1845634067717ab9522757ed2948f480fc52add5676487c8378e9011a7e2c0ac2f36cc3@3.71.132.231:30303",
"enode://595160631241ea41b187b85716f9f9572a266daa940d74edbe3b83477264ce284d69208e61cf50e91641b1b4f9a03fa8e60eb73d435a84cf4616b1c969bc2512@3.69.35.13:30303",
"enode://5abc2f73f81ea6b94f1e1b1e376731fc662ecd7863c4c7bc83ec307042542a64feab5af7985d52b3b1432acf3cb82460b327d0b6b70cb732afb1e5a16d6b1e58@35.206.174.92:30303",
diff --git a/src/Nethermind/Chains/op-mainnet.json b/src/Nethermind/Chains/op-mainnet.json
index 09cd4bdf480..2c04e2cc3c1 100644
--- a/src/Nethermind/Chains/op-mainnet.json
+++ b/src/Nethermind/Chains/op-mainnet.json
@@ -6,6 +6,8 @@
"params": {
"regolithTimestamp": "0x0",
"bedrockBlockNumber": "0x645C277",
+ "canyonTimestamp": "0x65a01e91",
+ "ecotoneTimestamp": "0x65f23e01",
"l1FeeRecipient": "0x420000000000000000000000000000000000001A",
"l1BlockAddress": "0x4200000000000000000000000000000000000015"
}
@@ -52,11 +54,16 @@
"eip3529Transition": "0x645C277",
"eip3541Transition": "0x645C277",
- "eip1153TransitionTimestamp": "0x65F23E01",
- "eip4788TransitionTimestamp": "0x65F23E01",
- "eip4844TransitionTimestamp": "0x65F23E01",
- "eip5656TransitionTimestamp": "0x65F23E01",
- "eip6780TransitionTimestamp": "0x65F23E01",
+ "eip4895TransitionTimestamp": "0x65a01e91",
+ "eip3651TransitionTimestamp": "0x65a01e91",
+ "eip3855TransitionTimestamp": "0x65a01e91",
+ "eip3860TransitionTimestamp": "0x65a01e91",
+
+ "eip1153TransitionTimestamp": "0x65f23e01",
+ "eip4788TransitionTimestamp": "0x65f23e01",
+ "eip4844TransitionTimestamp": "0x65f23e01",
+ "eip5656TransitionTimestamp": "0x65f23e01",
+ "eip6780TransitionTimestamp": "0x65f23e01",
"terminalTotalDifficulty": "0"
},
diff --git a/src/Nethermind/Chains/op-sepolia.json b/src/Nethermind/Chains/op-sepolia.json
index 1068ceb6c0e..f90ba4e5a25 100644
--- a/src/Nethermind/Chains/op-sepolia.json
+++ b/src/Nethermind/Chains/op-sepolia.json
@@ -7,6 +7,8 @@
"regolithTimestamp": "0x0",
"bedrockBlockNumber": "0x0",
"canyonTimestamp": "0x6553a790",
+ "ecotoneTimestamp": "0x65D62C10",
+ "fjordTimestamp": "0x66575100",
"l1FeeRecipient": "0x420000000000000000000000000000000000001A",
"l1BlockAddress": "0x4200000000000000000000000000000000000015",
"canyonBaseFeeChangeDenominator": "250",
@@ -50,18 +52,16 @@
"eip3198Transition": "0x0",
"eip3529Transition": "0x0",
"eip3541Transition": "0x0",
-
"eip4895TransitionTimestamp": "0x6553a790",
"eip3651TransitionTimestamp": "0x6553a790",
"eip3855TransitionTimestamp": "0x6553a790",
"eip3860TransitionTimestamp": "0x6553a790",
-
"eip1153TransitionTimestamp": "0x65D62C10",
"eip4788TransitionTimestamp": "0x65D62C10",
"eip4844TransitionTimestamp": "0x65D62C10",
"eip5656TransitionTimestamp": "0x65D62C10",
"eip6780TransitionTimestamp": "0x65D62C10",
-
+ "eip7212TransitionTimestamp": "0x66575100",
"terminalTotalDifficulty": "0"
},
"genesis": {
@@ -82,8 +82,8 @@
},
"nodes": [
"enode://2bd2e657bb3c8efffb8ff6db9071d9eb7be70d7c6d7d980ff80fc93b2629675c5f750bc0a5ef27cd788c2e491b8795a7e9a4a6e72178c14acc6753c0e5d77ae4@34.65.205.244:30305",
- "enode://db8e1cab24624cc62fc35dbb9e481b88a9ef0116114cd6e41034c55b5b4f18755983819252333509bd8e25f6b12aadd6465710cd2e956558faf17672cce7551f@34.65.173.88:30305",
- "enode://bfda2e0110cfd0f4c9f7aa5bf5ec66e6bd18f71a2db028d36b8bf8b0d6fdb03125c1606a6017b31311d96a36f5ef7e1ad11604d7a166745e6075a715dfa67f8a@34.65.229.245:30305",
+ "enode://db8e1cab24624cc62fc35dbb9e481b88a9ef0116114cd6e41034c55b5b4f18755983819252333509bd8e25f6b12aadd6465710cd2e956558faf17672cce7551f@34.65.173.88:30305",
+ "enode://bfda2e0110cfd0f4c9f7aa5bf5ec66e6bd18f71a2db028d36b8bf8b0d6fdb03125c1606a6017b31311d96a36f5ef7e1ad11604d7a166745e6075a715dfa67f8a@34.65.229.245:30305",
"enode://548f715f3fc388a7c917ba644a2f16270f1ede48a5d88a4d14ea287cc916068363f3092e39936f1a3e7885198bef0e5af951f1d7b1041ce8ba4010917777e71f@18.210.176.114:30301",
"enode://6f10052847a966a725c9f4adf6716f9141155b99a0fb487fea3f51498f4c2a2cb8d534e680ee678f9447db85b93ff7c74562762c3714783a7233ac448603b25f@107.21.251.55:30301"
],
@@ -12574,4 +12574,4 @@
"balance": "0x0"
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Nethermind/Directory.Build.props b/src/Nethermind/Directory.Build.props
index 5a068779c77..b1ac734da65 100644
--- a/src/Nethermind/Directory.Build.props
+++ b/src/Nethermind/Directory.Build.props
@@ -13,8 +13,8 @@
$([System.DateTimeOffset]::UtcNow.ToUnixTimeSeconds())
Demerzel Solutions Limited
Nethermind
- $(Commit.Substring(0, 8))
- 1.26.0
+ $(Commit)
+ 1.27.0
unstable
@@ -23,10 +23,6 @@
<_Parameter1>BuildTimestamp
<_Parameter2>$(BuildTimestamp)
-
- <_Parameter1>Commit
- <_Parameter2>$(Commit)
-
diff --git a/src/Nethermind/Directory.Packages.props b/src/Nethermind/Directory.Packages.props
index 1f3ac180c03..5d784e7530d 100644
--- a/src/Nethermind/Directory.Packages.props
+++ b/src/Nethermind/Directory.Packages.props
@@ -3,62 +3,63 @@
true
-
-
-
-
-
-
+
+
+
+
+
+
+
-
+
-
-
+
+
-
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
+
-
+
-
-
+
+
-
+
-
-
+
+
-
-
+
@@ -66,14 +67,14 @@
-
+
-
+
-
-
+
+
\ No newline at end of file
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinBlockChainTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinBlockChainTests.cs
new file mode 100644
index 00000000000..bc1ba343cf8
--- /dev/null
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinBlockChainTests.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Ethereum.Test.Base;
+using NUnit.Framework;
+
+namespace Ethereum.Blockchain.Pyspec.Test;
+
+[TestFixture]
+[Parallelizable(ParallelScope.All)]
+public class BerlinBlockChainTests : BlockchainTestBase
+{
+ [TestCaseSource(nameof(LoadTests))]
+ public async Task Test(BlockchainTest test) => await RunTest(test);
+
+ private static IEnumerable LoadTests()
+ {
+ TestsSourceLoader loader = new(new LoadPyspecTestsStrategy(), "fixtures/blockchain_tests/berlin");
+ return loader.LoadTests().Cast();
+ }
+}
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinStateTests.cs
new file mode 100644
index 00000000000..34346dc7e0f
--- /dev/null
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinStateTests.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using System.Linq;
+using Ethereum.Test.Base;
+using FluentAssertions;
+using NUnit.Framework;
+
+namespace Ethereum.Blockchain.Pyspec.Test;
+
+[TestFixture]
+[Parallelizable(ParallelScope.All)]
+public class BerlinStateTests : GeneralStateTestBase
+{
+ [TestCaseSource(nameof(LoadTests))]
+ public void Test(GeneralStateTest test) => RunTest(test).Pass.Should().BeTrue();
+
+ private static IEnumerable LoadTests()
+ {
+ TestsSourceLoader loader = new(new LoadPyspecTestsStrategy(), $"fixtures/state_tests/berlin");
+ return loader.LoadTests().Cast();
+ }
+}
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumBlockChainTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumBlockChainTests.cs
new file mode 100644
index 00000000000..08c90d0e5a8
--- /dev/null
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumBlockChainTests.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Ethereum.Test.Base;
+using NUnit.Framework;
+
+namespace Ethereum.Blockchain.Pyspec.Test;
+
+[TestFixture]
+[Parallelizable(ParallelScope.All)]
+public class ByzantiumBlockChainTests : BlockchainTestBase
+{
+ [TestCaseSource(nameof(LoadTests))]
+ public async Task Test(BlockchainTest test) => await RunTest(test);
+
+ private static IEnumerable LoadTests()
+ {
+ TestsSourceLoader loader = new(new LoadPyspecTestsStrategy(), "fixtures/blockchain_tests/byzantium");
+ return loader.LoadTests().Cast();
+ }
+}
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumStateTests.cs
new file mode 100644
index 00000000000..6ef336fcd70
--- /dev/null
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumStateTests.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using System.Linq;
+using Ethereum.Test.Base;
+using FluentAssertions;
+using NUnit.Framework;
+
+namespace Ethereum.Blockchain.Pyspec.Test;
+
+[TestFixture]
+[Parallelizable(ParallelScope.All)]
+public class ByzantiumStateTests : GeneralStateTestBase
+{
+ [TestCaseSource(nameof(LoadTests))]
+ public void Test(GeneralStateTest test) => RunTest(test).Pass.Should().BeTrue();
+
+ private static IEnumerable LoadTests()
+ {
+ TestsSourceLoader loader = new(new LoadPyspecTestsStrategy(), $"fixtures/state_tests/byzantium");
+ return loader.LoadTests().Cast();
+ }
+}
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/CancunStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/CancunStateTests.cs
index 5a0082d4b28..737487c2740 100644
--- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/CancunStateTests.cs
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/CancunStateTests.cs
@@ -13,8 +13,6 @@ namespace Ethereum.Blockchain.Pyspec.Test;
[Parallelizable(ParallelScope.All)]
public class CancunStateTests : GeneralStateTestBase
{
-
- [Explicit("We are failing some of those tests")]
[TestCaseSource(nameof(LoadTests))]
public void Test(GeneralStateTest test) => RunTest(test).Pass.Should().BeTrue();
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierBlockChainTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierBlockChainTests.cs
new file mode 100644
index 00000000000..c289ecc91bc
--- /dev/null
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierBlockChainTests.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Ethereum.Test.Base;
+using NUnit.Framework;
+
+namespace Ethereum.Blockchain.Pyspec.Test;
+
+[TestFixture]
+[Parallelizable(ParallelScope.All)]
+public class FrontierBlockChainTests : BlockchainTestBase
+{
+ [TestCaseSource(nameof(LoadTests))]
+ public async Task Test(BlockchainTest test) => await RunTest(test);
+
+ private static IEnumerable LoadTests()
+ {
+ TestsSourceLoader loader = new(new LoadPyspecTestsStrategy(), "fixtures/blockchain_tests/frontier");
+ return loader.LoadTests().Cast();
+ }
+}
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierStateTests.cs
new file mode 100644
index 00000000000..89526a552bf
--- /dev/null
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierStateTests.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using System.Linq;
+using Ethereum.Test.Base;
+using FluentAssertions;
+using NUnit.Framework;
+
+namespace Ethereum.Blockchain.Pyspec.Test;
+
+[TestFixture]
+[Parallelizable(ParallelScope.All)]
+public class FrontierStateTests : GeneralStateTestBase
+{
+ [TestCaseSource(nameof(LoadTests))]
+ public void Test(GeneralStateTest test) => RunTest(test).Pass.Should().BeTrue();
+
+ private static IEnumerable LoadTests()
+ {
+ TestsSourceLoader loader = new(new LoadPyspecTestsStrategy(), $"fixtures/state_tests/frontier");
+ return loader.LoadTests().Cast();
+ }
+}
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadBlockChainTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadBlockChainTests.cs
new file mode 100644
index 00000000000..e73cc62f28f
--- /dev/null
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadBlockChainTests.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Ethereum.Test.Base;
+using NUnit.Framework;
+
+namespace Ethereum.Blockchain.Pyspec.Test;
+
+[TestFixture]
+[Parallelizable(ParallelScope.All)]
+public class HomesteadBlockChainTests : BlockchainTestBase
+{
+ [TestCaseSource(nameof(LoadTests))]
+ public async Task Test(BlockchainTest test) => await RunTest(test);
+
+ private static IEnumerable LoadTests()
+ {
+ TestsSourceLoader loader = new(new LoadPyspecTestsStrategy(), "fixtures/blockchain_tests/homestead");
+ return loader.LoadTests().Cast();
+ }
+}
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadStateTests.cs
new file mode 100644
index 00000000000..48bee00d4ff
--- /dev/null
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadStateTests.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using System.Linq;
+using Ethereum.Test.Base;
+using FluentAssertions;
+using NUnit.Framework;
+
+namespace Ethereum.Blockchain.Pyspec.Test;
+
+[TestFixture]
+[Parallelizable(ParallelScope.All)]
+public class HomesteadStateTests : GeneralStateTestBase
+{
+ [TestCaseSource(nameof(LoadTests))]
+ public void Test(GeneralStateTest test) => RunTest(test).Pass.Should().BeTrue();
+
+ private static IEnumerable LoadTests()
+ {
+ TestsSourceLoader loader = new(new LoadPyspecTestsStrategy(), $"fixtures/state_tests/homestead");
+ return loader.LoadTests().Cast();
+ }
+}
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulBlockChainTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulBlockChainTests.cs
new file mode 100644
index 00000000000..5a239c1c93e
--- /dev/null
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulBlockChainTests.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Ethereum.Test.Base;
+using NUnit.Framework;
+
+namespace Ethereum.Blockchain.Pyspec.Test;
+
+[TestFixture]
+[Parallelizable(ParallelScope.All)]
+public class IstanbulBlockChainTests : BlockchainTestBase
+{
+ [TestCaseSource(nameof(LoadTests))]
+ public async Task Test(BlockchainTest test) => await RunTest(test);
+
+ private static IEnumerable LoadTests()
+ {
+ TestsSourceLoader loader = new(new LoadPyspecTestsStrategy(), "fixtures/blockchain_tests/istanbul");
+ return loader.LoadTests().Cast();
+ }
+}
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulStateTests.cs
new file mode 100644
index 00000000000..41274723230
--- /dev/null
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulStateTests.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using System.Linq;
+using Ethereum.Test.Base;
+using FluentAssertions;
+using NUnit.Framework;
+
+namespace Ethereum.Blockchain.Pyspec.Test;
+
+[TestFixture]
+[Parallelizable(ParallelScope.All)]
+public class IstanbulStateTests : GeneralStateTestBase
+{
+ [TestCaseSource(nameof(LoadTests))]
+ public void Test(GeneralStateTest test) => RunTest(test).Pass.Should().BeTrue();
+
+ private static IEnumerable LoadTests()
+ {
+ TestsSourceLoader loader = new(new LoadPyspecTestsStrategy(), $"fixtures/state_tests/istanbul");
+ return loader.LoadTests().Cast();
+ }
+}
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ParisBlockChainTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ParisBlockChainTests.cs
new file mode 100644
index 00000000000..a9ff1201768
--- /dev/null
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ParisBlockChainTests.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Ethereum.Test.Base;
+using NUnit.Framework;
+
+namespace Ethereum.Blockchain.Pyspec.Test;
+
+[TestFixture]
+[Parallelizable(ParallelScope.All)]
+public class ParisBlockChainTests : BlockchainTestBase
+{
+ [TestCaseSource(nameof(LoadTests))]
+ public async Task Test(BlockchainTest test) => await RunTest(test);
+
+ private static IEnumerable LoadTests()
+ {
+ TestsSourceLoader loader = new(new LoadPyspecTestsStrategy(), "fixtures/blockchain_tests/paris");
+ return loader.LoadTests().Cast();
+ }
+}
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiBlockChainTests.cs
similarity index 92%
rename from src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiTests.cs
rename to src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiBlockChainTests.cs
index 0c3928f6233..8a9aded47ca 100644
--- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiTests.cs
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiBlockChainTests.cs
@@ -11,7 +11,7 @@ namespace Ethereum.Blockchain.Pyspec.Test;
[TestFixture]
[Parallelizable(ParallelScope.All)]
-public class ShanghaiTests : BlockchainTestBase
+public class ShanghaiBlockChainTests : BlockchainTestBase
{
[TestCaseSource(nameof(LoadTests))]
public async Task Test(BlockchainTest test) => await RunTest(test);
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiStateTests.cs
new file mode 100644
index 00000000000..efab53db059
--- /dev/null
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiStateTests.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using System.Linq;
+using Ethereum.Test.Base;
+using FluentAssertions;
+using NUnit.Framework;
+
+namespace Ethereum.Blockchain.Pyspec.Test;
+
+[TestFixture]
+[Parallelizable(ParallelScope.All)]
+public class ShanghaiStateTests : GeneralStateTestBase
+{
+ [TestCaseSource(nameof(LoadTests))]
+ public void Test(GeneralStateTest test) => RunTest(test).Pass.Should().BeTrue();
+
+ private static IEnumerable LoadTests()
+ {
+ TestsSourceLoader loader = new(new LoadPyspecTestsStrategy(), $"fixtures/state_tests/shanghai");
+ return loader.LoadTests().Cast();
+ }
+}
diff --git a/src/Nethermind/Ethereum.Blockchain.Test/MetaTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/MetaTests.cs
index 4d6b6752274..6797ee8c60d 100644
--- a/src/Nethermind/Ethereum.Blockchain.Test/MetaTests.cs
+++ b/src/Nethermind/Ethereum.Blockchain.Test/MetaTests.cs
@@ -37,7 +37,7 @@ public void All_categories_are_tested()
{
string expectedTypeName = ExpectedTypeName(directory).Replace("-", "");
Type type = types.SingleOrDefault(t => string.Equals(t.Name, expectedTypeName, StringComparison.InvariantCultureIgnoreCase));
- if (type == null && !excludesDirectories.Contains(directory))
+ if (type is null && !excludesDirectories.Contains(directory))
{
if (new DirectoryInfo(directory).GetFiles().Any(f => f.Name.Contains(".resources.")))
{
diff --git a/src/Nethermind/Ethereum.Rlp.Test/RlpTests.cs b/src/Nethermind/Ethereum.Rlp.Test/RlpTests.cs
index 2a1369a1ed6..6185329ed45 100644
--- a/src/Nethermind/Ethereum.Rlp.Test/RlpTests.cs
+++ b/src/Nethermind/Ethereum.Rlp.Test/RlpTests.cs
@@ -185,7 +185,7 @@ public void PerfTest()
stopwatch.Stop();
Console.WriteLine($"2nd: {stopwatch.ElapsedMilliseconds}");
- if (block == null || perfBlock == null || block.Number != perfBlock.Number)
+ if (block is null || perfBlock is null || block.Number != perfBlock.Number)
{
throw new Exception();
}
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
index ad4d7078b2c..cba811e90e4 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
@@ -148,15 +148,18 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
IHeaderValidator headerValidator = new HeaderValidator(blockTree, Sealer, specProvider, _logManager);
IUnclesValidator unclesValidator = new UnclesValidator(blockTree, headerValidator, _logManager);
IBlockValidator blockValidator = new BlockValidator(txValidator, headerValidator, unclesValidator, specProvider, _logManager);
+ CodeInfoRepository codeInfoRepository = new();
IVirtualMachine virtualMachine = new VirtualMachine(
blockhashProvider,
specProvider,
+ codeInfoRepository,
_logManager);
TransactionProcessor? txProcessor = new(
specProvider,
stateProvider,
virtualMachine,
+ codeInfoRepository,
_logManager);
IBlockProcessor blockProcessor = new BlockProcessor(
@@ -167,7 +170,6 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
stateProvider),
stateProvider,
receiptStorage,
- NullWitnessCollector.Instance,
new BlockhashStore(blockTree, specProvider, stateProvider),
txProcessor,
_logManager);
@@ -340,13 +342,13 @@ private void InitializeTestState(BlockchainTest test, IWorldState stateProvider,
private List RunAssertions(BlockchainTest test, Block headBlock, IWorldState stateProvider)
{
- if (test.PostStateRoot != null)
+ if (test.PostStateRoot is not null)
{
return test.PostStateRoot != stateProvider.StateRoot ? new List { "state root mismatch" } : Enumerable.Empty().ToList();
}
TestBlockHeaderJson testHeaderJson = (test.Blocks?
- .Where(b => b.BlockHeader != null)
+ .Where(b => b.BlockHeader is not null)
.SingleOrDefault(b => new Hash256(b.BlockHeader.Hash) == headBlock.Hash)?.BlockHeader) ?? test.GenesisBlockHeader;
BlockHeader testHeader = JsonToEthereumTest.Convert(testHeaderJson);
List differences = new();
diff --git a/src/Nethermind/Ethereum.Test.Base/FileTestsSource.cs b/src/Nethermind/Ethereum.Test.Base/FileTestsSource.cs
index 71fa118309e..2e0baece45e 100644
--- a/src/Nethermind/Ethereum.Test.Base/FileTestsSource.cs
+++ b/src/Nethermind/Ethereum.Test.Base/FileTestsSource.cs
@@ -29,7 +29,7 @@ public IEnumerable LoadGeneralStateTests()
return Enumerable.Empty();
}
- if (_wildcard != null && !_fileName.Contains(_wildcard))
+ if (_wildcard is not null && !_fileName.Contains(_wildcard))
{
return Enumerable.Empty();
}
@@ -52,7 +52,7 @@ public IEnumerable LoadBlockchainTests()
return Enumerable.Empty();
}
- if (_wildcard != null && !_fileName.Contains(_wildcard))
+ if (_wildcard is not null && !_fileName.Contains(_wildcard))
{
return Enumerable.Empty();
}
diff --git a/src/Nethermind/Ethereum.Test.Base/GeneralStateTest.cs b/src/Nethermind/Ethereum.Test.Base/GeneralStateTest.cs
index d3190aa83bf..09158536941 100644
--- a/src/Nethermind/Ethereum.Test.Base/GeneralStateTest.cs
+++ b/src/Nethermind/Ethereum.Test.Base/GeneralStateTest.cs
@@ -33,6 +33,7 @@ public class GeneralStateTest : IEthereumTest
public Hash256? CurrentRandom { get; set; }
public Hash256? CurrentBeaconRoot { get; set; }
public Hash256? CurrentWithdrawalsRoot { get; set; }
+ public ulong? CurrentExcessBlobGas { get; set; }
public UInt256? ParentBlobGasUsed { get; set; }
public UInt256? ParentExcessBlobGas { get; set; }
diff --git a/src/Nethermind/Ethereum.Test.Base/GeneralStateTestEnvJson.cs b/src/Nethermind/Ethereum.Test.Base/GeneralStateTestEnvJson.cs
index f94f6015a02..a82748257d9 100644
--- a/src/Nethermind/Ethereum.Test.Base/GeneralStateTestEnvJson.cs
+++ b/src/Nethermind/Ethereum.Test.Base/GeneralStateTestEnvJson.cs
@@ -19,6 +19,7 @@ public class GeneralStateTestEnvJson
public Hash256? CurrentRandom { get; set; }
public Hash256? CurrentBeaconRoot { get; set; }
public Hash256? CurrentWithdrawalsRoot { get; set; }
+ public ulong? CurrentExcessBlobGas { get; set; }
public UInt256? ParentBlobGasUsed { get; set; }
public UInt256? ParentExcessBlobGas { get; set; }
}
diff --git a/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs b/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs
index 35b1533d69b..9965d252324 100644
--- a/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs
@@ -4,11 +4,14 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using Nethermind.Blockchain;
+using Nethermind.Consensus.Ethash;
using Nethermind.Consensus.Validators;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Extensions;
using Nethermind.Core.Specs;
+using Nethermind.Core.Test.Builders;
using Nethermind.Crypto;
using Nethermind.Db;
using Nethermind.Int256;
@@ -30,6 +33,7 @@ public abstract class GeneralStateTestBase
private static ILogger _logger = new(new ConsoleAsyncLogger(LogLevel.Info));
private static ILogManager _logManager = LimboLogs.Instance;
private static UInt256 _defaultBaseFeeForStateTest = 0xA;
+ private readonly TxValidator _txValidator = new(MainnetSpecProvider.Instance.ChainId);
[SetUp]
public void Setup()
@@ -67,15 +71,18 @@ protected EthereumTestResult RunTest(GeneralStateTest test, ITxTracer txTracer)
TrieStore trieStore = new(stateDb, _logManager);
WorldState stateProvider = new(trieStore, codeDb, _logManager);
IBlockhashProvider blockhashProvider = new TestBlockhashProvider();
+ CodeInfoRepository codeInfoRepository = new();
IVirtualMachine virtualMachine = new VirtualMachine(
blockhashProvider,
specProvider,
+ codeInfoRepository,
_logManager);
TransactionProcessor transactionProcessor = new(
specProvider,
stateProvider,
virtualMachine,
+ codeInfoRepository,
_logManager);
InitializeTestState(test, stateProvider, specProvider);
@@ -96,13 +103,16 @@ protected EthereumTestResult RunTest(GeneralStateTest test, ITxTracer txTracer)
header.MixHash = test.CurrentRandom;
header.WithdrawalsRoot = test.CurrentWithdrawalsRoot;
header.ParentBeaconBlockRoot = test.CurrentBeaconRoot;
- header.ExcessBlobGas = 0;
+ header.ExcessBlobGas = test.CurrentExcessBlobGas ?? (test.Fork is Cancun ? 0ul : null);
+ header.BlobGasUsed = BlobGasCalculator.CalculateBlobGas(test.Transaction);
header.RequestsRoot = test.RequestsRoot;
Stopwatch stopwatch = Stopwatch.StartNew();
- TxValidator? txValidator = new((MainnetSpecProvider.Instance.ChainId));
IReleaseSpec? spec = specProvider.GetSpec((ForkActivation)test.CurrentNumber);
- if (test.Transaction.ChainId == null)
+
+ if (spec is Cancun) KzgPolynomialCommitments.InitializeAsync();
+
+ if (test.Transaction.ChainId is null)
test.Transaction.ChainId = MainnetSpecProvider.Instance.ChainId;
if (test.ParentBlobGasUsed is not null && test.ParentExcessBlobGas is not null)
{
@@ -122,7 +132,11 @@ protected EthereumTestResult RunTest(GeneralStateTest test, ITxTracer txTracer)
};
header.ExcessBlobGas = BlobGasCalculator.CalculateExcessBlobGas(parent, spec);
}
- bool isValid = txValidator.IsWellFormed(test.Transaction, spec);
+
+ Block block = Build.A.Block.WithTransactions(test.Transaction).WithHeader(header).TestObject;
+
+ bool isValid = _txValidator.IsWellFormed(test.Transaction, spec) && IsValidBlock(block, specProvider);
+
if (isValid)
transactionProcessor.Execute(test.Transaction, new BlockExecutionContext(header), txTracer);
stopwatch.Stop();
@@ -168,6 +182,22 @@ private static void InitializeTestState(GeneralStateTest test, WorldState stateP
stateProvider.Reset();
}
+ private bool IsValidBlock(Block block, ISpecProvider specProvider)
+ {
+ IBlockTree blockTree = Build.A.BlockTree()
+ .WithSpecProvider(specProvider)
+ .WithoutSettingHead
+ .TestObject;
+
+ var difficultyCalculator = new EthashDifficultyCalculator(specProvider);
+ var sealer = new EthashSealValidator(_logManager, difficultyCalculator, new CryptoRandom(), new Ethash(_logManager), Timestamper.Default);
+ IHeaderValidator headerValidator = new HeaderValidator(blockTree, sealer, specProvider, _logManager);
+ IUnclesValidator unclesValidator = new UnclesValidator(blockTree, headerValidator, _logManager);
+ IBlockValidator blockValidator = new BlockValidator(_txValidator, headerValidator, unclesValidator, specProvider, _logManager);
+
+ return blockValidator.ValidateOrphanedBlock(block, out _);
+ }
+
private List RunAssertions(GeneralStateTest test, IWorldState stateProvider)
{
List differences = new();
diff --git a/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs b/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs
index f745b72618d..5e33bde1488 100644
--- a/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs
+++ b/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs
@@ -85,7 +85,7 @@ private static ForkActivation TransitionForkActivation(string transitionInfo)
public static BlockHeader Convert(TestBlockHeaderJson? headerJson)
{
- if (headerJson == null)
+ if (headerJson is null)
{
throw new InvalidDataException("Header JSON was null when constructing test.");
}
@@ -151,7 +151,7 @@ public static Transaction Convert(PostStateJson postStateJson, TransactionJson t
else
transaction.AccessList = null;
- if (transactionJson.MaxFeePerGas != null)
+ if (transactionJson.MaxFeePerGas is not null)
transaction.Type = TxType.EIP1559;
if (transaction.BlobVersionedHashes?.Length > 0)
@@ -202,7 +202,7 @@ private static AccountState Convert(AccountStateJson accountStateJson)
public static IEnumerable Convert(string name, GeneralStateTestJson testJson)
{
- if (testJson.LoadFailure != null)
+ if (testJson.LoadFailure is not null)
{
return Enumerable.Repeat(new GeneralStateTest { Name = name, LoadFailure = testJson.LoadFailure }, 1);
}
@@ -234,6 +234,7 @@ public static IEnumerable Convert(string name, GeneralStateTes
test.CurrentRandom = testJson.Env.CurrentRandom;
test.CurrentBeaconRoot = testJson.Env.CurrentBeaconRoot;
test.CurrentWithdrawalsRoot = testJson.Env.CurrentWithdrawalsRoot;
+ test.CurrentExcessBlobGas = testJson.Env.CurrentExcessBlobGas;
test.ParentBlobGasUsed = testJson.Env.ParentBlobGasUsed;
test.ParentExcessBlobGas = testJson.Env.ParentExcessBlobGas;
test.PostReceiptsRoot = stateJson.Logs;
@@ -251,7 +252,7 @@ public static IEnumerable Convert(string name, GeneralStateTes
public static BlockchainTest Convert(string name, BlockchainTestJson testJson)
{
- if (testJson.LoadFailure != null)
+ if (testJson.LoadFailure is not null)
{
return new BlockchainTest { Name = name, LoadFailure = testJson.LoadFailure };
}
@@ -262,13 +263,13 @@ public static BlockchainTest Convert(string name, BlockchainTestJson testJson)
test.NetworkAfterTransition = testJson.EthereumNetworkAfterTransition;
test.TransitionForkActivation = testJson.TransitionForkActivation;
test.LastBlockHash = new Hash256(testJson.LastBlockHash);
- test.GenesisRlp = testJson.GenesisRlp == null ? null : new Rlp(Bytes.FromHexString(testJson.GenesisRlp));
+ test.GenesisRlp = testJson.GenesisRlp is null ? null : new Rlp(Bytes.FromHexString(testJson.GenesisRlp));
test.GenesisBlockHeader = testJson.GenesisBlockHeader;
test.Blocks = testJson.Blocks;
test.Pre = testJson.Pre.ToDictionary(p => new Address(p.Key), p => Convert(p.Value));
HalfBlockchainTestJson half = testJson as HalfBlockchainTestJson;
- if (half != null)
+ if (half is not null)
{
test.PostStateRoot = half.PostState;
}
diff --git a/src/Nethermind/Ethereum.Test.Base/TestLoader.cs b/src/Nethermind/Ethereum.Test.Base/TestLoader.cs
index a3670fe5cba..4a910f73123 100644
--- a/src/Nethermind/Ethereum.Test.Base/TestLoader.cs
+++ b/src/Nethermind/Ethereum.Test.Base/TestLoader.cs
@@ -58,7 +58,7 @@ public static IEnumerable LoadFromFile(
Assembly assembly = typeof(TTest).Assembly;
string[] resourceNames = assembly.GetManifestResourceNames();
string resourceName = resourceNames.SingleOrDefault(r => r.Contains(testFileName));
- if (resourceName == null)
+ if (resourceName is null)
{
throw new ArgumentException($"Cannot find test resource: {testFileName}");
}
diff --git a/src/Nethermind/Ethereum.Transaction.Test/TransactionTests.cs b/src/Nethermind/Ethereum.Transaction.Test/TransactionTests.cs
index 9d005329538..23682737ab7 100644
--- a/src/Nethermind/Ethereum.Transaction.Test/TransactionTests.cs
+++ b/src/Nethermind/Ethereum.Transaction.Test/TransactionTests.cs
@@ -57,7 +57,7 @@ private static IEnumerable LoadTests(string testSet)
{
TransactionJson transactionJson = byName.Value.Transaction;
TransactionTest test;
- if (transactionJson != null)
+ if (transactionJson is not null)
{
test = new ValidTransactionTest(byDir.Key, byName.Key, byName.Value.Rlp);
ValidTransactionTest validTest = (ValidTransactionTest)test;
@@ -165,7 +165,7 @@ private void RunTest(TransactionTest test, IReleaseSpec spec)
}
catch (Exception)
{
- if (validTest == null)
+ if (validTest is null)
{
return;
}
@@ -177,7 +177,7 @@ private void RunTest(TransactionTest test, IReleaseSpec spec)
TxValidator validator = new(useChainId ? BlockchainIds.Mainnet : 0UL);
- if (validTest != null)
+ if (validTest is not null)
{
Assert.That(transaction.Value, Is.EqualTo(validTest.Value), "value");
Assert.That(transaction.Data.AsArray(), Is.EqualTo(validTest.Data), "data");
diff --git a/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.TestAccountAbstractionRpcBlockchain.cs b/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.TestAccountAbstractionRpcBlockchain.cs
index 0f2e685dc5c..9403f6b893f 100644
--- a/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.TestAccountAbstractionRpcBlockchain.cs
+++ b/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.TestAccountAbstractionRpcBlockchain.cs
@@ -122,19 +122,18 @@ protected override IBlockProducer CreateTestBlockProducer(TxPoolTxSource txPoolT
UserOperationTxSource = new(UserOperationTxBuilder, UserOperationPool, UserOperationSimulator, SpecProvider, State, Signer, LogManager.GetClassLogger());
- PostMergeBlockProducer CreatePostMergeBlockProducer(IBlockProductionTrigger blockProductionTrigger,
- ITxSource? txSource = null)
+ PostMergeBlockProducer CreatePostMergeBlockProducer(ITxSource? txSource = null)
{
var blockProducerEnv = blockProducerEnvFactory.Create(txSource);
return new PostMergeBlockProducerFactory(SpecProvider, SealEngine, Timestamper, blocksConfig,
LogManager, GasLimitCalculator).Create(
- blockProducerEnv, blockProductionTrigger);
+ blockProducerEnv);
}
- IBlockProducer blockProducer =
- CreatePostMergeBlockProducer(BlockProductionTrigger, UserOperationTxSource);
+ IBlockProducer blockProducer = CreatePostMergeBlockProducer(UserOperationTxSource);
- blockProducer.BlockProduced += OnBlockProduced;
+ BlockProducerRunner = new StandardBlockProducerRunner(BlockProductionTrigger, BlockTree, blockProducer);
+ BlockProducerRunner.BlockProduced += OnBlockProduced;
return blockProducer;
}
@@ -190,7 +189,6 @@ protected override BlockProcessor CreateBlockProcessor()
new BlockProcessor.BlockValidationTransactionsExecutor(TxProcessor, State),
State,
ReceiptStorage,
- NullWitnessCollector.Instance,
new BlockhashStore(BlockTree, SpecProvider, State),
TxProcessor,
LogManager);
diff --git a/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.cs b/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.cs
index a08ba710e10..6862acc8a0b 100644
--- a/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.cs
+++ b/src/Nethermind/Nethermind.AccountAbstraction.Test/AccountAbstractionRpcModuleTests.cs
@@ -18,6 +18,7 @@
using Nethermind.Core.Extensions;
using Nethermind.Core.Test.Builders;
using Nethermind.Crypto;
+using Nethermind.Facade.Eth;
using Nethermind.Int256;
using Nethermind.JsonRpc.Data;
using Nethermind.JsonRpc.Test.Modules;
diff --git a/src/Nethermind/Nethermind.AccountAbstraction.Test/Network/UserOperationsMessageSerializerTests.cs b/src/Nethermind/Nethermind.AccountAbstraction.Test/Network/UserOperationsMessageSerializerTests.cs
index 26ffda723f3..3532209a60c 100644
--- a/src/Nethermind/Nethermind.AccountAbstraction.Test/Network/UserOperationsMessageSerializerTests.cs
+++ b/src/Nethermind/Nethermind.AccountAbstraction.Test/Network/UserOperationsMessageSerializerTests.cs
@@ -16,10 +16,10 @@ namespace Nethermind.AccountAbstraction.Test.Network
[TestFixture, Parallelizable(ParallelScope.All)]
public class UserOperationsMessageSerializerTests
{
- [SetUp]
- public void Setup()
+ [OneTimeSetUp]
+ public void OneTimeSetUp()
{
- Rlp.RegisterDecoders(typeof(UserOperationDecoder).Assembly);
+ Rlp.RegisterDecoders(typeof(UserOperationDecoder).Assembly, true);
}
[Test]
diff --git a/src/Nethermind/Nethermind.AccountAbstraction/AccountAbstractionPlugin.cs b/src/Nethermind/Nethermind.AccountAbstraction/AccountAbstractionPlugin.cs
index 1a1198df67d..327b7715335 100644
--- a/src/Nethermind/Nethermind.AccountAbstraction/AccountAbstractionPlugin.cs
+++ b/src/Nethermind/Nethermind.AccountAbstraction/AccountAbstractionPlugin.cs
@@ -123,7 +123,7 @@ private UserOperationSimulator UserOperationSimulator(Address entryPoint)
ReadOnlyTxProcessingEnvFactory readOnlyTxProcessingEnvFactory = new(
getFromApi.WorldStateManager!,
- getFromApi.BlockTree,
+ getFromApi.BlockTree!,
getFromApi.SpecProvider,
getFromApi.LogManager);
@@ -348,7 +348,7 @@ public ValueTask DisposeAsync()
return ValueTask.CompletedTask;
}
- public Task InitBlockProducer(IBlockProducerFactory consensusPlugin, IBlockProductionTrigger blockProductionTrigger, ITxSource? additionalTxSource)
+ public IBlockProducer InitBlockProducer(IBlockProducerFactory consensusPlugin, ITxSource? additionalTxSource)
{
if (!Enabled) throw new InvalidOperationException("Account Abstraction plugin is disabled");
@@ -378,9 +378,7 @@ public Task InitBlockProducer(IBlockProducerFactory consensusPlu
$"Account Abstraction Plugin: Miner ({_nethermindApi.EngineSigner!.Address}) Ether balance adequate - {minerBalance / 1.Ether()} Ether");
}
- IManualBlockProductionTrigger trigger = new BuildBlocksWhenRequested();
-
- return consensusPlugin.InitBlockProducer(trigger, UserOperationTxSource);
+ return consensusPlugin.InitBlockProducer(UserOperationTxSource);
}
public bool MevPluginEnabled => _nethermindApi.Config().Enabled;
diff --git a/src/Nethermind/Nethermind.AccountAbstraction/AccountAbstractionRpcModule.cs b/src/Nethermind/Nethermind.AccountAbstraction/AccountAbstractionRpcModule.cs
index c25d80ff850..e7629f3d75a 100644
--- a/src/Nethermind/Nethermind.AccountAbstraction/AccountAbstractionRpcModule.cs
+++ b/src/Nethermind/Nethermind.AccountAbstraction/AccountAbstractionRpcModule.cs
@@ -19,7 +19,7 @@ public class AccountAbstractionRpcModule : IAccountAbstractionRpcModule
static AccountAbstractionRpcModule()
{
- Rlp.RegisterDecoders(typeof(UserOperationDecoder).Assembly);
+ Rlp.RegisterDecoders(typeof(UserOperationDecoder).Assembly, true);
}
public AccountAbstractionRpcModule(IDictionary userOperationPool, Address[] supportedEntryPoints)
diff --git a/src/Nethermind/Nethermind.AccountAbstraction/Broadcaster/PeerInfo.cs b/src/Nethermind/Nethermind.AccountAbstraction/Broadcaster/PeerInfo.cs
index 487e62bbc08..41cb3d53438 100644
--- a/src/Nethermind/Nethermind.AccountAbstraction/Broadcaster/PeerInfo.cs
+++ b/src/Nethermind/Nethermind.AccountAbstraction/Broadcaster/PeerInfo.cs
@@ -12,7 +12,7 @@ public class PeerInfo : IUserOperationPoolPeer
{
private IUserOperationPoolPeer Peer { get; }
- private LruKeyCache NotifiedUserOperations { get; } = new(MemoryAllowance.MemPoolSize, "notifiedUserOperations");
+ private LruKeyCacheLowObject NotifiedUserOperations { get; } = new(MemoryAllowance.MemPoolSize, "notifiedUserOperations");
public PeerInfo(IUserOperationPoolPeer peer)
{
diff --git a/src/Nethermind/Nethermind.AccountAbstraction/Executor/AABlockProducerTransactionsExecutorFactory.cs b/src/Nethermind/Nethermind.AccountAbstraction/Executor/AABlockProducerTransactionsExecutorFactory.cs
index 8dd11b9d59c..42f344bc7fd 100644
--- a/src/Nethermind/Nethermind.AccountAbstraction/Executor/AABlockProducerTransactionsExecutorFactory.cs
+++ b/src/Nethermind/Nethermind.AccountAbstraction/Executor/AABlockProducerTransactionsExecutorFactory.cs
@@ -6,6 +6,7 @@
using Nethermind.Consensus.Producers;
using Nethermind.Core;
using Nethermind.Core.Specs;
+using Nethermind.Evm.TransactionProcessing;
using Nethermind.Logging;
namespace Nethermind.AccountAbstraction.Executor
@@ -25,10 +26,10 @@ public AABlockProducerTransactionsExecutorFactory(ISpecProvider specProvider, IL
_entryPointAddresses = entryPointAddresses;
}
- public IBlockProcessor.IBlockTransactionsExecutor Create(ReadOnlyTxProcessingEnv readOnlyTxProcessingEnv)
+ public IBlockProcessor.IBlockTransactionsExecutor Create(IReadOnlyTxProcessingScope readOnlyTxProcessingEnv)
=> new AABlockProducerTransactionsExecutor(
readOnlyTxProcessingEnv.TransactionProcessor,
- readOnlyTxProcessingEnv.StateProvider,
+ readOnlyTxProcessingEnv.WorldState,
_specProvider,
_logManager,
_signer,
diff --git a/src/Nethermind/Nethermind.AccountAbstraction/Executor/IUserOperationSimulator.cs b/src/Nethermind/Nethermind.AccountAbstraction/Executor/IUserOperationSimulator.cs
index 6781e276de8..d4af7269707 100644
--- a/src/Nethermind/Nethermind.AccountAbstraction/Executor/IUserOperationSimulator.cs
+++ b/src/Nethermind/Nethermind.AccountAbstraction/Executor/IUserOperationSimulator.cs
@@ -18,7 +18,7 @@ ResultWrapper Simulate(UserOperation userOperation,
UInt256? timestamp = null,
CancellationToken cancellationToken = default);
- BlockchainBridge.CallOutput EstimateGas(BlockHeader header, Transaction tx,
+ CallOutput EstimateGas(BlockHeader header, Transaction tx,
CancellationToken cancellationToken);
}
}
diff --git a/src/Nethermind/Nethermind.AccountAbstraction/Executor/UserOperationSimulator.cs b/src/Nethermind/Nethermind.AccountAbstraction/Executor/UserOperationSimulator.cs
index e2bd4f8a0b4..f8835cabfb1 100644
--- a/src/Nethermind/Nethermind.AccountAbstraction/Executor/UserOperationSimulator.cs
+++ b/src/Nethermind/Nethermind.AccountAbstraction/Executor/UserOperationSimulator.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Runtime.CompilerServices;
using System.Threading;
using Nethermind.Abi;
using Nethermind.AccountAbstraction.Data;
@@ -86,14 +87,14 @@ public ResultWrapper Simulate(UserOperation userOperation,
}
IEip1559Spec specFor1559 = _specProvider.GetSpecFor1559(parent.Number + 1);
- ReadOnlyTxProcessingEnv txProcessingEnv = _readOnlyTxProcessingEnvFactory.Create();
- ITransactionProcessor transactionProcessor = txProcessingEnv.Build(_stateProvider.StateRoot);
+ IReadOnlyTxProcessorSource processorSource = _readOnlyTxProcessingEnvFactory.Create();
+ using IReadOnlyTxProcessingScope scope = processorSource.Build(_stateProvider.StateRoot);
// wrap userOp into a tx calling the simulateWallet function off-chain from zero-address (look at EntryPoint.sol for more context)
Transaction simulateValidationTransaction =
BuildSimulateValidationTransaction(userOperation, parent, specFor1559);
- UserOperationSimulationResult simulationResult = SimulateValidation(simulateValidationTransaction, userOperation, parent, transactionProcessor);
+ UserOperationSimulationResult simulationResult = SimulateValidation(simulateValidationTransaction, userOperation, parent, scope.TransactionProcessor);
if (!simulationResult.Success)
return ResultWrapper.Fail(simulationResult.Error ?? "unknown simulation failure");
@@ -185,24 +186,24 @@ private Transaction BuildSimulateValidationTransaction(
}
[Todo("Refactor once BlockchainBridge is separated")]
- public BlockchainBridge.CallOutput EstimateGas(BlockHeader header, Transaction tx, CancellationToken cancellationToken)
+ public CallOutput EstimateGas(BlockHeader header, Transaction tx, CancellationToken cancellationToken)
{
- ReadOnlyTxProcessingEnv txProcessingEnv = _readOnlyTxProcessingEnvFactory.Create();
- using IReadOnlyTransactionProcessor transactionProcessor = txProcessingEnv.Build(header.StateRoot!);
+ IReadOnlyTxProcessorSource txProcessorSource = _readOnlyTxProcessingEnvFactory.Create();
+ using IReadOnlyTxProcessingScope scope = txProcessorSource.Build(header.StateRoot!);
EstimateGasTracer estimateGasTracer = new();
(bool Success, string Error) tryCallResult = TryCallAndRestore(
- transactionProcessor,
+ scope.TransactionProcessor,
header,
Math.Max(header.Timestamp + 1, _timestamper.UnixTime.Seconds),
tx,
true,
estimateGasTracer.WithCancellation(cancellationToken));
- GasEstimator gasEstimator = new(transactionProcessor, _stateProvider, _specProvider, _blocksConfig);
+ GasEstimator gasEstimator = new(scope.TransactionProcessor, _stateProvider, _specProvider, _blocksConfig);
long estimate = gasEstimator.Estimate(tx, header, estimateGasTracer, GasEstimator.DefaultErrorMargin, cancellationToken);
- return new BlockchainBridge.CallOutput
+ return new CallOutput
{
Error = tryCallResult.Success ? estimateGasTracer.Error : tryCallResult.Error,
GasSpent = estimate,
diff --git a/src/Nethermind/Nethermind.AccountAbstraction/Source/UserOperationTxSource.cs b/src/Nethermind/Nethermind.AccountAbstraction/Source/UserOperationTxSource.cs
index ec6def2cd1e..4dac4b3fe47 100644
--- a/src/Nethermind/Nethermind.AccountAbstraction/Source/UserOperationTxSource.cs
+++ b/src/Nethermind/Nethermind.AccountAbstraction/Source/UserOperationTxSource.cs
@@ -172,7 +172,7 @@ public IEnumerable GetTransactions(BlockHeader parent, long gasLimi
// TODO: Remove logging, just for testing
_logger.Info($"Constructed tx from {userOperationsToInclude!.Count} userOperations: {userOperationTransaction.Hash}");
- BlockchainBridge.CallOutput callOutput = _userOperationSimulators[entryPoint].EstimateGas(parent, userOperationTransaction, CancellationToken.None);
+ CallOutput callOutput = _userOperationSimulators[entryPoint].EstimateGas(parent, userOperationTransaction, CancellationToken.None);
FailedOp? failedOp = txBuilder.DecodeEntryPointOutputError(callOutput.OutputData);
if (failedOp is not null)
{
diff --git a/src/Nethermind/Nethermind.Api/Extensions/IConsensusPlugin.cs b/src/Nethermind/Nethermind.Api/Extensions/IConsensusPlugin.cs
index 6b140a99d39..9a0be89152e 100644
--- a/src/Nethermind/Nethermind.Api/Extensions/IConsensusPlugin.cs
+++ b/src/Nethermind/Nethermind.Api/Extensions/IConsensusPlugin.cs
@@ -15,15 +15,9 @@ public interface IConsensusPlugin : INethermindPlugin, IBlockProducerFactory
{
string SealEngineType { get; }
- ///
- /// Default block production trigger for this consensus plugin.
- ///
- ///
- /// Needed when this plugin is used in combination with other plugin that affects block production like MEV plugin.
- ///
- IBlockProductionTrigger DefaultBlockProductionTrigger { get; }
-
INethermindApi CreateApi(IConfigProvider configProvider, IJsonSerializer jsonSerializer,
ILogManager logManager, ChainSpec chainSpec) => new NethermindApi(configProvider, jsonSerializer, logManager, chainSpec);
+
+ IBlockProducerRunner CreateBlockProducerRunner();
}
}
diff --git a/src/Nethermind/Nethermind.Api/Extensions/IConsensusWrapperPlugin.cs b/src/Nethermind/Nethermind.Api/Extensions/IConsensusWrapperPlugin.cs
index 33eb6c84a09..b81722632bc 100644
--- a/src/Nethermind/Nethermind.Api/Extensions/IConsensusWrapperPlugin.cs
+++ b/src/Nethermind/Nethermind.Api/Extensions/IConsensusWrapperPlugin.cs
@@ -3,14 +3,15 @@
using System.Threading.Tasks;
using Nethermind.Consensus;
-using Nethermind.Consensus.Producers;
using Nethermind.Consensus.Transactions;
namespace Nethermind.Api.Extensions
{
public interface IConsensusWrapperPlugin : INethermindPlugin
{
- Task InitBlockProducer(IBlockProducerFactory baseBlockProducerFactory, IBlockProductionTrigger blockProductionTrigger, ITxSource? txSource);
+ IBlockProducer InitBlockProducer(IBlockProducerFactory baseBlockProducerFactory, ITxSource? txSource);
+
+ IBlockProducerRunner InitBlockProducerRunner(IBlockProducerRunner baseRunner) => baseRunner;
///
/// Priorities for ordering multiple plugin. Only used to determine the wrapping order of block production.
diff --git a/src/Nethermind/Nethermind.Api/Extensions/INethermindPlugin.cs b/src/Nethermind/Nethermind.Api/Extensions/INethermindPlugin.cs
new file mode 100644
index 00000000000..ad1c8c28027
--- /dev/null
+++ b/src/Nethermind/Nethermind.Api/Extensions/INethermindPlugin.cs
@@ -0,0 +1,26 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Threading.Tasks;
+
+namespace Nethermind.Api.Extensions;
+
+public interface INethermindPlugin : IAsyncDisposable
+{
+ string Name { get; }
+
+ string Description { get; }
+
+ string Author { get; }
+
+ void InitRlpDecoders(INethermindApi api) { }
+
+ Task Init(INethermindApi nethermindApi) => Task.CompletedTask;
+
+ Task InitNetworkProtocol() => Task.CompletedTask;
+
+ Task InitRpcModules() => Task.CompletedTask;
+
+ bool MustInitialize => false;
+}
diff --git a/src/Nethermind/Nethermind.Api/Extensions/IPlugin.cs b/src/Nethermind/Nethermind.Api/Extensions/IPlugin.cs
deleted file mode 100644
index 95c9e13ad81..00000000000
--- a/src/Nethermind/Nethermind.Api/Extensions/IPlugin.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
-// SPDX-License-Identifier: LGPL-3.0-only
-
-using System;
-using System.Threading.Tasks;
-
-namespace Nethermind.Api.Extensions
-{
- public interface INethermindPlugin : IAsyncDisposable
- {
- string Name { get; }
-
- string Description { get; }
-
- string Author { get; }
-
- Task Init(INethermindApi nethermindApi);
-
- Task InitNetworkProtocol();
-
- Task InitRpcModules();
-
- bool MustInitialize { get => false; }
- }
-}
diff --git a/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs b/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs
index 7dd4d5b01de..496f107e7ea 100644
--- a/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs
+++ b/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs
@@ -38,6 +38,7 @@ public interface IApiWithBlockchain : IApiWithStores, IBlockchainBridgeFactory
IBlockProcessingQueue? BlockProcessingQueue { get; set; }
IBlockProcessor? MainBlockProcessor { get; set; }
IBlockProducer? BlockProducer { get; set; }
+ IBlockProducerRunner? BlockProducerRunner { get; set; }
IBlockValidator? BlockValidator { get; set; }
IEnode? Enode { get; set; }
IFilterStore? FilterStore { get; set; }
@@ -70,8 +71,6 @@ public interface IApiWithBlockchain : IApiWithStores, IBlockchainBridgeFactory
ITxPool? TxPool { get; set; }
ITxPoolInfoProvider? TxPoolInfoProvider { get; set; }
CompositeTxGossipPolicy TxGossipPolicy { get; }
- IWitnessCollector? WitnessCollector { get; set; }
- IWitnessRepository? WitnessRepository { get; set; }
IHealthHintService? HealthHintService { get; set; }
IRpcCapabilitiesProvider? RpcCapabilitiesProvider { get; set; }
ITransactionComparerProvider? TransactionComparerProvider { get; set; }
diff --git a/src/Nethermind/Nethermind.Api/NethermindApi.cs b/src/Nethermind/Nethermind.Api/NethermindApi.cs
index 97e16f3041b..e07aa13ba9e 100644
--- a/src/Nethermind/Nethermind.Api/NethermindApi.cs
+++ b/src/Nethermind/Nethermind.Api/NethermindApi.cs
@@ -31,6 +31,7 @@
using Nethermind.Evm.TransactionProcessing;
using Nethermind.Facade;
using Nethermind.Facade.Eth;
+using Nethermind.Facade.Simulate;
using Nethermind.Grpc;
using Nethermind.JsonRpc;
using Nethermind.JsonRpc.Modules;
@@ -81,11 +82,20 @@ public IBlockchainBridge CreateBlockchainBridge()
SpecProvider,
LogManager);
+ SimulateReadOnlyBlocksProcessingEnvFactory simulateReadOnlyBlocksProcessingEnvFactory =
+ new SimulateReadOnlyBlocksProcessingEnvFactory(
+ WorldStateManager!,
+ readOnlyTree,
+ DbProvider!,
+ SpecProvider!,
+ LogManager);
+
IMiningConfig miningConfig = ConfigProvider.GetConfig();
IBlocksConfig blocksConfig = ConfigProvider.GetConfig();
return new BlockchainBridge(
readOnlyTxProcessingEnv,
+ simulateReadOnlyBlocksProcessingEnvFactory,
TxPool,
ReceiptFinder,
FilterStore,
@@ -106,6 +116,7 @@ public IBlockchainBridge CreateBlockchainBridge()
public IBlockProcessingQueue? BlockProcessingQueue { get; set; }
public IBlockProcessor? MainBlockProcessor { get; set; }
public IBlockProducer? BlockProducer { get; set; }
+ public IBlockProducerRunner? BlockProducerRunner { get; set; }
public IBlockTree? BlockTree { get; set; }
public IBlockValidator? BlockValidator { get; set; }
public IBloomStorage? BloomStorage { get; set; }
@@ -146,8 +157,6 @@ public IBlockchainBridge CreateBlockchainBridge()
public IProtocolsManager? ProtocolsManager { get; set; }
public IProtocolValidator? ProtocolValidator { get; set; }
public IReceiptStorage? ReceiptStorage { get; set; }
- public IWitnessCollector? WitnessCollector { get; set; }
- public IWitnessRepository? WitnessRepository { get; set; }
public IReceiptFinder? ReceiptFinder { get; set; }
public IReceiptMonitor? ReceiptMonitor { get; set; }
public IRewardCalculatorSource? RewardCalculatorSource { get; set; } = NoBlockRewards.Instance;
diff --git a/src/Nethermind/Nethermind.AuRa.Test/AuRaBlockProducerTests.cs b/src/Nethermind/Nethermind.AuRa.Test/AuRaBlockProducerTests.cs
index b8494907bf7..b2fe5479336 100644
--- a/src/Nethermind/Nethermind.AuRa.Test/AuRaBlockProducerTests.cs
+++ b/src/Nethermind/Nethermind.AuRa.Test/AuRaBlockProducerTests.cs
@@ -43,6 +43,7 @@ private class Context
public IAuRaStepCalculator AuRaStepCalculator { get; }
public Address NodeAddress { get; }
public AuRaBlockProducer AuRaBlockProducer { get; private set; }
+ public IBlockProducerRunner BlockProducerRunner { get; set; }
public TimeSpan StepDelay { get; }
public Context()
@@ -97,7 +98,6 @@ public void InitProducer(IAuraConfig auraConfig)
AuRaBlockProducer = new AuRaBlockProducer(
TransactionSource,
BlockchainProcessor,
- onlyWhenNotProcessing,
StateProvider,
Sealer,
BlockTree,
@@ -110,7 +110,12 @@ public void InitProducer(IAuraConfig auraConfig)
LimboLogs.Instance,
blocksConfig);
- ProducedBlockSuggester suggester = new(BlockTree, AuRaBlockProducer);
+ BlockProducerRunner = new StandardBlockProducerRunner(
+ onlyWhenNotProcessing,
+ BlockTree,
+ AuRaBlockProducer);
+
+ ProducedBlockSuggester suggester = new(BlockTree, BlockProducerRunner);
}
}
@@ -223,7 +228,7 @@ private async Task StartStop(Context context, bool processingQueueEm
processedEvent.Set();
});
- await context.AuRaBlockProducer.Start();
+ context.BlockProducerRunner.Start();
await processedEvent.WaitOneAsync(context.StepDelay * stepDelayMultiplier * 5, CancellationToken.None);
context.BlockTree.ClearReceivedCalls();
await Task.Delay(context.StepDelay);
@@ -248,7 +253,7 @@ private async Task StartStop(Context context, bool processingQueueEm
}
finally
{
- await context.AuRaBlockProducer.StopAsync();
+ await context.BlockProducerRunner.StopAsync();
}
return new TestResult(q => context.BlockTree.Received(q).SuggestBlock(Arg.Any(), Arg.Any()));
diff --git a/src/Nethermind/Nethermind.AuRa.Test/AuRaPluginTests.cs b/src/Nethermind/Nethermind.AuRa.Test/AuRaPluginTests.cs
index 009035305dd..03c84f9b2b8 100644
--- a/src/Nethermind/Nethermind.AuRa.Test/AuRaPluginTests.cs
+++ b/src/Nethermind/Nethermind.AuRa.Test/AuRaPluginTests.cs
@@ -6,6 +6,7 @@
using Nethermind.Api;
using Nethermind.Config;
using Nethermind.Consensus.AuRa;
+using Nethermind.Consensus.AuRa.InitializationSteps;
using Nethermind.Logging;
using Nethermind.Serialization.Json;
using Nethermind.Specs.ChainSpecStyle;
@@ -19,7 +20,7 @@ public class AuRaPluginTests
public void Init_when_not_AuRa_doesnt_trow()
{
AuRaPlugin auRaPlugin = new();
- Action init = () => auRaPlugin.Init(new NethermindApi(new ConfigProvider(), new EthereumJsonSerializer(), new TestLogManager(), new ChainSpec()));
+ Action init = () => auRaPlugin.Init(new AuRaNethermindApi(new ConfigProvider(), new EthereumJsonSerializer(), new TestLogManager(), new ChainSpec()));
init.Should().NotThrow();
}
diff --git a/src/Nethermind/Nethermind.AuRa.Test/Contract/AuRaContractGasLimitOverrideTests.cs b/src/Nethermind/Nethermind.AuRa.Test/Contract/AuRaContractGasLimitOverrideTests.cs
index d9e559f47dd..24b29330e4c 100644
--- a/src/Nethermind/Nethermind.AuRa.Test/Contract/AuRaContractGasLimitOverrideTests.cs
+++ b/src/Nethermind/Nethermind.AuRa.Test/Contract/AuRaContractGasLimitOverrideTests.cs
@@ -6,6 +6,7 @@
using System.Threading.Tasks;
using FluentAssertions;
using Nethermind.Abi;
+using Nethermind.Blockchain;
using Nethermind.Consensus;
using Nethermind.Consensus.AuRa;
using Nethermind.Consensus.AuRa.Contracts;
@@ -83,7 +84,7 @@ protected override BlockProcessor CreateBlockProcessor()
BlockGasLimitContract gasLimitContract = new(AbiEncoder.Instance, blockGasLimitContractTransition.Value, blockGasLimitContractTransition.Key,
new ReadOnlyTxProcessingEnv(
WorldStateManager,
- BlockTree, SpecProvider, LimboLogs.Instance));
+ BlockTree.AsReadOnly(), SpecProvider, LimboLogs.Instance));
GasLimitOverrideCache = new AuRaContractGasLimitOverride.Cache();
GasLimitCalculator = new AuRaContractGasLimitOverride(new[] { gasLimitContract }, GasLimitOverrideCache, false, new FollowOtherMiners(SpecProvider), LimboLogs.Instance);
diff --git a/src/Nethermind/Nethermind.AuRa.Test/Contract/TxPriorityContractTests.cs b/src/Nethermind/Nethermind.AuRa.Test/Contract/TxPriorityContractTests.cs
index 276671dab2a..1caa20bf3a9 100644
--- a/src/Nethermind/Nethermind.AuRa.Test/Contract/TxPriorityContractTests.cs
+++ b/src/Nethermind/Nethermind.AuRa.Test/Contract/TxPriorityContractTests.cs
@@ -10,6 +10,7 @@
using System.Threading.Tasks;
using FluentAssertions;
using Nethermind.Abi;
+using Nethermind.Blockchain;
using Nethermind.Blockchain.Data;
using Nethermind.Consensus.AuRa.Contracts;
using Nethermind.Consensus.AuRa.Contracts.DataStore;
@@ -254,7 +255,7 @@ protected override TxPoolTxSource CreateTxPoolTxSource()
TxPoolTxSource txPoolTxSource = base.CreateTxPoolTxSource();
TxPriorityContract = new TxPriorityContract(AbiEncoder.Instance, TestItem.AddressA,
- new ReadOnlyTxProcessingEnv(WorldStateManager, BlockTree, SpecProvider, LimboLogs.Instance));
+ new ReadOnlyTxProcessingEnv(WorldStateManager, BlockTree.AsReadOnly(), SpecProvider, LimboLogs.Instance));
Priorities = new DictionaryContractDataStore(
new TxPriorityContract.DestinationSortedListContractDataStoreCollection(),
diff --git a/src/Nethermind/Nethermind.AuRa.Test/Contract/ValidatorContractTests.cs b/src/Nethermind/Nethermind.AuRa.Test/Contract/ValidatorContractTests.cs
index 8b7ed8d3901..ae1a5040a4f 100644
--- a/src/Nethermind/Nethermind.AuRa.Test/Contract/ValidatorContractTests.cs
+++ b/src/Nethermind/Nethermind.AuRa.Test/Contract/ValidatorContractTests.cs
@@ -6,6 +6,7 @@
using Nethermind.Abi;
using Nethermind.Consensus;
using Nethermind.Consensus.AuRa.Contracts;
+using Nethermind.Consensus.Processing;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Test;
@@ -26,7 +27,7 @@ public class ValidatorContractTests
{
private Block _block;
private readonly Address _contractAddress = Address.FromNumber(long.MaxValue);
- private IReadOnlyTransactionProcessor _transactionProcessor;
+ private ITransactionProcessor _transactionProcessor;
private IReadOnlyTxProcessorSource _readOnlyTxProcessorSource;
private IWorldState _stateProvider;
@@ -34,16 +35,13 @@ public class ValidatorContractTests
public void SetUp()
{
_block = new Block(Build.A.BlockHeader.TestObject, new BlockBody());
- _transactionProcessor = Substitute.For();
- _readOnlyTxProcessorSource = Substitute.For();
- _readOnlyTxProcessorSource.Build(TestItem.KeccakA).Returns(_transactionProcessor);
+ _transactionProcessor = Substitute.For();
_stateProvider = Substitute.For();
_stateProvider.StateRoot.Returns(TestItem.KeccakA);
+ _readOnlyTxProcessorSource = Substitute.For();
+ _readOnlyTxProcessorSource.Build(TestItem.KeccakA).Returns(new ReadOnlyTxProcessingScope(_transactionProcessor, _stateProvider, Keccak.EmptyTreeHash));
}
- [TearDown]
- public void TearDown() => _transactionProcessor?.Dispose();
-
[Test]
public void constructor_throws_ArgumentNullException_on_null_contractAddress()
{
diff --git a/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxCertifierFilterTests.cs b/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxCertifierFilterTests.cs
index c65d2efc805..f6403fa1184 100644
--- a/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxCertifierFilterTests.cs
+++ b/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxCertifierFilterTests.cs
@@ -6,6 +6,7 @@
using FluentAssertions;
using Nethermind.Abi;
using Nethermind.AuRa.Test.Contract;
+using Nethermind.Blockchain;
using Nethermind.Consensus.AuRa;
using Nethermind.Consensus.AuRa.Contracts;
using Nethermind.Consensus.AuRa.Transactions;
@@ -137,7 +138,7 @@ protected override BlockProcessor CreateBlockProcessor()
AbiEncoder abiEncoder = AbiEncoder.Instance;
ReadOnlyTransactionProcessorSource = new ReadOnlyTxProcessingEnv(
WorldStateManager,
- BlockTree, SpecProvider,
+ BlockTree.AsReadOnly(), SpecProvider,
LimboLogs.Instance);
RegisterContract = new RegisterContract(abiEncoder, ChainSpec.Parameters.Registrar, ReadOnlyTransactionProcessorSource);
CertifierContract = new CertifierContract(
diff --git a/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxPermissionFilterTest.cs b/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxPermissionFilterTest.cs
index 87706013ea2..7bae62ac4df 100644
--- a/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxPermissionFilterTest.cs
+++ b/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxPermissionFilterTest.cs
@@ -8,6 +8,7 @@
using FluentAssertions;
using Nethermind.Abi;
using Nethermind.AuRa.Test.Contract;
+using Nethermind.Blockchain;
using Nethermind.Consensus.AuRa;
using Nethermind.Consensus.AuRa.Contracts;
using Nethermind.Consensus.AuRa.Transactions;
@@ -277,12 +278,12 @@ protected override BlockProcessor CreateBlockProcessor()
IReadOnlyTrieStore trieStore = new TrieStore(DbProvider.StateDb, LimboLogs.Instance).AsReadOnly();
IReadOnlyTxProcessorSource txProcessorSource = new ReadOnlyTxProcessingEnv(
WorldStateManager,
- BlockTree,
+ BlockTree.AsReadOnly(),
SpecProvider,
LimboLogs.Instance);
VersionedTransactionPermissionContract transactionPermissionContract = new(AbiEncoder.Instance, _contractAddress, 1,
- new ReadOnlyTxProcessingEnv(WorldStateManager, BlockTree, SpecProvider, LimboLogs.Instance), TransactionPermissionContractVersions, LimboLogs.Instance, SpecProvider);
+ new ReadOnlyTxProcessingEnv(WorldStateManager, BlockTree.AsReadOnly(), SpecProvider, LimboLogs.Instance), TransactionPermissionContractVersions, LimboLogs.Instance, SpecProvider);
TxPermissionFilterCache = new PermissionBasedTxFilter.Cache();
PermissionBasedTxFilter = new PermissionBasedTxFilter(transactionPermissionContract, TxPermissionFilterCache, LimboLogs.Instance);
diff --git a/src/Nethermind/Nethermind.AuRa.Test/Validators/ContractBasedValidatorTests.cs b/src/Nethermind/Nethermind.AuRa.Test/Validators/ContractBasedValidatorTests.cs
index 91dad8e1fc5..3902182d6e8 100644
--- a/src/Nethermind/Nethermind.AuRa.Test/Validators/ContractBasedValidatorTests.cs
+++ b/src/Nethermind/Nethermind.AuRa.Test/Validators/ContractBasedValidatorTests.cs
@@ -32,6 +32,7 @@
using Nethermind.Evm;
using Nethermind.Core.Specs;
using System.Text.Json;
+using Nethermind.Consensus.Processing;
namespace Nethermind.AuRa.Test.Validators;
@@ -43,7 +44,7 @@ public class ContractBasedValidatorTests
private AuRaParameters.Validator _validator;
private Block _block;
private BlockHeader _parentHeader;
- private IReadOnlyTransactionProcessor _transactionProcessor;
+ private ITransactionProcessor _transactionProcessor;
private IAuRaBlockFinalizationManager _blockFinalizationManager;
private static readonly Address _contractAddress = Address.FromNumber(1000);
private (Address Sender, byte[] TransactionData) _getValidatorsData = (Address.Zero, new byte[] { 0, 1, 2 });
@@ -74,11 +75,12 @@ public void SetUp()
};
_block = new Block(Build.A.BlockHeader.WithNumber(1).WithAura(1, Array.Empty()).TestObject, new BlockBody());
- _transactionProcessor = Substitute.For();
- _transactionProcessor.IsContractDeployed(_contractAddress).Returns(true);
- _readOnlyTxProcessorSource = Substitute.For();
- _readOnlyTxProcessorSource.Build(Arg.Any()).Returns(_transactionProcessor);
+ _transactionProcessor = Substitute.For();
_stateProvider.StateRoot.Returns(TestItem.KeccakA);
+ _stateProvider.IsContract(_contractAddress).Returns(true);
+
+ _readOnlyTxProcessorSource = Substitute.For();
+ _readOnlyTxProcessorSource.Build(Arg.Any()).Returns(new ReadOnlyTxProcessingScope(_transactionProcessor, _stateProvider, Keccak.EmptyTreeHash));
_blockTree.Head.Returns(_block);
_abiEncoder
@@ -96,7 +98,6 @@ public void SetUp()
public void TearDown()
{
_blockFinalizationManager?.Dispose();
- _transactionProcessor?.Dispose();
}
[Test]
diff --git a/src/Nethermind/Nethermind.Benchmark/Evm/JumpDestinationsBenchmark.cs b/src/Nethermind/Nethermind.Benchmark/Evm/JumpDestinationsBenchmark.cs
index b77cc017fa4..8ee151d0343 100644
--- a/src/Nethermind/Nethermind.Benchmark/Evm/JumpDestinationsBenchmark.cs
+++ b/src/Nethermind/Nethermind.Benchmark/Evm/JumpDestinationsBenchmark.cs
@@ -29,7 +29,7 @@ public void Setup()
[Benchmark]
public bool Current()
{
- return _codeInfo.ValidateJump(0, false);
+ return _codeInfo.ValidateJump(0);
}
}
}
diff --git a/src/Nethermind/Nethermind.Blockchain.Test.Runner/BlockchainTestsBugHunter.cs b/src/Nethermind/Nethermind.Blockchain.Test.Runner/BlockchainTestsBugHunter.cs
index e3a38660ba0..ce6593f4751 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test.Runner/BlockchainTestsBugHunter.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test.Runner/BlockchainTestsBugHunter.cs
@@ -32,7 +32,7 @@ public async Task> RunTestsAsync()
Setup();
Console.Write($"{test,-120} ");
- if (test.LoadFailure != null)
+ if (test.LoadFailure is not null)
{
WriteRed(test.LoadFailure);
testResults.Add(new EthereumTestResult(test.Name, test.LoadFailure));
diff --git a/src/Nethermind/Nethermind.Blockchain.Test.Runner/PerfTest.cs b/src/Nethermind/Nethermind.Blockchain.Test.Runner/PerfTest.cs
index c94b78867b1..a25bfb6038a 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test.Runner/PerfTest.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test.Runner/PerfTest.cs
@@ -28,7 +28,7 @@ public IEnumerable RunTests()
bool isNewLine = true;
foreach (GeneralStateTest test in tests)
{
- if (test.LoadFailure != null)
+ if (test.LoadFailure is not null)
{
continue;
}
diff --git a/src/Nethermind/Nethermind.Blockchain.Test.Runner/StateTestsBugHunter.cs b/src/Nethermind/Nethermind.Blockchain.Test.Runner/StateTestsBugHunter.cs
index d98679e02b9..9dd9cf56c7a 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test.Runner/StateTestsBugHunter.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test.Runner/StateTestsBugHunter.cs
@@ -32,7 +32,7 @@ public IEnumerable RunTests()
Setup(LimboLogs.Instance);
Console.Write($"{test,-120} ");
- if (test.LoadFailure != null)
+ if (test.LoadFailure is not null)
{
WriteRed(test.LoadFailure);
testResults.Add(new EthereumTestResult(test.Name, test.ForkName, test.LoadFailure));
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs
index 0cc724cfccc..8e8172f1b0a 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs
@@ -49,7 +49,6 @@ public void Prepared_block_contains_author_field()
new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider),
stateProvider,
NullReceiptStorage.Instance,
- NullWitnessCollector.Instance,
Substitute.For(),
transactionProcessor,
LimboLogs.Instance);
@@ -65,39 +64,6 @@ public void Prepared_block_contains_author_field()
Assert.That(processedBlocks[0].Author, Is.EqualTo(block.Author), "author");
}
- [Test, Timeout(Timeout.MaxTestTime)]
- public void Can_store_a_witness()
- {
- IDb stateDb = new MemDb();
- IDb codeDb = new MemDb();
- TrieStore trieStore = new TrieStore(stateDb, LimboLogs.Instance);
-
- IWorldState stateProvider = new WorldState(trieStore, codeDb, LimboLogs.Instance);
- ITransactionProcessor transactionProcessor = Substitute.For();
- IWitnessCollector witnessCollector = Substitute.For();
- BlockProcessor processor = new(
- HoleskySpecProvider.Instance,
- TestBlockValidator.AlwaysValid,
- NoBlockRewards.Instance,
- new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider),
- stateProvider,
- NullReceiptStorage.Instance,
- witnessCollector,
- Substitute.For(),
- transactionProcessor,
- LimboLogs.Instance);
-
- BlockHeader header = Build.A.BlockHeader.WithAuthor(TestItem.AddressD).TestObject;
- Block block = Build.A.Block.WithHeader(header).TestObject;
- _ = processor.Process(
- Keccak.EmptyTreeHash,
- new List { block },
- ProcessingOptions.None,
- NullBlockTracer.Instance);
-
- witnessCollector.Received(1).Persist(block.Hash!);
- }
-
[Test, Timeout(Timeout.MaxTestTime)]
public void Recovers_state_on_cancel()
{
@@ -113,7 +79,6 @@ public void Recovers_state_on_cancel()
new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider),
stateProvider,
NullReceiptStorage.Instance,
- NullWitnessCollector.Instance,
Substitute.For(),
transactionProcessor,
LimboLogs.Instance);
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/ClefSignerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/ClefSignerTests.cs
new file mode 100644
index 00000000000..b4ce5520b71
--- /dev/null
+++ b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/ClefSignerTests.cs
@@ -0,0 +1,101 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Threading.Tasks;
+using FluentAssertions;
+using Nethermind.Core;
+using Nethermind.Core.Crypto;
+using Nethermind.Core.Extensions;
+using Nethermind.Core.Test.Builders;
+using Nethermind.JsonRpc;
+using Nethermind.JsonRpc.Client;
+using NSubstitute;
+using NUnit.Framework;
+
+namespace Nethermind.Blockchain.Test.Consensus
+{
+ [TestFixture]
+ public class ClefSignerTests
+ {
+ [Test]
+ public async Task Sign_SigningHash_RequestHasCorrectParameters()
+ {
+ IJsonRpcClient client = Substitute.For();
+ client.Post("account_list").Returns(Task.FromResult([TestItem.AddressA!.ToString()]));
+ Task postMethod = client.Post("account_signData", "text/plain", Arg.Any(), Keccak.Zero);
+ var returnValue = (new byte[65]).ToHexString();
+ postMethod.Returns(returnValue);
+ ClefSigner sut = await ClefSigner.Create(client);
+
+ var result = sut.Sign(Keccak.Zero);
+
+ Assert.That(new Signature(returnValue).Bytes, Is.EqualTo(result.Bytes));
+ }
+
+ [Test]
+ public async Task Sign_SigningCliqueHeader_PassingCorrectClefParametersForRequest()
+ {
+ IJsonRpcClient client = Substitute.For();
+ client.Post("account_list").Returns(Task.FromResult([TestItem.AddressA!.ToString()]));
+ Task postMethod = client.Post(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any());
+ var returnValue = (new byte[65]).ToHexString();
+ postMethod.Returns(returnValue);
+ BlockHeader blockHeader = Build.A.BlockHeader.TestObject;
+ ClefSigner sut = await ClefSigner.Create(client);
+
+ sut.Sign(blockHeader);
+
+ await client.Received().Post("account_signData", "application/x-clique-header", Arg.Any(), Arg.Any());
+ }
+
+
+ [TestCase(0, 27)]
+ [TestCase(1, 28)]
+ public async Task Sign_RecoveryIdIsSetToCliqueValues_RecoveryIdIsAdjusted(byte recId, byte expected)
+ {
+ IJsonRpcClient client = Substitute.For();
+ client.Post("account_list").Returns(Task.FromResult([TestItem.AddressA!.ToString()]));
+ Task postMethod = client.Post("account_signData", "application/x-clique-header", Arg.Any(), Arg.Any());
+ var returnValue = (new byte[65]);
+ returnValue[64] = recId;
+ postMethod.Returns(returnValue.ToHexString());
+ BlockHeader blockHeader = Build.A.BlockHeader.TestObject;
+ ClefSigner sut = await ClefSigner.Create(client);
+
+ var result = sut.Sign(blockHeader);
+
+ Assert.That(result.V, Is.EqualTo(expected));
+ }
+
+ [Test]
+ public async Task Create_SignerAddressSpecified_CorrectAddressIsSet()
+ {
+ IJsonRpcClient client = Substitute.For();
+ client.Post("account_list").Returns(Task.FromResult([TestItem.AddressA!.ToString(), TestItem.AddressB!.ToString()]));
+
+ ClefSigner sut = await ClefSigner.Create(client, TestItem.AddressB);
+
+ Assert.That(sut.Address, Is.EqualTo(TestItem.AddressB));
+ }
+
+ [Test]
+ public void Create_SignerAddressDoesNotExists_ThrowInvalidOperationException()
+ {
+ IJsonRpcClient client = Substitute.For();
+ client.Post("account_list").Returns(Task.FromResult([TestItem.AddressA!.ToString(), TestItem.AddressB!.ToString()]));
+
+ Assert.That(async () => await ClefSigner.Create(client, TestItem.AddressC), Throws.InstanceOf());
+ }
+
+ [Test]
+ public async Task SetSigner_TryingToASigner_ThrowInvalidOperationException()
+ {
+ IJsonRpcClient client = Substitute.For();
+ client.Post("account_list").Returns(Task.FromResult([TestItem.AddressA!.ToString()]));
+ ClefSigner sut = await ClefSigner.Create(client);
+
+ Assert.That(() => sut.SetSigner(Build.A.PrivateKey.TestObject), Throws.InstanceOf());
+ }
+ }
+}
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/KnownChainSizesTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/KnownChainSizesTests.cs
index d17d8d06f79..9367267797b 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/KnownChainSizesTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/KnownChainSizesTests.cs
@@ -14,8 +14,8 @@ public class KnownChainSizesTests
public void Update_known_chain_sizes()
{
// Pruning size have to be updated frequently
- ChainSizes.CreateChainSizeInfo(BlockchainIds.Mainnet).PruningSize.Should().BeLessThan(220.GB());
- ChainSizes.CreateChainSizeInfo(BlockchainIds.Sepolia).PruningSize.Should().BeLessThan(20.GB());
+ ChainSizes.CreateChainSizeInfo(BlockchainIds.Mainnet).PruningSize.Should().BeLessThan(240.GB());
+ ChainSizes.CreateChainSizeInfo(BlockchainIds.Sepolia).PruningSize.Should().BeLessThan(24.GB());
ChainSizes.CreateChainSizeInfo(BlockchainIds.Chiado).PruningSize.Should().Be(null);
ChainSizes.CreateChainSizeInfo(BlockchainIds.Gnosis).PruningSize.Should().Be(null);
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Nethermind.Blockchain.Test.csproj b/src/Nethermind/Nethermind.Blockchain.Test/Nethermind.Blockchain.Test.csproj
index a4aa0b53879..caa031ac836 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/Nethermind.Blockchain.Test.csproj
+++ b/src/Nethermind/Nethermind.Blockchain.Test/Nethermind.Blockchain.Test.csproj
@@ -26,6 +26,7 @@
+
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.IsProducingBlocks.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.IsProducingBlocks.cs
index 49e67f7c50b..3735ff1bc1b 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.IsProducingBlocks.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.IsProducingBlocks.cs
@@ -42,12 +42,13 @@ public async Task DevBlockProducer_IsProducingBlocks_returns_expected_results()
testRpc.BlockchainProcessor,
testRpc.State,
testRpc.BlockTree,
- Substitute.For(),
testRpc.Timestamper,
testRpc.SpecProvider,
new BlocksConfig(),
LimboLogs.Instance);
- await AssertIsProducingBlocks(blockProducer);
+ StandardBlockProducerRunner runner = new StandardBlockProducerRunner(
+ Substitute.For(), testRpc.BlockTree, blockProducer);
+ await AssertIsProducingBlocks(runner);
}
[Test, Timeout(Timeout.MaxTestTime)]
@@ -61,12 +62,13 @@ public async Task TestBlockProducer_IsProducingBlocks_returns_expected_results()
testRpc.State,
Substitute.For(),
testRpc.BlockTree,
- Substitute.For(),
testRpc.Timestamper,
testRpc.SpecProvider,
LimboLogs.Instance,
blocksConfig);
- await AssertIsProducingBlocks(blockProducer);
+ StandardBlockProducerRunner runner = new StandardBlockProducerRunner(
+ Substitute.For(), testRpc.BlockTree, blockProducer);
+ await AssertIsProducingBlocks(runner);
}
[Test, Timeout(Timeout.MaxTestTime)]
@@ -79,14 +81,15 @@ public async Task MinedBlockProducer_IsProducingBlocks_returns_expected_results(
testRpc.BlockchainProcessor,
Substitute.For(),
testRpc.BlockTree,
- Substitute.For(),
testRpc.State,
Substitute.For(),
testRpc.Timestamper,
testRpc.SpecProvider,
LimboLogs.Instance,
blocksConfig);
- await AssertIsProducingBlocks(blockProducer);
+ StandardBlockProducerRunner runner = new StandardBlockProducerRunner(
+ Substitute.For(), testRpc.BlockTree, blockProducer);
+ await AssertIsProducingBlocks(runner);
}
[Test, Timeout(Timeout.MaxTestTime)]
@@ -97,7 +100,6 @@ public async Task AuraTestBlockProducer_IsProducingBlocks_returns_expected_resul
AuRaBlockProducer blockProducer = new(
Substitute.For(),
Substitute.For(),
- Substitute.For(),
Substitute.For(),
Substitute.For(),
Substitute.For(),
@@ -109,7 +111,9 @@ public async Task AuraTestBlockProducer_IsProducingBlocks_returns_expected_resul
Substitute.For(),
LimboLogs.Instance,
Substitute.For());
- await AssertIsProducingBlocks(blockProducer);
+ StandardBlockProducerRunner runner = new StandardBlockProducerRunner(
+ Substitute.For(), Substitute.For(), blockProducer);
+ await AssertIsProducingBlocks(runner);
}
[Test, Timeout(Timeout.MaxTestTime)]
@@ -120,7 +124,6 @@ public async Task CliqueBlockProducer_IsProducingBlocks_returns_expected_results
Substitute.For(),
testRpc.BlockchainProcessor,
testRpc.State,
- testRpc.BlockTree,
testRpc.Timestamper,
Substitute.For(),
Substitute.For(),
@@ -129,7 +132,17 @@ public async Task CliqueBlockProducer_IsProducingBlocks_returns_expected_results
Substitute.For(),
new CliqueConfig(),
LimboLogs.Instance);
- await AssertIsProducingBlocks(blockProducer);
+
+ CliqueBlockProducerRunner runner = new CliqueBlockProducerRunner(
+ testRpc.BlockTree,
+ testRpc.Timestamper,
+ Substitute.For(),
+ Substitute.For(),
+ blockProducer,
+ new CliqueConfig(),
+ LimboLogs.Instance);
+
+ await AssertIsProducingBlocks(runner);
}
private async Task CreateTestRpc()
@@ -143,10 +156,10 @@ private async Task CreateTestRpc()
return testRpc;
}
- private async Task AssertIsProducingBlocks(IBlockProducer blockProducer)
+ private async Task AssertIsProducingBlocks(IBlockProducerRunner blockProducer)
{
Assert.That(blockProducer.IsProducingBlocks(null), Is.EqualTo(false));
- await blockProducer.Start();
+ blockProducer.Start();
Assert.That(blockProducer.IsProducingBlocks(null), Is.EqualTo(true));
Thread.Sleep(5000);
Assert.That(blockProducer.IsProducingBlocks(1), Is.EqualTo(false));
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.cs
index 4b8b6ef14b7..e4edbe07823 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.cs
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System;
-using System.Threading.Tasks;
using FluentAssertions;
using Nethermind.Config;
using Nethermind.Consensus;
@@ -30,7 +29,6 @@ public ProducerUnderTest(
IBlockchainProcessor processor,
ISealer sealer,
IBlockTree blockTree,
- IBlockProductionTrigger blockProductionTrigger,
IWorldState stateProvider,
IGasLimitCalculator gasLimitCalculator,
ITimestamper timestamper,
@@ -41,7 +39,6 @@ public ProducerUnderTest(
processor,
sealer,
blockTree,
- blockProductionTrigger,
stateProvider,
gasLimitCalculator,
timestamper,
@@ -52,16 +49,10 @@ public ProducerUnderTest(
{
}
- public override Task Start() { return Task.CompletedTask; }
-
- public override Task StopAsync() => Task.CompletedTask;
-
public Block Prepare() => PrepareBlock(Build.A.BlockHeader.TestObject);
public Block Prepare(BlockHeader header) => PrepareBlock(header);
- protected override bool IsRunning() => true;
-
private class TimestampDifficultyCalculator : IDifficultyCalculator
{
public UInt256 Calculate(BlockHeader header, BlockHeader parent) => header.Timestamp;
@@ -78,7 +69,6 @@ public void Time_passing_does_not_break_the_block()
Substitute.For(),
NullSealEngine.Instance,
Build.A.BlockTree().TestObject,
- Substitute.For(),
Substitute.For(),
Substitute.For(),
timestamper,
@@ -101,7 +91,6 @@ public void Parent_timestamp_is_used_consistently()
Substitute.For(),
NullSealEngine.Instance,
Build.A.BlockTree().TestObject,
- Substitute.For(),
Substitute.For(),
Substitute.For(),
timestamper,
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs
index 4d492270c74..ae107c08af5 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs
@@ -6,6 +6,7 @@
using Nethermind.Blockchain.Blocks;
using Nethermind.Blockchain.Receipts;
using Nethermind.Config;
+using Nethermind.Consensus;
using Nethermind.Consensus.Processing;
using Nethermind.Consensus.Producers;
using Nethermind.Consensus.Rewards;
@@ -57,14 +58,17 @@ public void Test()
LimboLogs.Instance);
StateReader stateReader = new(trieStore, dbProvider.GetDb(DbNames.State), LimboLogs.Instance);
BlockhashProvider blockhashProvider = new(blockTree, specProvider, stateProvider, LimboLogs.Instance);
+ CodeInfoRepository codeInfoRepository = new();
VirtualMachine virtualMachine = new(
blockhashProvider,
specProvider,
+ codeInfoRepository,
LimboLogs.Instance);
TransactionProcessor txProcessor = new(
specProvider,
stateProvider,
virtualMachine,
+ codeInfoRepository,
LimboLogs.Instance);
BlockProcessor blockProcessor = new(
specProvider,
@@ -73,7 +77,6 @@ public void Test()
new BlockProcessor.BlockValidationTransactionsExecutor(txProcessor, stateProvider),
stateProvider,
NullReceiptStorage.Instance,
- NullWitnessCollector.Instance,
new BlockhashStore(blockTree, specProvider, stateProvider),
txProcessor,
LimboLogs.Instance);
@@ -91,15 +94,16 @@ public void Test()
blockchainProcessor,
stateProvider,
blockTree,
- trigger,
timestamper,
specProvider,
new BlocksConfig(),
LimboLogs.Instance);
+ StandardBlockProducerRunner blockProducerRunner = new StandardBlockProducerRunner(trigger, blockTree, devBlockProducer);
+
blockchainProcessor.Start();
- devBlockProducer.Start();
- ProducedBlockSuggester _ = new ProducedBlockSuggester(blockTree, devBlockProducer);
+ blockProducerRunner.Start();
+ ProducedBlockSuggester _ = new ProducedBlockSuggester(blockTree, blockProducerRunner);
AutoResetEvent autoResetEvent = new(false);
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Proofs/ReceiptTrieTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Proofs/ReceiptTrieTests.cs
index 1fbaa51be02..6ee424c6b38 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/Proofs/ReceiptTrieTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/Proofs/ReceiptTrieTests.cs
@@ -19,12 +19,14 @@ namespace Nethermind.Blockchain.Test.Proofs
{
public class ReceiptTrieTests
{
+ private static readonly IRlpStreamDecoder _decoder = Rlp.GetStreamDecoder()!;
+
[Test, Timeout(Timeout.MaxTestTime)]
public void Can_calculate_root_no_eip_658()
{
TxReceipt receipt = Build.A.Receipt.WithAllFieldsFilled.TestObject;
Hash256 rootHash = ReceiptTrie.CalculateRoot(MainnetSpecProvider.Instance.GetSpec((1, null)),
- new[] { receipt }, ReceiptMessageDecoder.Instance);
+ [receipt], _decoder);
Assert.That(rootHash.ToString(),
Is.EqualTo("0xe51a2d9f986d68628990c9d65e45c36128ec7bb697bd426b0bb4d18a3f3321be"));
}
@@ -35,7 +37,7 @@ public void Can_calculate_root()
TxReceipt receipt = Build.A.Receipt.WithAllFieldsFilled.TestObject;
Hash256 rootHash = ReceiptTrie.CalculateRoot(
MainnetSpecProvider.Instance.GetSpec((MainnetSpecProvider.MuirGlacierBlockNumber, null)),
- new[] { receipt }, ReceiptMessageDecoder.Instance);
+ [receipt], _decoder);
Assert.That(rootHash.ToString(),
Is.EqualTo("0x2e6d89c5b539e72409f2e587730643986c2ef33db5e817a4223aa1bb996476d5"));
}
@@ -46,7 +48,7 @@ public void Can_collect_proof_with_branch()
TxReceipt receipt1 = Build.A.Receipt.WithAllFieldsFilled.TestObject;
TxReceipt receipt2 = Build.A.Receipt.WithAllFieldsFilled.TestObject;
ReceiptTrie trie = new(MainnetSpecProvider.Instance.GetSpec((ForkActivation)1),
- new[] { receipt1, receipt2 }, ReceiptMessageDecoder.Instance, true);
+ [receipt1, receipt2], _decoder, true);
byte[][] proof = trie.BuildProof(0);
Assert.That(proof.Length, Is.EqualTo(2));
@@ -54,11 +56,11 @@ public void Can_collect_proof_with_branch()
VerifyProof(proof, trie.RootHash);
}
- private static void VerifyProof(byte[][] proof, Hash256 receiptRoot)
+ private void VerifyProof(byte[][] proof, Hash256 receiptRoot)
{
TrieNode node = new(NodeType.Unknown, proof.Last());
node.ResolveNode(Substitute.For(), TreePath.Empty);
- TxReceipt receipt = new ReceiptMessageDecoder().Decode(node.Value.AsRlpStream());
+ TxReceipt receipt = _decoder.Decode(node.Value.AsRlpStream());
Assert.NotNull(receipt.Bloom);
for (int i = proof.Length; i > 0; i--)
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Receipts/ReceiptsIteratorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Receipts/ReceiptsIteratorTests.cs
index e56498db73a..da658279ddc 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/Receipts/ReceiptsIteratorTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/Receipts/ReceiptsIteratorTests.cs
@@ -112,7 +112,7 @@ private ReceiptsIterator CreateIterator(TxReceipt[] receipts, Block block)
false
);
- ReceiptsIterator iterator = new ReceiptsIterator(span, blockDb, () => recovery.CreateRecoveryContext(new ReceiptRecoveryBlock(block)), ReceiptArrayStorageDecoder.GetRefDecoder(span));
+ ReceiptsIterator iterator = new ReceiptsIterator(span, blockDb, () => recovery.CreateRecoveryContext(new ReceiptRecoveryBlock(block)), _decoder.GetRefDecoder(span));
return iterator;
}
}
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/ReorgTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/ReorgTests.cs
index 912cfd4f100..63e4bc13cdc 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/ReorgTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/ReorgTests.cs
@@ -19,7 +19,6 @@
using Nethermind.Logging;
using Nethermind.Specs;
using Nethermind.State;
-using Nethermind.State.Witnesses;
using Nethermind.Trie.Pruning;
using Nethermind.TxPool;
using NUnit.Framework;
@@ -58,14 +57,17 @@ public void Setup()
LimboLogs.Instance,
transactionComparerProvider.GetDefaultComparer());
BlockhashProvider blockhashProvider = new(_blockTree, specProvider, stateProvider, LimboLogs.Instance);
+ CodeInfoRepository codeInfoRepository = new();
VirtualMachine virtualMachine = new(
blockhashProvider,
specProvider,
+ codeInfoRepository,
LimboLogs.Instance);
TransactionProcessor transactionProcessor = new(
specProvider,
stateProvider,
virtualMachine,
+ codeInfoRepository,
LimboLogs.Instance);
BlockProcessor blockProcessor = new(
@@ -75,7 +77,6 @@ public void Setup()
new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider),
stateProvider,
NullReceiptStorage.Instance,
- new WitnessCollector(memDbProvider.StateDb, LimboLogs.Instance),
new BlockhashStore(_blockTree, MainnetSpecProvider.Instance, stateProvider),
transactionProcessor,
LimboLogs.Instance);
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/TransactionSelectorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/TransactionSelectorTests.cs
index bb730fa4b20..6b833e60048 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/TransactionSelectorTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/TransactionSelectorTests.cs
@@ -195,7 +195,7 @@ public void Proper_transactions_selected(ProperTransactionsSelectedTestCase test
MemDb stateDb = new();
MemDb codeDb = new();
TrieStore trieStore = new(stateDb, LimboLogs.Instance);
- WorldState stateProvider = new(trieStore, codeDb, LimboLogs.Instance);
+ IWorldState stateProvider = new WorldState(trieStore, codeDb, LimboLogs.Instance);
StateReader _ = new(new TrieStore(stateDb, LimboLogs.Instance), codeDb, LimboLogs.Instance);
ISpecProvider specProvider = Substitute.For();
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/TransactionsExecutorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/TransactionsExecutorTests.cs
index f43d92ead95..8799490191a 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/TransactionsExecutorTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/TransactionsExecutorTests.cs
@@ -262,7 +262,7 @@ public void Proper_transactions_selected(TransactionSelectorTests.ProperTransact
MemDb stateDb = new();
MemDb codeDb = new();
TrieStore trieStore = new(stateDb, LimboLogs.Instance);
- WorldState stateProvider = new(trieStore, codeDb, LimboLogs.Instance);
+ IWorldState stateProvider = new WorldState(trieStore, codeDb, LimboLogs.Instance);
ISpecProvider specProvider = Substitute.For();
IReleaseSpec spec = testCase.ReleaseSpec;
diff --git a/src/Nethermind/Nethermind.Blockchain/BlockTree.cs b/src/Nethermind/Nethermind.Blockchain/BlockTree.cs
index d2a96800259..c7338fa2aec 100644
--- a/src/Nethermind/Nethermind.Blockchain/BlockTree.cs
+++ b/src/Nethermind/Nethermind.Blockchain/BlockTree.cs
@@ -628,32 +628,6 @@ as it does not require the step of resolving number -> hash */
return result;
}
- public BlockHeader? FindLowestCommonAncestor(BlockHeader firstDescendant, BlockHeader secondDescendant,
- long maxSearchDepth)
- {
- if (firstDescendant.Number > secondDescendant.Number)
- {
- firstDescendant = GetAncestorAtNumber(firstDescendant, secondDescendant.Number);
- }
- else if (secondDescendant.Number > firstDescendant.Number)
- {
- secondDescendant = GetAncestorAtNumber(secondDescendant, firstDescendant.Number);
- }
-
- long currentSearchDepth = 0;
- while (
- firstDescendant is not null
- && secondDescendant is not null
- && firstDescendant.Hash != secondDescendant.Hash)
- {
- if (currentSearchDepth++ >= maxSearchDepth) return null;
- firstDescendant = this.FindParentHeader(firstDescendant, BlockTreeLookupOptions.TotalDifficultyNotNeeded);
- secondDescendant = this.FindParentHeader(secondDescendant, BlockTreeLookupOptions.TotalDifficultyNotNeeded);
- }
-
- return firstDescendant;
- }
-
private BlockHeader? GetAncestorAtNumber(BlockHeader header, long number)
{
BlockHeader? result = header;
@@ -827,22 +801,17 @@ private void DeleteBlocks(Hash256 deletePointer)
return childHash;
}
- public bool IsMainChain(BlockHeader blockHeader)
- {
- ChainLevelInfo? chainLevelInfo = LoadLevel(blockHeader.Number);
- bool isMain = chainLevelInfo is not null && chainLevelInfo.MainChainBlock?.BlockHash.Equals(blockHeader.Hash) == true;
- return isMain;
- }
+ public bool IsMainChain(BlockHeader blockHeader) =>
+ LoadLevel(blockHeader.Number)?.MainChainBlock?.BlockHash.Equals(blockHeader.Hash) == true;
- public bool IsMainChain(Hash256 blockHash)
+ public bool IsMainChain(Hash256 blockHash, bool throwOnMissingHash = true)
{
BlockHeader? header = FindHeader(blockHash, BlockTreeLookupOptions.TotalDifficultyNotNeeded);
- if (header is null)
- {
- throw new InvalidOperationException($"Not able to retrieve block number for an unknown block {blockHash}");
- }
-
- return IsMainChain(header);
+ return header is not null
+ ? IsMainChain(header)
+ : throwOnMissingHash
+ ? throw new InvalidOperationException($"Not able to retrieve block number for an unknown block {blockHash}")
+ : false;
}
public BlockHeader? FindBestSuggestedHeader() => BestSuggestedHeader;
@@ -1279,7 +1248,7 @@ private ChainLevelInfo UpdateOrCreateLevel(long number, Hash256 hash, BlockInfo
///
private bool ShouldCache(long number)
{
- return number == 0L || Head is null || number >= Head.Number - HeaderStore.CacheSize;
+ return number == 0L || Head is null || number >= Head.Number - BlockStore.CacheSize;
}
public ChainLevelInfo? FindLevel(long number)
diff --git a/src/Nethermind/Nethermind.Blockchain/BlockTreeOverlay.cs b/src/Nethermind/Nethermind.Blockchain/BlockTreeOverlay.cs
new file mode 100644
index 00000000000..c16834f63a8
--- /dev/null
+++ b/src/Nethermind/Nethermind.Blockchain/BlockTreeOverlay.cs
@@ -0,0 +1,251 @@
+// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Nethermind.Blockchain.Visitors;
+using Nethermind.Core;
+using Nethermind.Core.Collections;
+using Nethermind.Core.Crypto;
+
+namespace Nethermind.Blockchain;
+
+public class BlockTreeOverlay : IBlockTree
+{
+ private readonly IBlockTree _baseTree;
+ private readonly IBlockTree _overlayTree;
+
+ public BlockTreeOverlay(IReadOnlyBlockTree baseTree, IBlockTree overlayTree)
+ {
+ _baseTree = baseTree ?? throw new ArgumentNullException(nameof(baseTree));
+ _overlayTree = overlayTree ?? throw new ArgumentNullException(nameof(overlayTree));
+ _overlayTree.UpdateMainChain(new[] { _baseTree.Head }, true, true);
+ }
+
+ public ulong NetworkId => _baseTree.NetworkId;
+ public ulong ChainId => _baseTree.ChainId;
+ public BlockHeader? Genesis => _baseTree.Genesis;
+ public BlockHeader? BestSuggestedHeader => _overlayTree.BestSuggestedHeader ?? _baseTree.BestSuggestedHeader;
+ public Block? BestSuggestedBody => _overlayTree.BestSuggestedBody ?? _baseTree.BestSuggestedBody;
+ public BlockHeader? BestSuggestedBeaconHeader => _overlayTree.BestSuggestedBeaconHeader ?? _baseTree.BestSuggestedBeaconHeader;
+ public BlockHeader? LowestInsertedHeader => _overlayTree.LowestInsertedHeader ?? _baseTree.LowestInsertedHeader;
+
+ public long? LowestInsertedBodyNumber
+ {
+ get => _overlayTree.LowestInsertedBodyNumber ?? _baseTree.LowestInsertedBodyNumber;
+ set => _overlayTree.LowestInsertedBodyNumber = value;
+ }
+
+ public BlockHeader? LowestInsertedBeaconHeader
+ {
+ get => _overlayTree.LowestInsertedBeaconHeader ?? _baseTree.LowestInsertedBeaconHeader;
+ set => _overlayTree.LowestInsertedBeaconHeader = value;
+ }
+
+ public long BestKnownNumber => Math.Max(_overlayTree.BestKnownNumber, _baseTree.BestKnownNumber);
+ public long BestKnownBeaconNumber => Math.Max(_overlayTree.BestKnownBeaconNumber, _baseTree.BestKnownBeaconNumber);
+ public Hash256 HeadHash => _overlayTree.HeadHash ?? _baseTree.HeadHash;
+ public Hash256 GenesisHash => _baseTree.GenesisHash;
+ public Hash256? PendingHash => _overlayTree.PendingHash ?? _baseTree.PendingHash;
+ public Hash256? FinalizedHash => _overlayTree.FinalizedHash ?? _baseTree.FinalizedHash;
+ public Hash256? SafeHash => _overlayTree.SafeHash ?? _baseTree.SafeHash;
+ public Block? Head => _overlayTree.Head ?? _baseTree.Head;
+ public long? BestPersistedState { get => _overlayTree.BestPersistedState; set => _overlayTree.BestPersistedState = value; }
+
+ public AddBlockResult Insert(BlockHeader header, BlockTreeInsertHeaderOptions headerOptions = BlockTreeInsertHeaderOptions.None) =>
+ _overlayTree.Insert(header, headerOptions);
+
+ public AddBlockResult Insert(Block block,
+ BlockTreeInsertBlockOptions insertBlockOptions = BlockTreeInsertBlockOptions.None,
+ BlockTreeInsertHeaderOptions insertHeaderOptions = BlockTreeInsertHeaderOptions.None,
+ WriteFlags bodiesWriteFlags = WriteFlags.None) =>
+ _overlayTree.Insert(block, insertBlockOptions, insertHeaderOptions, bodiesWriteFlags);
+
+ public void UpdateHeadBlock(Hash256 blockHash) =>
+ _overlayTree.UpdateHeadBlock(blockHash);
+
+ public AddBlockResult SuggestBlock(Block block,
+ BlockTreeSuggestOptions options = BlockTreeSuggestOptions.ShouldProcess) =>
+ _overlayTree.SuggestBlock(block, options);
+
+ public ValueTask SuggestBlockAsync(Block block,
+ BlockTreeSuggestOptions options = BlockTreeSuggestOptions.ShouldProcess) =>
+ _overlayTree.SuggestBlockAsync(block, options);
+
+ public AddBlockResult SuggestHeader(BlockHeader header) => _overlayTree.SuggestHeader(header);
+
+ public bool IsKnownBlock(long number, Hash256 blockHash) => _overlayTree.IsKnownBlock(number, blockHash) || _baseTree.IsKnownBlock(number, blockHash);
+
+ public bool IsKnownBeaconBlock(long number, Hash256 blockHash) => _overlayTree.IsKnownBeaconBlock(number, blockHash) || _baseTree.IsKnownBeaconBlock(number, blockHash);
+
+ public bool WasProcessed(long number, Hash256 blockHash) => _overlayTree.WasProcessed(number, blockHash) || _baseTree.WasProcessed(number, blockHash);
+
+ public void UpdateMainChain(IReadOnlyList blocks, bool wereProcessed, bool forceHeadBlock = false) =>
+ _overlayTree.UpdateMainChain(blocks, wereProcessed, forceHeadBlock);
+
+ public void MarkChainAsProcessed(IReadOnlyList blocks) => _overlayTree.MarkChainAsProcessed(blocks);
+
+ public bool CanAcceptNewBlocks => _overlayTree.CanAcceptNewBlocks;
+
+ public Task Accept(IBlockTreeVisitor blockTreeVisitor, CancellationToken cancellationToken) => _overlayTree.Accept(blockTreeVisitor, cancellationToken);
+
+ public (BlockInfo? Info, ChainLevelInfo? Level) GetInfo(long number, Hash256 blockHash)
+ {
+ (BlockInfo Info, ChainLevelInfo Level) overlayInfo = _overlayTree.GetInfo(number, blockHash);
+ return overlayInfo.Info is not null || overlayInfo.Level is not null ? overlayInfo : _baseTree.GetInfo(number, blockHash);
+ }
+
+ public ChainLevelInfo? FindLevel(long number) => _overlayTree.FindLevel(number) ?? _baseTree.FindLevel(number);
+
+ public BlockInfo FindCanonicalBlockInfo(long blockNumber) => _overlayTree.FindCanonicalBlockInfo(blockNumber) ?? _baseTree.FindCanonicalBlockInfo(blockNumber);
+
+ public Hash256 FindHash(long blockNumber) => _overlayTree.FindHash(blockNumber) ?? _baseTree.FindHash(blockNumber);
+
+ public IOwnedReadOnlyList FindHeaders(Hash256 hash, int numberOfBlocks, int skip, bool reverse)
+ {
+ IOwnedReadOnlyList overlayHeaders = _overlayTree.FindHeaders(hash, numberOfBlocks, skip, reverse);
+ return overlayHeaders.Count > 0 ? overlayHeaders : _baseTree.FindHeaders(hash, numberOfBlocks, skip, reverse);
+ }
+
+ public void DeleteInvalidBlock(Block invalidBlock) =>
+ _overlayTree.DeleteInvalidBlock(invalidBlock);
+
+ public void ForkChoiceUpdated(Hash256? finalizedBlockHash, Hash256? safeBlockBlockHash) =>
+ _overlayTree.ForkChoiceUpdated(finalizedBlockHash, safeBlockBlockHash);
+
+ public event EventHandler? NewBestSuggestedBlock
+ {
+ add
+ {
+ if (value is not null)
+ {
+ _baseTree.NewBestSuggestedBlock += value;
+ _overlayTree.NewBestSuggestedBlock += value;
+ }
+ }
+ remove
+ {
+ if (value is not null)
+ {
+ _baseTree.NewBestSuggestedBlock -= value;
+ _overlayTree.NewBestSuggestedBlock -= value;
+ }
+ }
+ }
+
+ public event EventHandler? NewSuggestedBlock
+ {
+ add
+ {
+ if (value is not null)
+ {
+ _baseTree.NewSuggestedBlock += value;
+ _overlayTree.NewSuggestedBlock += value;
+ }
+ }
+ remove
+ {
+ if (value is not null)
+ {
+ _baseTree.NewSuggestedBlock -= value;
+ _overlayTree.NewSuggestedBlock -= value;
+ }
+ }
+ }
+
+ public event EventHandler? BlockAddedToMain
+ {
+ add
+ {
+ if (value is not null)
+ {
+ _baseTree.BlockAddedToMain += value;
+ _overlayTree.BlockAddedToMain += value;
+ }
+ }
+ remove
+ {
+ if (value is not null)
+ {
+ _baseTree.BlockAddedToMain -= value;
+ _overlayTree.BlockAddedToMain -= value;
+ }
+ }
+ }
+
+ public event EventHandler? NewHeadBlock
+ {
+ add
+ {
+ if (value is not null)
+ {
+ _baseTree.NewHeadBlock += value;
+ _overlayTree.NewHeadBlock += value;
+ }
+ }
+ remove
+ {
+ if (value is not null)
+ {
+ _baseTree.NewHeadBlock -= value;
+ _overlayTree.NewHeadBlock -= value;
+ }
+ }
+ }
+
+ public event EventHandler? OnUpdateMainChain
+ {
+ add
+ {
+ if (value is not null)
+ {
+ _baseTree.OnUpdateMainChain += value;
+ _overlayTree.OnUpdateMainChain += value;
+ }
+ }
+ remove
+ {
+ if (value is not null)
+ {
+ _baseTree.OnUpdateMainChain -= value;
+ _overlayTree.OnUpdateMainChain -= value;
+ }
+ }
+ }
+
+ public int DeleteChainSlice(in long startNumber, long? endNumber = null, bool force = false) =>
+ _overlayTree.DeleteChainSlice(startNumber, endNumber, force);
+
+ public bool IsBetterThanHead(BlockHeader? header) => _overlayTree.IsBetterThanHead(header) || _baseTree.IsBetterThanHead(header);
+
+ public void UpdateBeaconMainChain(BlockInfo[]? blockInfos, long clearBeaconMainChainStartPoint) =>
+ _overlayTree.UpdateBeaconMainChain(blockInfos, clearBeaconMainChainStartPoint);
+
+ public void RecalculateTreeLevels() => _overlayTree.RecalculateTreeLevels();
+
+ public Block? FindBlock(Hash256 blockHash, BlockTreeLookupOptions options, long? blockNumber = null) =>
+ _overlayTree.FindBlock(blockHash, options, blockNumber) ?? _baseTree.FindBlock(blockHash, options, blockNumber);
+
+ public Block? FindBlock(long blockNumber, BlockTreeLookupOptions options) =>
+ _overlayTree.FindBlock(blockNumber, options) ?? _baseTree.FindBlock(blockNumber, options);
+
+ public BlockHeader? FindHeader(Hash256 blockHash, BlockTreeLookupOptions options, long? blockNumber = null) =>
+ _overlayTree.FindHeader(blockHash, options, blockNumber) ?? _baseTree.FindHeader(blockHash, options, blockNumber);
+
+ public BlockHeader? FindHeader(long blockNumber, BlockTreeLookupOptions options) =>
+ _overlayTree.FindHeader(blockNumber, options) ?? _baseTree.FindHeader(blockNumber, options);
+
+ public Hash256? FindBlockHash(long blockNumber) =>
+ _overlayTree.FindBlockHash(blockNumber) ?? _baseTree.FindBlockHash(blockNumber);
+
+ public bool IsMainChain(BlockHeader blockHeader) =>
+ _baseTree.IsMainChain(blockHeader) || _overlayTree.IsMainChain(blockHeader);
+
+ public bool IsMainChain(Hash256 blockHash, bool throwOnMissingHash = true) =>
+ _baseTree.IsMainChain(blockHash, false) || _overlayTree.IsMainChain(blockHash, throwOnMissingHash);
+
+ public BlockHeader FindBestSuggestedHeader() =>
+ _overlayTree.FindBestSuggestedHeader() ?? _baseTree.FindBestSuggestedHeader();
+}
diff --git a/src/Nethermind/Nethermind.Blockchain/Blocks/BlockStore.cs b/src/Nethermind/Nethermind.Blockchain/Blocks/BlockStore.cs
index 29fcdcf5d33..20aee80ea04 100644
--- a/src/Nethermind/Nethermind.Blockchain/Blocks/BlockStore.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Blocks/BlockStore.cs
@@ -18,7 +18,7 @@ public class BlockStore : IBlockStore
{
private readonly IDb _blockDb;
private readonly BlockDecoder _blockDecoder = new();
- private const int CacheSize = 128 + 32;
+ public const int CacheSize = 128 + 32;
private readonly LruCache
_blockCache = new(CacheSize, CacheSize, "blocks");
diff --git a/src/Nethermind/Nethermind.Blockchain/Contracts/Contract.ConstantContract.cs b/src/Nethermind/Nethermind.Blockchain/Contracts/Contract.ConstantContract.cs
index 2d2255b0045..d8b3f164d50 100644
--- a/src/Nethermind/Nethermind.Blockchain/Contracts/Contract.ConstantContract.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Contracts/Contract.ConstantContract.cs
@@ -58,7 +58,7 @@ protected ConstantContractBase(Contract contract)
protected Transaction GenerateTransaction(CallInfo callInfo) =>
_contract.GenerateTransaction(callInfo.ContractAddress, callInfo.FunctionName, callInfo.Sender, DefaultConstantContractGasLimit, callInfo.ParentHeader, callInfo.Arguments);
- protected byte[] CallCore(CallInfo callInfo, IReadOnlyTransactionProcessor readOnlyTransactionProcessor, Transaction transaction) =>
+ protected byte[] CallCore(CallInfo callInfo, ITransactionProcessor readOnlyTransactionProcessor, Transaction transaction) =>
_contract.CallCore(readOnlyTransactionProcessor, callInfo.ParentHeader, callInfo.FunctionName, transaction, true);
protected object[] DecodeReturnData(string functionName, byte[] data) => _contract.DecodeReturnData(functionName, data);
@@ -85,17 +85,17 @@ public override object[] Call(CallInfo callInfo)
lock (_readOnlyTxProcessorSource)
{
- using var readOnlyTransactionProcessor = _readOnlyTxProcessorSource.Build(GetState(callInfo.ParentHeader));
- return CallRaw(callInfo, readOnlyTransactionProcessor);
+ using var scope = _readOnlyTxProcessorSource.Build(GetState(callInfo.ParentHeader));
+ return CallRaw(callInfo, scope);
}
}
- protected virtual object[] CallRaw(CallInfo callInfo, IReadOnlyTransactionProcessor readOnlyTransactionProcessor)
+ protected virtual object[] CallRaw(CallInfo callInfo, IReadOnlyTxProcessingScope scope)
{
var transaction = GenerateTransaction(callInfo);
- if (_contract.ContractAddress is not null && readOnlyTransactionProcessor.IsContractDeployed(_contract.ContractAddress))
+ if (_contract.ContractAddress is not null && scope.WorldState.IsContract(_contract.ContractAddress))
{
- var result = CallCore(callInfo, readOnlyTransactionProcessor, transaction);
+ var result = CallCore(callInfo, scope.TransactionProcessor, transaction);
return callInfo.Result = _contract.DecodeReturnData(callInfo.FunctionName, result);
}
else if (callInfo.MissingContractResult is not null)
diff --git a/src/Nethermind/Nethermind.Blockchain/Find/IBlockFinder.cs b/src/Nethermind/Nethermind.Blockchain/Find/IBlockFinder.cs
index 69299ab7dda..e65b57f8c49 100644
--- a/src/Nethermind/Nethermind.Blockchain/Find/IBlockFinder.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Find/IBlockFinder.cs
@@ -43,8 +43,9 @@ public interface IBlockFinder
/// Checks if the block is currently in the canonical chain
///
/// Hash of the block to check
+ /// If should throw when hash is not found
/// True if part of the canonical chain, otherwise False
- bool IsMainChain(Hash256 blockHash);
+ bool IsMainChain(Hash256 blockHash, bool throwOnMissingHash = true);
public Block? FindBlock(Hash256 blockHash, long? blockNumber = null) => FindBlock(blockHash, BlockTreeLookupOptions.None, blockNumber);
diff --git a/src/Nethermind/Nethermind.Blockchain/FullPruning/FullPruner.cs b/src/Nethermind/Nethermind.Blockchain/FullPruning/FullPruner.cs
index 33e86022f79..e951e03226a 100644
--- a/src/Nethermind/Nethermind.Blockchain/FullPruning/FullPruner.cs
+++ b/src/Nethermind/Nethermind.Blockchain/FullPruning/FullPruner.cs
@@ -254,6 +254,16 @@ private async Task CopyTrie(IPruningContext pruning, Hash256 stateRoot, Cancella
targetNodeStorage.Scheme = INodeStorage.KeyScheme.HalfPath;
}
+ if (originalKeyScheme == INodeStorage.KeyScheme.Hash && targetNodeStorage.Scheme == INodeStorage.KeyScheme.HalfPath)
+ {
+ if (_logger.IsInfo) _logger.Info($"Converting from Hash key scheme to HalfPath key scheme");
+
+ if (_pruningConfig.FullPruningMemoryBudgetMb < 8000)
+ {
+ if (_logger.IsWarn) _logger.Warn($"Full pruning memory budget is less than 8 GB. Full pruning from Hash to HalfPath require more memory budget for efficient copy. Consider increasing full pruning memory budget to at least 8GB.");
+ }
+ }
+
VisitingOptions visitingOptions = new()
{
MaxDegreeOfParallelism = _pruningConfig.FullPruningMaxDegreeOfParallelism,
diff --git a/src/Nethermind/Nethermind.Blockchain/IBlockTree.cs b/src/Nethermind/Nethermind.Blockchain/IBlockTree.cs
index 1bfbfaa6f87..006f2de938b 100644
--- a/src/Nethermind/Nethermind.Blockchain/IBlockTree.cs
+++ b/src/Nethermind/Nethermind.Blockchain/IBlockTree.cs
@@ -153,8 +153,6 @@ AddBlockResult Insert(Block block, BlockTreeInsertBlockOptions insertBlockOption
IOwnedReadOnlyList FindHeaders(Hash256 hash, int numberOfBlocks, int skip, bool reverse);
- BlockHeader FindLowestCommonAncestor(BlockHeader firstDescendant, BlockHeader secondDescendant, long maxSearchDepth);
-
void DeleteInvalidBlock(Block invalidBlock);
void ForkChoiceUpdated(Hash256? finalizedBlockHash, Hash256? safeBlockBlockHash);
diff --git a/src/Nethermind/Nethermind.Blockchain/Processing/WitnessPruner.cs b/src/Nethermind/Nethermind.Blockchain/Processing/WitnessPruner.cs
deleted file mode 100644
index c2863c3e354..00000000000
--- a/src/Nethermind/Nethermind.Blockchain/Processing/WitnessPruner.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
-// SPDX-License-Identifier: LGPL-3.0-only
-
-using System;
-using Nethermind.Blockchain;
-using Nethermind.Core;
-using Nethermind.Logging;
-using Nethermind.State;
-
-namespace Nethermind.Synchronization.Witness
-{
- public static class WitnessCollectorExtensions
- {
- public static IWitnessRepository WithPruning(
- this IWitnessRepository repository,
- IBlockTree blockTree,
- ILogManager logManager,
- int followDistance = 16)
- {
- new WitnessPruner(blockTree, repository, logManager, followDistance).Start();
- return repository;
- }
- }
-
- public class WitnessPruner
- {
- private readonly IBlockTree _blockTree;
- private readonly IWitnessRepository _witnessRepository;
- private readonly int _followDistance;
- private readonly ILogger _logger;
-
- public WitnessPruner(IBlockTree blockTree, IWitnessRepository witnessRepository, ILogManager logManager, int followDistance = 16)
- {
- _blockTree = blockTree ?? throw new ArgumentNullException(nameof(blockTree));
- _witnessRepository = witnessRepository ?? throw new ArgumentNullException(nameof(witnessRepository));
- _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager));
- _followDistance = followDistance;
- }
-
- public void Start()
- {
- _blockTree.NewHeadBlock += OnNewHeadBlock;
- }
-
- private void OnNewHeadBlock(object? sender, BlockEventArgs e)
- {
- long toPrune = e.Block.Number - _followDistance;
- if (toPrune > 0)
- {
- var level = _blockTree.FindLevel(toPrune);
- if (level is not null)
- {
- if (_logger.IsTrace) _logger.Trace($"Pruning witness from blocks with number {toPrune}");
-
- for (int i = 0; i < level.BlockInfos.Length; i++)
- {
- var blockInfo = level.BlockInfos[i];
- if (blockInfo.BlockHash is not null)
- {
- _witnessRepository.Delete(blockInfo.BlockHash);
- }
- }
- }
- }
- }
- }
-}
diff --git a/src/Nethermind/Nethermind.Blockchain/ReadOnlyBlockTree.cs b/src/Nethermind/Nethermind.Blockchain/ReadOnlyBlockTree.cs
index 5ceaacf2495..4fc9e1077e8 100644
--- a/src/Nethermind/Nethermind.Blockchain/ReadOnlyBlockTree.cs
+++ b/src/Nethermind/Nethermind.Blockchain/ReadOnlyBlockTree.cs
@@ -106,13 +106,11 @@ public void UpdateHeadBlock(Hash256 blockHash)
public IOwnedReadOnlyList FindHeaders(Hash256 hash, int numberOfBlocks, int skip, bool reverse) => _wrapped.FindHeaders(hash, numberOfBlocks, skip, reverse);
- public BlockHeader FindLowestCommonAncestor(BlockHeader firstDescendant, BlockHeader secondDescendant, long maxSearchDepth) => _wrapped.FindLowestCommonAncestor(firstDescendant, secondDescendant, maxSearchDepth);
-
public Block FindBlock(long blockNumber, BlockTreeLookupOptions options) => _wrapped.FindBlock(blockNumber, options);
public void DeleteInvalidBlock(Block invalidBlock) => throw new InvalidOperationException($"{nameof(ReadOnlyBlockTree)} does not expect {nameof(DeleteInvalidBlock)} calls");
- public bool IsMainChain(Hash256 blockHash) => _wrapped.IsMainChain(blockHash);
+ public bool IsMainChain(Hash256 blockHash, bool throwOnMissingHash = true) => _wrapped.IsMainChain(blockHash, throwOnMissingHash);
public BlockHeader FindBestSuggestedHeader() => _wrapped.FindBestSuggestedHeader();
diff --git a/src/Nethermind/Nethermind.Blockchain/Receipts/PersistentReceiptStorage.cs b/src/Nethermind/Nethermind.Blockchain/Receipts/PersistentReceiptStorage.cs
index 2d2ef1695c4..7a3ce9593f4 100644
--- a/src/Nethermind/Nethermind.Blockchain/Receipts/PersistentReceiptStorage.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Receipts/PersistentReceiptStorage.cs
@@ -256,7 +256,7 @@ public bool TryGetReceiptsIterator(long blockNumber, Hash256 blockHash, out Rece
};
}
- IReceiptRefDecoder refDecoder = ReceiptArrayStorageDecoder.GetRefDecoder(receiptsData);
+ IReceiptRefDecoder refDecoder = _storageDecoder.GetRefDecoder(receiptsData);
iterator = result ? new ReceiptsIterator(receiptsData, _blocksDb, recoveryContextFactory, refDecoder) : new ReceiptsIterator();
return result;
diff --git a/src/Nethermind/Nethermind.Blockchain/Receipts/ReceiptsRootCalculator.cs b/src/Nethermind/Nethermind.Blockchain/Receipts/ReceiptsRootCalculator.cs
index a70f397f827..5bd7d32bb59 100644
--- a/src/Nethermind/Nethermind.Blockchain/Receipts/ReceiptsRootCalculator.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Receipts/ReceiptsRootCalculator.cs
@@ -13,6 +13,8 @@ public class ReceiptsRootCalculator : IReceiptsRootCalculator
{
public static readonly ReceiptsRootCalculator Instance = new();
+ private static readonly IRlpStreamDecoder _decoder = Rlp.GetStreamDecoder(RlpDecoderKey.Trie);
+
public Hash256 GetReceiptsRoot(TxReceipt[] receipts, IReceiptSpec spec, Hash256? suggestedRoot)
{
Hash256 SkipStateAndStatusReceiptsRoot()
@@ -20,7 +22,7 @@ Hash256 SkipStateAndStatusReceiptsRoot()
receipts.SetSkipStateAndStatusInRlp(true);
try
{
- return ReceiptTrie.CalculateRoot(spec, receipts, ReceiptMessageDecoder.Instance);
+ return ReceiptTrie.CalculateRoot(spec, receipts, _decoder);
}
finally
{
@@ -28,7 +30,7 @@ Hash256 SkipStateAndStatusReceiptsRoot()
}
}
- Hash256 receiptsRoot = ReceiptTrie.CalculateRoot(spec, receipts, ReceiptMessageDecoder.Instance);
+ Hash256 receiptsRoot = ReceiptTrie.CalculateRoot(spec, receipts, _decoder);
if (!spec.ValidateReceipts && receiptsRoot != suggestedRoot)
{
var skipStateAndStatusReceiptsRoot = SkipStateAndStatusReceiptsRoot();
diff --git a/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncConfig.cs b/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncConfig.cs
index a647aa0988c..551a9856a33 100644
--- a/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncConfig.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncConfig.cs
@@ -93,9 +93,6 @@ public interface ISyncConfig : IConfig
[ConfigItem(DisabledForCli = true, HiddenFromDocs = true, DefaultValue = "1")]
public long AncientReceiptsBarrierCalc => Math.Max(1, Math.Min(PivotNumberParsed, Math.Max(AncientBodiesBarrier, AncientReceiptsBarrier)));
- [ConfigItem(Description = "Whether to enable the Witness protocol.", DefaultValue = "false")]
- public bool WitnessProtocolEnabled { get; set; }
-
[ConfigItem(Description = "Whether to use the Snap sync mode.", DefaultValue = "false")]
public bool SnapSync { get; set; }
diff --git a/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncPeer.cs b/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncPeer.cs
index a51275ff58c..82e52beb0ef 100644
--- a/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncPeer.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncPeer.cs
@@ -13,11 +13,6 @@
namespace Nethermind.Blockchain.Synchronization
{
- public interface IWitnessPeer
- {
- Task GetBlockWitnessHashes(Hash256 blockHash, CancellationToken token);
- }
-
public interface ISyncPeer : ITxPoolPeer, IPeerWithSatelliteProtocol
{
Node Node { get; }
diff --git a/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncConfig.cs b/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncConfig.cs
index c896c206c75..d2645336586 100644
--- a/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncConfig.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncConfig.cs
@@ -48,7 +48,6 @@ public string? PivotHash
set => _pivotHash = value;
}
public int MaxAttemptsToUpdatePivot { get; set; } = int.MaxValue;
- public bool WitnessProtocolEnabled { get; set; } = false;
public bool SnapSync { get; set; } = false;
public int SnapSyncAccountRangePartitionCount { get; set; } = 8;
public bool FixReceipts { get; set; } = false;
diff --git a/src/Nethermind/Nethermind.Blockchain/Utils/LastNStateRootTracker.cs b/src/Nethermind/Nethermind.Blockchain/Utils/LastNStateRootTracker.cs
index 9a15de970ce..b9ca08c0792 100644
--- a/src/Nethermind/Nethermind.Blockchain/Utils/LastNStateRootTracker.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Utils/LastNStateRootTracker.cs
@@ -29,7 +29,7 @@ public LastNStateRootTracker(IBlockTree blockTree, int lastN)
_lastN = lastN;
_blockTree.BlockAddedToMain += BlockTreeOnNewHeadBlock;
- if (_blockTree.Head != null) ResetAvailableStateRoots(_blockTree.Head.Header, true);
+ if (_blockTree.Head is not null) ResetAvailableStateRoots(_blockTree.Head.Header, true);
}
private void BlockTreeOnNewHeadBlock(object? sender, BlockEventArgs e)
diff --git a/src/Nethermind/Nethermind.Cli.Test/ProofCliModuleTests.cs b/src/Nethermind/Nethermind.Cli.Test/ProofCliModuleTests.cs
index dac449f4a53..3eac4d9207c 100644
--- a/src/Nethermind/Nethermind.Cli.Test/ProofCliModuleTests.cs
+++ b/src/Nethermind/Nethermind.Cli.Test/ProofCliModuleTests.cs
@@ -7,6 +7,7 @@
using Nethermind.Cli.Modules;
using Nethermind.Core.Crypto;
using Nethermind.Core.Test.Builders;
+using Nethermind.Facade.Eth;
using Nethermind.JsonRpc;
using Nethermind.JsonRpc.Client;
using Nethermind.JsonRpc.Data;
diff --git a/src/Nethermind/Nethermind.Cli/Modules/EthCliModule.cs b/src/Nethermind/Nethermind.Cli/Modules/EthCliModule.cs
index adba54d9821..961ce37bfe9 100644
--- a/src/Nethermind/Nethermind.Cli/Modules/EthCliModule.cs
+++ b/src/Nethermind/Nethermind.Cli/Modules/EthCliModule.cs
@@ -7,6 +7,7 @@
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Extensions;
+using Nethermind.Facade.Eth;
using Nethermind.Int256;
using Nethermind.JsonRpc.Data;
@@ -49,6 +50,10 @@ public JsValue GetProof(string address, string[] storageKeys, string? blockParam
return NodeManager.Post("eth_call", tx, blockParameter ?? "latest").Result;
}
+ [CliFunction("eth", "simulateV1")]
+ public JsValue SimulateV1(ulong version, object[] blockCalls, string? blockParameter = null, bool traceTransfers = true) =>
+ NodeManager.PostJint("eth_simulateV1", 1, blockCalls, blockParameter ?? "latest", traceTransfers).Result;
+
[CliFunction("eth", "getBlockByHash")]
public JsValue GetBlockByHash(string hash, bool returnFullTransactionObjects)
{
diff --git a/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs b/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs
index d30115175e0..a21d6bf5c45 100644
--- a/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs
+++ b/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs
@@ -7,6 +7,7 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using FluentAssertions;
using Nethermind.Blockchain;
using Nethermind.Blockchain.Blocks;
using Nethermind.Blockchain.Receipts;
@@ -55,7 +56,7 @@ private class On
private readonly Dictionary _snapshotManager = new();
private readonly Dictionary _blockTrees = new();
private readonly Dictionary _blockEvents = new();
- private readonly Dictionary _producers = new();
+ private readonly Dictionary _producers = new();
private readonly Dictionary _pools = new();
private On()
@@ -127,8 +128,10 @@ public On CreateNode(PrivateKey privateKey, bool withGenesisAlreadyProcessed = f
_genesis.Header.Hash = _genesis.Header.CalculateHash();
_genesis3Validators.Header.Hash = _genesis3Validators.Header.CalculateHash();
+ CodeInfoRepository codeInfoRepository = new();
TransactionProcessor transactionProcessor = new(goerliSpecProvider, stateProvider,
- new VirtualMachine(blockhashProvider, specProvider, nodeLogManager),
+ new VirtualMachine(blockhashProvider, specProvider, codeInfoRepository, nodeLogManager),
+ codeInfoRepository,
nodeLogManager);
BlockProcessor blockProcessor = new(
goerliSpecProvider,
@@ -137,7 +140,6 @@ public On CreateNode(PrivateKey privateKey, bool withGenesisAlreadyProcessed = f
new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider),
stateProvider,
NullReceiptStorage.Instance,
- NullWitnessCollector.Instance,
new BlockhashStore(blockTree, goerliSpecProvider, stateProvider),
transactionProcessor,
nodeLogManager);
@@ -148,8 +150,8 @@ public On CreateNode(PrivateKey privateKey, bool withGenesisAlreadyProcessed = f
IReadOnlyTrieStore minerTrieStore = trieStore.AsReadOnly();
WorldState minerStateProvider = new(minerTrieStore, codeDb, nodeLogManager);
- VirtualMachine minerVirtualMachine = new(blockhashProvider, specProvider, nodeLogManager);
- TransactionProcessor minerTransactionProcessor = new(goerliSpecProvider, minerStateProvider, minerVirtualMachine, nodeLogManager);
+ VirtualMachine minerVirtualMachine = new(blockhashProvider, specProvider, codeInfoRepository, nodeLogManager);
+ TransactionProcessor minerTransactionProcessor = new(goerliSpecProvider, minerStateProvider, minerVirtualMachine, codeInfoRepository, nodeLogManager);
BlockProcessor minerBlockProcessor = new(
goerliSpecProvider,
@@ -158,7 +160,6 @@ public On CreateNode(PrivateKey privateKey, bool withGenesisAlreadyProcessed = f
new BlockProcessor.BlockProductionTransactionsExecutor(minerTransactionProcessor, minerStateProvider, goerliSpecProvider, _logManager),
minerStateProvider,
NullReceiptStorage.Instance,
- NullWitnessCollector.Instance,
new BlockhashStore(blockTree, goerliSpecProvider, minerStateProvider),
minerTransactionProcessor,
nodeLogManager);
@@ -179,7 +180,6 @@ public On CreateNode(PrivateKey privateKey, bool withGenesisAlreadyProcessed = f
txPoolTxSource,
minerProcessor,
minerStateProvider,
- blockTree,
_timestamper,
new CryptoRandom(),
snapshotManager,
@@ -188,11 +188,21 @@ public On CreateNode(PrivateKey privateKey, bool withGenesisAlreadyProcessed = f
MainnetSpecProvider.Instance,
_cliqueConfig,
nodeLogManager);
- blockProducer.Start();
- ProducedBlockSuggester suggester = new ProducedBlockSuggester(blockTree, blockProducer);
+ CliqueBlockProducerRunner producerRunner = new CliqueBlockProducerRunner(
+ blockTree,
+ _timestamper,
+ new CryptoRandom(),
+ snapshotManager,
+ blockProducer,
+ _cliqueConfig,
+ LimboLogs.Instance);
+
+ producerRunner.Start();
+
+ ProducedBlockSuggester suggester = new ProducedBlockSuggester(blockTree, producerRunner);
- _producers.Add(privateKey, blockProducer);
+ _producers.Add(privateKey, producerRunner);
return this;
}
@@ -253,7 +263,7 @@ public On UncastVote(PrivateKey nodeId, Address address)
public On IsProducingBlocks(PrivateKey nodeId, bool expected, ulong? maxInterval)
{
if (_logger.IsInfo) _logger.Info($"IsProducingBlocks");
- Assert.That(((IBlockProducer)_producers[nodeId]).IsProducingBlocks(maxInterval), Is.EqualTo(expected));
+ Assert.That(((IBlockProducerRunner)_producers[nodeId]).IsProducingBlocks(maxInterval), Is.EqualTo(expected));
return this;
}
diff --git a/src/Nethermind/Nethermind.Clique.Test/CliqueRpcModuleTests.cs b/src/Nethermind/Nethermind.Clique.Test/CliqueRpcModuleTests.cs
index b1f68c90b37..cf8cc178f51 100644
--- a/src/Nethermind/Nethermind.Clique.Test/CliqueRpcModuleTests.cs
+++ b/src/Nethermind/Nethermind.Clique.Test/CliqueRpcModuleTests.cs
@@ -36,7 +36,6 @@ public void Sets_clique_block_producer_properly()
Substitute.For(),
Substitute.For(),
Substitute.For(),
- blockTree,
Substitute.For(),
Substitute.For(),
Substitute.For(),
@@ -48,7 +47,16 @@ public void Sets_clique_block_producer_properly()
SnapshotManager snapshotManager = new(CliqueConfig.Default, new MemDb(), Substitute.For(), NullEthereumEcdsa.Instance, LimboLogs.Instance);
- CliqueRpcModule bridge = new(producer, snapshotManager, blockTree);
+ CliqueBlockProducerRunner producerRunner = new CliqueBlockProducerRunner(
+ blockTree,
+ Substitute.For(),
+ Substitute.For(),
+ snapshotManager,
+ producer,
+ cliqueConfig,
+ LimboLogs.Instance);
+
+ CliqueRpcModule bridge = new(producerRunner, snapshotManager, blockTree);
Assert.DoesNotThrow(() => bridge.CastVote(TestItem.AddressB, true));
Assert.DoesNotThrow(() => bridge.UncastVote(TestItem.AddressB));
Assert.DoesNotThrow(() => bridge.CastVote(TestItem.AddressB, false));
@@ -63,7 +71,7 @@ public void Can_ask_for_block_signer()
BlockHeader header = Build.A.BlockHeader.TestObject;
blockFinder.FindHeader(Arg.Any()).Returns(header);
snapshotManager.GetBlockSealer(header).Returns(TestItem.AddressA);
- CliqueRpcModule rpcModule = new(Substitute.For(), snapshotManager, blockFinder);
+ CliqueRpcModule rpcModule = new(Substitute.For(), snapshotManager, blockFinder);
rpcModule.clique_getBlockSigner(Keccak.Zero).Result.ResultType.Should().Be(ResultType.Success);
rpcModule.clique_getBlockSigner(Keccak.Zero).Data.Should().Be(TestItem.AddressA);
}
@@ -74,7 +82,7 @@ public void Can_ask_for_block_signer_when_block_is_unknown()
ISnapshotManager snapshotManager = Substitute.For();
IBlockFinder blockFinder = Substitute.For();
blockFinder.FindHeader(Arg.Any()).Returns((BlockHeader)null);
- CliqueRpcModule rpcModule = new(Substitute.For(), snapshotManager, blockFinder);
+ CliqueRpcModule rpcModule = new(Substitute.For(), snapshotManager, blockFinder);
rpcModule.clique_getBlockSigner(Keccak.Zero).Result.ResultType.Should().Be(ResultType.Failure);
}
@@ -83,7 +91,7 @@ public void Can_ask_for_block_signer_when_hash_is_null()
{
ISnapshotManager snapshotManager = Substitute.For();
IBlockFinder blockFinder = Substitute.For();
- CliqueRpcModule rpcModule = new(Substitute.For(), snapshotManager, blockFinder);
+ CliqueRpcModule rpcModule = new(Substitute.For(), snapshotManager, blockFinder);
rpcModule.clique_getBlockSigner(null).Result.ResultType.Should().Be(ResultType.Failure);
}
}
diff --git a/src/Nethermind/Nethermind.Clique.Test/CliqueTests.cs b/src/Nethermind/Nethermind.Clique.Test/CliqueTests.cs
index 56bc5325969..21c436e18ca 100644
--- a/src/Nethermind/Nethermind.Clique.Test/CliqueTests.cs
+++ b/src/Nethermind/Nethermind.Clique.Test/CliqueTests.cs
@@ -13,7 +13,9 @@
using Nethermind.Int256;
using Nethermind.Logging;
using Nethermind.Serialization.Rlp;
+using NSubstitute;
using NUnit.Framework;
+using System.Threading.Tasks;
using BlockTree = Nethermind.Blockchain.BlockTree;
namespace Nethermind.Clique.Test
@@ -91,6 +93,37 @@ public void Test_no_signer_data_at_epoch_fails(string blockRlp)
Assert.True(validSeal);
}
+ [TestCase(Block4Rlp)]
+ public async Task SealBlock_SignerCanSignHeader_FullHeaderIsUsedToSign(string blockRlp)
+ {
+ IHeaderSigner signer = Substitute.For();
+ signer.CanSignHeader.Returns(true);
+ signer.CanSign.Returns(true);
+ signer.Address.Returns(new Address("0x7ffc57839b00206d1ad20c69a1981b489f772031"));
+ signer.Sign(Arg.Any()).Returns(new Signature(new byte[65]));
+ CliqueSealer sut = new CliqueSealer(signer, new CliqueConfig(), _snapshotManager, LimboLogs.Instance);
+ Block block = Rlp.Decode(new Rlp(Bytes.FromHexString(blockRlp)));
+
+ await sut.SealBlock(block, System.Threading.CancellationToken.None);
+
+ signer.Received().Sign(Arg.Any());
+ }
+
+ [TestCase(Block4Rlp)]
+ public async Task SealBlock_SignerCannotSignHeader_HashIsUsedToSign(string blockRlp)
+ {
+ ISigner signer = Substitute.For();
+ signer.CanSign.Returns(true);
+ signer.Address.Returns(new Address("0x7ffc57839b00206d1ad20c69a1981b489f772031"));
+ signer.Sign(Arg.Any()).Returns(new Signature(new byte[65]));
+ CliqueSealer sut = new CliqueSealer(signer, new CliqueConfig(), _snapshotManager, LimboLogs.Instance);
+ Block block = Rlp.Decode(new Rlp(Bytes.FromHexString(blockRlp)));
+
+ await sut.SealBlock(block, System.Threading.CancellationToken.None);
+
+ signer.Received().Sign(Arg.Any());
+ }
+
public static Block GetGenesis()
{
Hash256 parentHash = Keccak.Zero;
diff --git a/src/Nethermind/Nethermind.Config/BlocksConfig.cs b/src/Nethermind/Nethermind.Config/BlocksConfig.cs
index 4a6334f40b4..9a12edfb5d4 100644
--- a/src/Nethermind/Nethermind.Config/BlocksConfig.cs
+++ b/src/Nethermind/Nethermind.Config/BlocksConfig.cs
@@ -24,6 +24,7 @@ public class BlocksConfig : IBlocksConfig
public ulong SecondsPerSlot { get; set; } = 12;
+ public bool PreWarmStateOnBlockProcessing { get; set; } = true;
public string ExtraData
{
diff --git a/src/Nethermind/Nethermind.Config/IBlocksConfig.cs b/src/Nethermind/Nethermind.Config/IBlocksConfig.cs
index a78820f5f56..8f232cf2b02 100644
--- a/src/Nethermind/Nethermind.Config/IBlocksConfig.cs
+++ b/src/Nethermind/Nethermind.Config/IBlocksConfig.cs
@@ -34,5 +34,8 @@ public interface IBlocksConfig : IConfig
[ConfigItem(Description = "The block time slot, in seconds.", DefaultValue = "12")]
ulong SecondsPerSlot { get; set; }
+ [ConfigItem(Description = "Try to pre-warm the state when processing blocks. Can lead to 2x speedup in main loop block processing.", DefaultValue = "True")]
+ bool PreWarmStateOnBlockProcessing { get; set; }
+
byte[] GetExtraDataBytes();
}
diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProcessor.cs b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProcessor.cs
index a926ebdb7c7..6d259b36940 100644
--- a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProcessor.cs
@@ -57,7 +57,6 @@ public AuRaBlockProcessor(
blockTransactionsExecutor,
stateProvider,
receiptStorage,
- NullWitnessCollector.Instance,
new BlockhashStore(blockTree, specProvider, stateProvider),
transactionProcessor,
logManager,
diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProducer.cs b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProducer.cs
index 3db92361804..b74ae8cc935 100644
--- a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProducer.cs
+++ b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProducer.cs
@@ -27,7 +27,6 @@ public class AuRaBlockProducer : BlockProducerBase
public AuRaBlockProducer(ITxSource txSource,
IBlockchainProcessor processor,
- IBlockProductionTrigger blockProductionTrigger,
IWorldState stateProvider,
ISealer sealer,
IBlockTree blockTree,
@@ -44,7 +43,6 @@ public AuRaBlockProducer(ITxSource txSource,
processor,
sealer,
blockTree,
- blockProductionTrigger,
stateProvider,
gasLimitCalculator,
timestamper,
diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaPlugin.cs b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaPlugin.cs
index 558433e9e78..f3c766da5f0 100644
--- a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaPlugin.cs
+++ b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaPlugin.cs
@@ -31,6 +31,8 @@ public class AuRaPlugin : IConsensusPlugin, ISynchronizationPlugin, IInitializat
public string SealEngineType => Core.SealEngineType.AuRa;
+ private StartBlockProducerAuRa? _blockProducerStarter;
+
public ValueTask DisposeAsync()
{
@@ -40,16 +42,10 @@ public ValueTask DisposeAsync()
public Task Init(INethermindApi nethermindApi)
{
_nethermindApi = nethermindApi as AuRaNethermindApi;
- return Task.CompletedTask;
- }
-
- public Task InitNetworkProtocol()
- {
- return Task.CompletedTask;
- }
-
- public Task InitRpcModules()
- {
+ if (_nethermindApi is not null)
+ {
+ _blockProducerStarter = new(_nethermindApi);
+ }
return Task.CompletedTask;
}
@@ -63,19 +59,23 @@ public Task InitSynchronization()
return Task.CompletedTask;
}
- public Task InitBlockProducer(IBlockProductionTrigger? blockProductionTrigger = null, ITxSource? additionalTxSource = null)
+ public IBlockProducer InitBlockProducer(ITxSource? additionalTxSource = null)
{
if (_nethermindApi is not null)
{
- StartBlockProducerAuRa blockProducerStarter = new(_nethermindApi);
- DefaultBlockProductionTrigger ??= blockProducerStarter.CreateTrigger();
- return blockProducerStarter.BuildProducer(blockProductionTrigger ?? DefaultBlockProductionTrigger, additionalTxSource);
+ return _blockProducerStarter!.BuildProducer(additionalTxSource);
}
- return Task.FromResult(null);
+ return null;
}
- public IBlockProductionTrigger? DefaultBlockProductionTrigger { get; private set; }
+ public IBlockProducerRunner CreateBlockProducerRunner()
+ {
+ return new StandardBlockProducerRunner(
+ _blockProducerStarter.CreateTrigger(),
+ _nethermindApi.BlockTree,
+ _nethermindApi.BlockProducer!);
+ }
public INethermindApi CreateApi(IConfigProvider configProvider, IJsonSerializer jsonSerializer,
ILogManager logManager, ChainSpec chainSpec) => new AuRaNethermindApi(configProvider, jsonSerializer, logManager, chainSpec);
diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/Contracts/TransactionPermissionContract.cs b/src/Nethermind/Nethermind.Consensus.AuRa/Contracts/TransactionPermissionContract.cs
index 8efb2163ab2..28f57bded5d 100644
--- a/src/Nethermind/Nethermind.Consensus.AuRa/Contracts/TransactionPermissionContract.cs
+++ b/src/Nethermind/Nethermind.Consensus.AuRa/Contracts/TransactionPermissionContract.cs
@@ -109,14 +109,14 @@ public PermissionConstantContract(Contract contract, IReadOnlyTxProcessorSource
{
}
- protected override object[] CallRaw(CallInfo callInfo, IReadOnlyTransactionProcessor readOnlyTransactionProcessor)
+ protected override object[] CallRaw(CallInfo callInfo, IReadOnlyTxProcessingScope scope)
{
if (callInfo is PermissionCallInfo transactionPermissionCallInfo)
{
- transactionPermissionCallInfo.ToIsContract = readOnlyTransactionProcessor.IsContractDeployed(transactionPermissionCallInfo.To);
+ transactionPermissionCallInfo.ToIsContract = scope.WorldState.IsContract(transactionPermissionCallInfo.To);
}
- return base.CallRaw(callInfo, readOnlyTransactionProcessor);
+ return base.CallRaw(callInfo, scope);
}
public class PermissionCallInfo : CallInfo
diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/AuRaNethermindApi.cs b/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/AuRaNethermindApi.cs
index 12151507209..c3822f5edd0 100644
--- a/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/AuRaNethermindApi.cs
+++ b/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/AuRaNethermindApi.cs
@@ -56,7 +56,7 @@ public TxPriorityContract.LocalDataSource? TxPriorityContractLocalDataSource
{
get
{
- if (_txPriorityContractLocalDataSource != null) return _txPriorityContractLocalDataSource;
+ if (_txPriorityContractLocalDataSource is not null) return _txPriorityContractLocalDataSource;
IAuraConfig config = this.Config();
string? auraConfigTxPriorityConfigFilePath = config.TxPriorityConfigFilePath;
diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/StartBlockProducerAuRa.cs b/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/StartBlockProducerAuRa.cs
index a6a8d0ff24f..4abf23d082e 100644
--- a/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/StartBlockProducerAuRa.cs
+++ b/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/StartBlockProducerAuRa.cs
@@ -20,6 +20,7 @@
using Nethermind.Consensus.Producers;
using Nethermind.Consensus.Transactions;
using Nethermind.Core;
+using Nethermind.Core.Crypto;
using Nethermind.Crypto;
using Nethermind.Evm.TransactionProcessing;
using Nethermind.Init.Steps;
@@ -72,7 +73,7 @@ public IBlockProductionTrigger CreateTrigger()
return onlyWhenNotProcessing;
}
- public Task BuildProducer(IBlockProductionTrigger blockProductionTrigger, ITxSource? additionalTxSource = null)
+ public IBlockProducer BuildProducer(ITxSource? additionalTxSource = null)
{
if (_api.EngineSigner is null) throw new StepDependencyException(nameof(_api.EngineSigner));
if (_api.ChainSpec is null) throw new StepDependencyException(nameof(_api.ChainSpec));
@@ -87,7 +88,6 @@ public Task BuildProducer(IBlockProductionTrigger blockProductio
IBlockProducer blockProducer = new AuRaBlockProducer(
producerEnv.TxSource,
producerEnv.ChainProcessor,
- blockProductionTrigger,
producerEnv.ReadOnlyStateProvider,
_api.Sealer,
_api.BlockTree,
@@ -100,10 +100,10 @@ public Task BuildProducer(IBlockProductionTrigger blockProductio
_api.LogManager,
_api.ConfigProvider.GetConfig());
- return Task.FromResult(blockProducer);
+ return blockProducer;
}
- private BlockProcessor CreateBlockProcessor(ReadOnlyTxProcessingEnv changeableTxProcessingEnv)
+ private BlockProcessor CreateBlockProcessor(IReadOnlyTxProcessingScope changeableTxProcessingEnv)
{
if (_api.RewardCalculatorSource is null) throw new StepDependencyException(nameof(_api.RewardCalculatorSource));
if (_api.ValidatorStore is null) throw new StepDependencyException(nameof(_api.ValidatorStore));
@@ -120,9 +120,9 @@ private BlockProcessor CreateBlockProcessor(ReadOnlyTxProcessingEnv changeableTx
new LocalTxFilter(_api.EngineSigner));
_validator = new AuRaValidatorFactory(_api.AbiEncoder,
- changeableTxProcessingEnv.StateProvider,
+ changeableTxProcessingEnv.WorldState,
changeableTxProcessingEnv.TransactionProcessor,
- changeableTxProcessingEnv.BlockTree,
+ _api.BlockTree,
_api.CreateReadOnlyTransactionProcessorSource(),
_api.ReceiptStorage,
_api.ValidatorStore,
@@ -152,10 +152,10 @@ private BlockProcessor CreateBlockProcessor(ReadOnlyTxProcessingEnv changeableTx
_api.BlockValidator,
_api.RewardCalculatorSource.Get(changeableTxProcessingEnv.TransactionProcessor),
_api.BlockProducerEnvFactory.TransactionsExecutorFactory.Create(changeableTxProcessingEnv),
- changeableTxProcessingEnv.StateProvider,
+ changeableTxProcessingEnv.WorldState,
_api.ReceiptStorage,
_api.LogManager,
- changeableTxProcessingEnv.BlockTree,
+ _api.BlockTree,
NullWithdrawalProcessor.Instance,
_api.TransactionProcessor,
_validator,
@@ -164,7 +164,7 @@ private BlockProcessor CreateBlockProcessor(ReadOnlyTxProcessingEnv changeableTx
contractRewriter);
}
- internal TxPoolTxSource CreateTxPoolTxSource(ReadOnlyTxProcessingEnv processingEnv)
+ internal TxPoolTxSource CreateTxPoolTxSource()
{
_txPriorityContract = TxAuRaFilterBuilders.CreateTxPrioritySources(_api);
_localDataSource = _api.TxPriorityContractLocalDataSource;
@@ -205,7 +205,7 @@ internal TxPoolTxSource CreateTxPoolTxSource(ReadOnlyTxProcessingEnv processingE
return new TxPriorityTxSource(
_api.TxPool,
- processingEnv.StateReader,
+ _api.StateReader,
_api.LogManager,
txFilterPipeline,
whitelistContractDataStore,
@@ -227,27 +227,28 @@ BlockProducerEnv Create()
ReadOnlyBlockTree readOnlyBlockTree = _api.BlockTree.AsReadOnly();
ReadOnlyTxProcessingEnv txProcessingEnv = _api.CreateReadOnlyTransactionProcessorSource();
- BlockProcessor blockProcessor = CreateBlockProcessor(txProcessingEnv);
+ IReadOnlyTxProcessingScope scope = txProcessingEnv.Build(Keccak.EmptyTreeHash);
+ BlockProcessor blockProcessor = CreateBlockProcessor(scope);
IBlockchainProcessor blockchainProcessor =
new BlockchainProcessor(
readOnlyBlockTree,
blockProcessor,
_api.BlockPreprocessor,
- txProcessingEnv.StateReader,
+ _api.StateReader,
_api.LogManager,
BlockchainProcessor.Options.NoReceipts);
OneTimeChainProcessor chainProcessor = new(
- txProcessingEnv.StateProvider,
+ scope.WorldState,
blockchainProcessor);
return new BlockProducerEnv()
{
BlockTree = readOnlyBlockTree,
ChainProcessor = chainProcessor,
- ReadOnlyStateProvider = txProcessingEnv.StateProvider,
- TxSource = CreateTxSourceForProducer(txProcessingEnv, additionalTxSource),
+ ReadOnlyStateProvider = scope.WorldState,
+ TxSource = CreateTxSourceForProducer(additionalTxSource),
ReadOnlyTxProcessingEnv = _api.CreateReadOnlyTransactionProcessorSource(),
};
}
@@ -255,8 +256,8 @@ BlockProducerEnv Create()
return _blockProducerContext ??= Create();
}
- private ITxSource CreateStandardTxSourceForProducer(ReadOnlyTxProcessingEnv processingEnv) =>
- CreateTxPoolTxSource(processingEnv);
+ private ITxSource CreateStandardTxSourceForProducer() =>
+ CreateTxPoolTxSource();
private TxPoolTxSource CreateStandardTxPoolTxSource()
{
@@ -270,7 +271,7 @@ private TxPoolTxSource CreateStandardTxPoolTxSource()
private ITxFilter CreateAuraTxFilterForProducer() => TxAuRaFilterBuilders.CreateAuRaTxFilterForProducer(_api, _minGasPricesContractDataStore);
- private ITxSource CreateTxSourceForProducer(ReadOnlyTxProcessingEnv processingEnv, ITxSource? additionalTxSource)
+ private ITxSource CreateTxSourceForProducer(ITxSource? additionalTxSource)
{
bool CheckAddPosdaoTransactions(IList list, long auRaPosdaoTransition)
{
@@ -322,7 +323,7 @@ IList GetRandomContracts(
if (_api.BlockTree is null) throw new StepDependencyException(nameof(_api.BlockTree));
if (_api.EngineSigner is null) throw new StepDependencyException(nameof(_api.EngineSigner));
- IList txSources = new List { CreateStandardTxSourceForProducer(processingEnv) };
+ IList txSources = new List { CreateStandardTxSourceForProducer() };
bool needSigner = false;
if (additionalTxSource is not null)
@@ -337,7 +338,7 @@ IList GetRandomContracts(
if (needSigner)
{
TxSealer transactionSealer = new TxSealer(_api.EngineSigner, _api.Timestamper);
- txSource = new GeneratedTxSource(txSource, transactionSealer, processingEnv.StateReader, _api.LogManager);
+ txSource = new GeneratedTxSource(txSource, transactionSealer, _api.StateReader, _api.LogManager);
}
ITxFilter? txPermissionFilter = TxAuRaFilterBuilders.CreateTxPermissionFilter(_api);
diff --git a/src/Nethermind/Nethermind.Consensus.Clique/CliqueBlockProducer.cs b/src/Nethermind/Nethermind.Consensus.Clique/CliqueBlockProducer.cs
index 53d798834a8..8d9fb4007a1 100644
--- a/src/Nethermind/Nethermind.Consensus.Clique/CliqueBlockProducer.cs
+++ b/src/Nethermind/Nethermind.Consensus.Clique/CliqueBlockProducer.cs
@@ -27,54 +27,38 @@
namespace Nethermind.Consensus.Clique;
-public class CliqueBlockProducer : ICliqueBlockProducer, IDisposable
+public class CliqueBlockProducerRunner : ICliqueBlockProducerRunner, IDisposable
{
private readonly IBlockTree _blockTree;
- private readonly IWorldState _stateProvider;
private readonly ITimestamper _timestamper;
private readonly ILogger _logger;
private readonly ICryptoRandom _cryptoRandom;
private readonly WiggleRandomizer _wiggle;
- private readonly ITxSource _txSource;
- private readonly IBlockchainProcessor _processor;
- private readonly ISealer _sealer;
- private readonly IGasLimitCalculator _gasLimitCalculator;
- private readonly ISpecProvider _specProvider;
private readonly ISnapshotManager _snapshotManager;
private readonly ICliqueConfig _config;
- private readonly ConcurrentDictionary _proposals = new();
-
private readonly CancellationTokenSource _cancellationTokenSource = new();
private readonly System.Timers.Timer _timer = new();
private DateTime _lastProducedBlock;
- public CliqueBlockProducer(
- ITxSource txSource,
- IBlockchainProcessor blockchainProcessor,
- IWorldState stateProvider,
+ private CliqueBlockProducer _blockProducer;
+
+ public CliqueBlockProducerRunner(
IBlockTree blockTree,
ITimestamper timestamper,
ICryptoRandom cryptoRandom,
ISnapshotManager snapshotManager,
- ISealer cliqueSealer,
- IGasLimitCalculator gasLimitCalculator,
- ISpecProvider? specProvider,
+ CliqueBlockProducer blockProducer,
ICliqueConfig config,
ILogManager logManager)
{
_logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager));
- _txSource = txSource ?? throw new ArgumentNullException(nameof(txSource));
- _processor = blockchainProcessor ?? throw new ArgumentNullException(nameof(blockchainProcessor));
_blockTree = blockTree ?? throw new ArgumentNullException(nameof(blockTree));
- _stateProvider = stateProvider ?? throw new ArgumentNullException(nameof(stateProvider));
_timestamper = timestamper ?? throw new ArgumentNullException(nameof(timestamper));
_cryptoRandom = cryptoRandom ?? throw new ArgumentNullException(nameof(cryptoRandom));
- _sealer = cliqueSealer ?? throw new ArgumentNullException(nameof(cliqueSealer));
- _gasLimitCalculator = gasLimitCalculator ?? throw new ArgumentNullException(nameof(gasLimitCalculator));
- _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider));
_snapshotManager = snapshotManager ?? throw new ArgumentNullException(nameof(snapshotManager));
+ _blockProducer = blockProducer;
_config = config ?? throw new ArgumentNullException(nameof(config));
_wiggle = new WiggleRandomizer(_cryptoRandom, _snapshotManager);
@@ -91,7 +75,7 @@ public CliqueBlockProducer(
public void CastVote(Address signer, bool vote)
{
- bool success = _proposals.TryAdd(signer, vote);
+ bool success = _blockProducer.Proposals.TryAdd(signer, vote);
if (!success)
{
throw new InvalidOperationException($"A vote for {signer} has already been cast.");
@@ -102,7 +86,7 @@ public void CastVote(Address signer, bool vote)
public void UncastVote(Address signer)
{
- bool success = _proposals.TryRemove(signer, out _);
+ bool success = _blockProducer.Proposals.TryRemove(signer, out _);
if (!success)
{
throw new InvalidOperationException("Cannot uncast vote");
@@ -189,11 +173,10 @@ private void TimerOnElapsed(object sender, ElapsedEventArgs e)
private Task? _producerTask;
- public Task Start()
+ public void Start()
{
_blockTree.NewHeadBlock += BlockTreeOnNewHeadBlock;
_producerTask = RunConsumeSignal();
- return Task.CompletedTask;
}
private Task RunConsumeSignal()
@@ -204,7 +187,7 @@ private Task RunConsumeSignal()
{
try
{
- ConsumeSignal();
+ ConsumeSignal().Wait();
if (_logger.IsDebug) _logger.Debug("Clique block producer complete.");
}
catch (OperationCanceledException)
@@ -236,11 +219,12 @@ private void BlockTreeOnNewHeadBlock(object? sender, BlockEventArgs e)
_signalsQueue.Add(e.Block);
}
- private void ConsumeSignal()
+ private async Task ConsumeSignal()
{
_lastProducedBlock = DateTime.UtcNow;
foreach (Block signal in _signalsQueue.GetConsumingEnumerable(_cancellationTokenSource.Token))
{
+ // TODO: Maybe use IBlockProducer specific to clique?
Block parentBlock = signal;
while (_signalsQueue.TryTake(out Block? nextSignal))
{
@@ -252,59 +236,12 @@ private void ConsumeSignal()
try
{
- Block? block = PrepareBlock(parentBlock);
- if (block is null)
+ Block? block = await _blockProducer.BuildBlock(parentBlock?.Header, token: CancellationToken.None);
+ if (block is not null)
{
- if (_logger.IsTrace) _logger.Trace("Skipping block production or block production failed");
- Metrics.FailedBlockSeals++;
- continue;
+ _scheduledBlock = block;
+ _lastProducedBlock = DateTime.UtcNow;
}
-
- if (_logger.IsInfo) _logger.Info($"Processing prepared block {block.Number}");
- Block? processedBlock = _processor.Process(
- block,
- ProcessingOptions.ProducingBlock,
- NullBlockTracer.Instance);
- if (processedBlock is null)
- {
- if (_logger.IsInfo) _logger.Info($"Prepared block has lost the race");
- Metrics.FailedBlockSeals++;
- continue;
- }
-
- if (_logger.IsDebug) _logger.Debug($"Sealing prepared block {processedBlock.Number}");
-
- _sealer.SealBlock(processedBlock, _cancellationTokenSource.Token).ContinueWith(t =>
- {
- if (t.IsCompletedSuccessfully)
- {
- if (t.Result is not null)
- {
- if (_logger.IsInfo)
- _logger.Info($"Sealed block {t.Result.ToString(Block.Format.HashNumberDiffAndTx)}");
- _scheduledBlock = t.Result;
- _lastProducedBlock = DateTime.UtcNow;
- Metrics.BlocksSealed++;
- }
- else
- {
- if (_logger.IsInfo)
- _logger.Info(
- $"Failed to seal block {processedBlock.ToString(Block.Format.HashNumberDiffAndTx)} (null seal)");
- Metrics.FailedBlockSeals++;
- }
- }
- else if (t.IsFaulted)
- {
- if (_logger.IsError) _logger.Error("Mining failed", t.Exception);
- Metrics.FailedBlockSeals++;
- }
- else if (t.IsCanceled)
- {
- if (_logger.IsInfo) _logger.Info($"Sealing block {processedBlock.Number} cancelled");
- Metrics.FailedBlockSeals++;
- }
- }, _cancellationTokenSource.Token);
}
catch (Exception e)
{
@@ -324,7 +261,7 @@ public async Task StopAsync()
await (_producerTask ?? Task.CompletedTask);
}
- bool IBlockProducer.IsProducingBlocks(ulong? maxProducingInterval)
+ bool IBlockProducerRunner.IsProducingBlocks(ulong? maxProducingInterval)
{
if (_producerTask is null || _producerTask.IsCompleted)
return false;
@@ -336,11 +273,122 @@ bool IBlockProducer.IsProducingBlocks(ulong? maxProducingInterval)
public event EventHandler? BlockProduced;
+
+ public void Dispose()
+ {
+ _cancellationTokenSource?.Dispose();
+ _timer?.Dispose();
+ }
+}
+
+public class CliqueBlockProducer : IBlockProducer
+{
+ private readonly IWorldState _stateProvider;
+ private readonly ITxSource _txSource;
+ private readonly IBlockchainProcessor _processor;
+ private readonly ISealer _sealer;
+ private readonly IGasLimitCalculator _gasLimitCalculator;
+ private readonly ISpecProvider _specProvider;
+ private readonly ISnapshotManager _snapshotManager;
+ private readonly ILogger _logger;
+ private readonly ITimestamper _timestamper;
+ private readonly ICryptoRandom _cryptoRandom;
+ private readonly ICliqueConfig _config;
+ private readonly ConcurrentDictionary _proposals = new();
+
+ public CliqueBlockProducer(
+ ITxSource txSource,
+ IBlockchainProcessor blockchainProcessor,
+ IWorldState stateProvider,
+ ITimestamper timestamper,
+ ICryptoRandom cryptoRandom,
+ ISnapshotManager snapshotManager,
+ ISealer cliqueSealer,
+ IGasLimitCalculator gasLimitCalculator,
+ ISpecProvider? specProvider,
+ ICliqueConfig config,
+ ILogManager logManager
+ )
+ {
+ _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager));
+ _txSource = txSource ?? throw new ArgumentNullException(nameof(txSource));
+ _processor = blockchainProcessor ?? throw new ArgumentNullException(nameof(blockchainProcessor));
+ _stateProvider = stateProvider ?? throw new ArgumentNullException(nameof(stateProvider));
+ _timestamper = timestamper ?? throw new ArgumentNullException(nameof(timestamper));
+ _cryptoRandom = cryptoRandom ?? throw new ArgumentNullException(nameof(cryptoRandom));
+ _sealer = cliqueSealer ?? throw new ArgumentNullException(nameof(cliqueSealer));
+ _gasLimitCalculator = gasLimitCalculator ?? throw new ArgumentNullException(nameof(gasLimitCalculator));
+ _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider));
+ _snapshotManager = snapshotManager ?? throw new ArgumentNullException(nameof(snapshotManager));
+ _config = config ?? throw new ArgumentNullException(nameof(config));
+ _logger = logManager.GetClassLogger();
+ }
+
+ public ConcurrentDictionary Proposals => _proposals;
+
+ public async Task BuildBlock(BlockHeader? parentHeader, IBlockTracer? blockTracer = null,
+ PayloadAttributes? payloadAttributes = null, CancellationToken? token = null)
+ {
+ token ??= default;
+ Block? block = PrepareBlock(parentHeader);
+ if (block is null)
+ {
+ if (_logger.IsTrace) _logger.Trace("Skipping block production or block production failed");
+ Metrics.FailedBlockSeals++;
+ return null;
+ }
+
+ if (_logger.IsInfo) _logger.Info($"Processing prepared block {block.Number}");
+ Block? processedBlock = _processor.Process(
+ block,
+ ProcessingOptions.ProducingBlock,
+ NullBlockTracer.Instance);
+ if (processedBlock is null)
+ {
+ if (_logger.IsInfo) _logger.Info($"Prepared block has lost the race");
+ Metrics.FailedBlockSeals++;
+ return null;
+ }
+
+ if (_logger.IsDebug) _logger.Debug($"Sealing prepared block {processedBlock.Number}");
+
+ try
+ {
+ Block? sealedBlock = await _sealer.SealBlock(processedBlock, token.Value);
+ if (sealedBlock is not null)
+ {
+ if (_logger.IsInfo)
+ _logger.Info($"Sealed block {sealedBlock.ToString(Block.Format.HashNumberDiffAndTx)}");
+ Metrics.BlocksSealed++;
+ }
+ else
+ {
+ if (_logger.IsInfo)
+ _logger.Info(
+ $"Failed to seal block {processedBlock.ToString(Block.Format.HashNumberDiffAndTx)} (null seal)");
+ Metrics.FailedBlockSeals++;
+ }
+
+ return sealedBlock;
+ }
+ catch (OperationCanceledException)
+ {
+ if (_logger.IsInfo) _logger.Info($"Sealing block {processedBlock.Number} cancelled");
+ Metrics.FailedBlockSeals++;
+ }
+ catch (Exception e)
+ {
+ if (_logger.IsError) _logger.Error("Mining failed", e);
+ Metrics.FailedBlockSeals++;
+ }
+
+ return null;
+ }
+
private Hash256? _recentNotAllowedParent;
- private Block? PrepareBlock(Block parentBlock)
+ private Block? PrepareBlock(BlockHeader parentHeader)
{
- BlockHeader parentHeader = parentBlock.Header;
if (parentHeader.Hash is null)
{
if (_logger.IsError) _logger.Error(
@@ -348,20 +396,20 @@ bool IBlockProducer.IsProducingBlocks(ulong? maxProducingInterval)
return null;
}
- if (_recentNotAllowedParent == parentBlock.Hash)
+ if (_recentNotAllowedParent == parentHeader.Hash)
{
return null;
}
if (!_sealer.CanSeal(parentHeader.Number + 1, parentHeader.Hash))
{
- if (_logger.IsTrace) _logger.Trace($"Not allowed to sign block ({parentBlock.Number + 1})");
+ if (_logger.IsTrace) _logger.Trace($"Not allowed to sign block ({parentHeader.Number + 1})");
_recentNotAllowedParent = parentHeader.Hash;
return null;
}
if (_logger.IsInfo)
- _logger.Info($"Preparing new block on top of {parentBlock.ToString(Block.Format.Short)}");
+ _logger.Info($"Preparing new block on top of {parentHeader}");
ulong timestamp = _timestamper.UnixTime.Seconds;
@@ -370,9 +418,9 @@ bool IBlockProducer.IsProducingBlocks(ulong? maxProducingInterval)
Keccak.OfAnEmptySequenceRlp,
Address.Zero,
1,
- parentBlock.Number + 1,
- _gasLimitCalculator.GetGasLimit(parentBlock.Header),
- timestamp > parentBlock.Timestamp ? timestamp : parentBlock.Timestamp + 1,
+ parentHeader.Number + 1,
+ _gasLimitCalculator.GetGasLimit(parentHeader),
+ timestamp > parentHeader.Timestamp ? timestamp : parentHeader.Timestamp + 1,
Array.Empty());
// If the block isn't a checkpoint, cast a random vote (good enough for now)
@@ -404,16 +452,16 @@ bool IBlockProducer.IsProducingBlocks(ulong? maxProducingInterval)
}
// Ensure the timestamp has the correct delay
- header.Timestamp = Math.Max(parentBlock.Timestamp + _config.BlockPeriod, _timestamper.UnixTime.Seconds);
+ header.Timestamp = Math.Max(parentHeader.Timestamp + _config.BlockPeriod, _timestamper.UnixTime.Seconds);
var spec = _specProvider.GetSpec(header);
header.BaseFeePerGas = BaseFeeCalculator.Calculate(parentHeader, spec);
// Set the correct difficulty
header.Difficulty = CalculateDifficulty(snapshot, _sealer.Address);
- header.TotalDifficulty = parentBlock.TotalDifficulty + header.Difficulty;
+ header.TotalDifficulty = parentHeader.TotalDifficulty + header.Difficulty;
if (_logger.IsDebug)
- _logger.Debug($"Setting total difficulty to {parentBlock.TotalDifficulty} + {header.Difficulty}.");
+ _logger.Debug($"Setting total difficulty to {parentHeader.TotalDifficulty} + {header.Difficulty}.");
// Set extra data
int mainBytesLength = Clique.ExtraVanityLength + Clique.ExtraSealLength;
@@ -441,14 +489,14 @@ bool IBlockProducer.IsProducingBlocks(ulong? maxProducingInterval)
_stateProvider.StateRoot = parentHeader.StateRoot!;
- IEnumerable selectedTxs = _txSource.GetTransactions(parentBlock.Header, header.GasLimit);
+ IEnumerable selectedTxs = _txSource.GetTransactions(parentHeader, header.GasLimit);
Block block = new BlockToProduce(
header,
selectedTxs,
Array.Empty(),
spec.WithdrawalsEnabled ? Enumerable.Empty() : null,
spec.ConsensusRequestsEnabled ? Enumerable.Empty() : null
- );
+ );
header.TxRoot = TxTrie.CalculateRoot(block.Transactions);
block.Header.Author = _sealer.Address;
return block;
@@ -465,10 +513,4 @@ private UInt256 CalculateDifficulty(Snapshot snapshot, Address signer)
if (_logger.IsInfo) _logger.Info("Producing out of turn block");
return Clique.DifficultyNoTurn;
}
-
- public void Dispose()
- {
- _cancellationTokenSource?.Dispose();
- _timer?.Dispose();
- }
}
diff --git a/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs b/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs
index d5bc352e850..6ff7e436189 100644
--- a/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs
+++ b/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs
@@ -16,6 +16,9 @@
using Nethermind.Consensus.Transactions;
using Nethermind.Consensus.Withdrawals;
using Nethermind.Core.Attributes;
+using Nethermind.Core.Crypto;
+using Nethermind.Db;
+using Nethermind.Evm.TransactionProcessing;
using Nethermind.JsonRpc.Modules;
using Nethermind.State;
@@ -67,11 +70,11 @@ public Task Init(INethermindApi nethermindApi)
return Task.CompletedTask;
}
- public Task InitBlockProducer(IBlockProductionTrigger? blockProductionTrigger = null, ITxSource? additionalTxSource = null)
+ public IBlockProducer InitBlockProducer(ITxSource? additionalTxSource = null)
{
if (_nethermindApi!.SealEngineType != Nethermind.Core.SealEngineType.Clique)
{
- return Task.FromResult((IBlockProducer)null);
+ return null;
}
(IApiWithBlockchain getFromApi, IApiWithBlockchain setInApi) = _nethermindApi!.ForProducer;
@@ -99,18 +102,19 @@ public Task InitBlockProducer(IBlockProductionTrigger? blockProd
getFromApi.SpecProvider,
getFromApi.LogManager);
+ IReadOnlyTxProcessingScope scope = producerEnv.Build(Keccak.EmptyTreeHash);
+
BlockProcessor producerProcessor = new(
getFromApi!.SpecProvider,
getFromApi!.BlockValidator,
NoBlockRewards.Instance,
- getFromApi.BlockProducerEnvFactory.TransactionsExecutorFactory.Create(producerEnv),
- producerEnv.StateProvider,
+ getFromApi.BlockProducerEnvFactory.TransactionsExecutorFactory.Create(scope),
+ scope.WorldState,
NullReceiptStorage.Instance,
- NullWitnessCollector.Instance,
- new BlockhashStore(getFromApi.BlockTree, getFromApi.SpecProvider, producerEnv.StateProvider),
+ new BlockhashStore(getFromApi.BlockTree, getFromApi.SpecProvider, scope.WorldState),
getFromApi.TransactionProcessor,
getFromApi.LogManager,
- new BlockProductionWithdrawalProcessor(new WithdrawalProcessor(producerEnv.StateProvider, getFromApi.LogManager)));
+ new BlockProductionWithdrawalProcessor(new WithdrawalProcessor(scope.WorldState, getFromApi.LogManager)));
IBlockchainProcessor producerChainProcessor = new BlockchainProcessor(
readOnlyBlockTree,
@@ -121,7 +125,7 @@ public Task InitBlockProducer(IBlockProductionTrigger? blockProd
BlockchainProcessor.Options.NoReceipts);
OneTimeChainProcessor chainProcessor = new(
- producerEnv.StateProvider,
+ scope.WorldState,
producerChainProcessor);
ITxFilterPipeline txFilterPipeline =
@@ -142,8 +146,7 @@ public Task InitBlockProducer(IBlockProductionTrigger? blockProd
CliqueBlockProducer blockProducer = new(
additionalTxSource.Then(txPoolTxSource),
chainProcessor,
- producerEnv.StateProvider,
- getFromApi.BlockTree!,
+ scope.WorldState,
getFromApi.Timestamper,
getFromApi.CryptoRandom,
_snapshotManager!,
@@ -153,14 +156,21 @@ public Task InitBlockProducer(IBlockProductionTrigger? blockProd
_cliqueConfig!,
getFromApi.LogManager);
- getFromApi.DisposeStack.Push(blockProducer);
-
- return Task.FromResult((IBlockProducer)blockProducer);
+ return blockProducer;
}
- public Task InitNetworkProtocol()
+ public IBlockProducerRunner CreateBlockProducerRunner()
{
- return Task.CompletedTask;
+ _blockProducerRunner = new CliqueBlockProducerRunner(
+ _nethermindApi.BlockTree,
+ _nethermindApi.Timestamper,
+ _nethermindApi.CryptoRandom,
+ _snapshotManager,
+ (CliqueBlockProducer)_nethermindApi.BlockProducer!,
+ _cliqueConfig,
+ _nethermindApi.LogManager);
+ _nethermindApi.DisposeStack.Push(_blockProducerRunner);
+ return _blockProducerRunner;
}
public Task InitRpcModules()
@@ -172,7 +182,7 @@ public Task InitRpcModules()
(IApiWithNetwork getFromApi, _) = _nethermindApi!.ForRpc;
CliqueRpcModule cliqueRpcModule = new(
- getFromApi!.BlockProducer as ICliqueBlockProducer,
+ _blockProducerRunner,
_snapshotManager!,
getFromApi.BlockTree!);
@@ -184,9 +194,6 @@ public Task InitRpcModules()
public string SealEngineType => Nethermind.Core.SealEngineType.Clique;
- [Todo("Redo clique producer to support triggers and MEV")]
- public IBlockProductionTrigger DefaultBlockProductionTrigger => _nethermindApi!.ManualBlockProductionTrigger;
-
public ValueTask DisposeAsync() { return ValueTask.CompletedTask; }
private INethermindApi? _nethermindApi;
@@ -196,5 +203,6 @@ public Task InitRpcModules()
private ICliqueConfig? _cliqueConfig;
private IBlocksConfig? _blocksConfig;
+ private CliqueBlockProducerRunner _blockProducerRunner = null!;
}
}
diff --git a/src/Nethermind/Nethermind.Consensus.Clique/CliqueRpcModule.cs b/src/Nethermind/Nethermind.Consensus.Clique/CliqueRpcModule.cs
index 82581295402..07142a25b7a 100644
--- a/src/Nethermind/Nethermind.Consensus.Clique/CliqueRpcModule.cs
+++ b/src/Nethermind/Nethermind.Consensus.Clique/CliqueRpcModule.cs
@@ -15,11 +15,11 @@ public class CliqueRpcModule : ICliqueRpcModule
{
private const string CannotVoteOnNonValidatorMessage = "Not a signer node - cannot vote";
- private readonly ICliqueBlockProducer? _cliqueBlockProducer;
+ private readonly ICliqueBlockProducerRunner? _cliqueBlockProducer;
private readonly ISnapshotManager _snapshotManager;
private readonly IBlockFinder _blockTree;
- public CliqueRpcModule(ICliqueBlockProducer? cliqueBlockProducer, ISnapshotManager snapshotManager, IBlockFinder blockTree)
+ public CliqueRpcModule(ICliqueBlockProducerRunner? cliqueBlockProducer, ISnapshotManager snapshotManager, IBlockFinder blockTree)
{
_cliqueBlockProducer = cliqueBlockProducer;
_snapshotManager = snapshotManager ?? throw new ArgumentNullException(nameof(snapshotManager));
diff --git a/src/Nethermind/Nethermind.Consensus.Clique/CliqueSealer.cs b/src/Nethermind/Nethermind.Consensus.Clique/CliqueSealer.cs
index 584a1194956..2e47118d42e 100644
--- a/src/Nethermind/Nethermind.Consensus.Clique/CliqueSealer.cs
+++ b/src/Nethermind/Nethermind.Consensus.Clique/CliqueSealer.cs
@@ -7,8 +7,11 @@
using System.Threading.Tasks;
using Nethermind.Core;
using Nethermind.Core.Crypto;
+using Nethermind.Core.Extensions;
using Nethermind.Crypto;
+using Nethermind.JsonRpc;
using Nethermind.Logging;
+using Nethermind.Serialization.Rlp;
[assembly: InternalsVisibleTo("Nethermind.Clique.Test")]
@@ -27,7 +30,6 @@ public CliqueSealer(ISigner signer, ICliqueConfig config, ISnapshotManager snaps
_snapshotManager = snapshotManager ?? throw new ArgumentNullException(nameof(snapshotManager));
_config = config ?? throw new ArgumentNullException(nameof(config));
_signer = signer ?? throw new ArgumentNullException(nameof(signer));
-
if (config.Epoch == 0) config.Epoch = Clique.DefaultEpochLength;
}
@@ -64,7 +66,19 @@ public CliqueSealer(ISigner signer, ICliqueConfig config, ISnapshotManager snaps
// Sign all the things!
Hash256 headerHash = SnapshotManager.CalculateCliqueHeaderHash(header);
- Signature signature = _signer.Sign(headerHash);
+ Signature signature;
+ if (_signer is IHeaderSigner headerSigner)
+ {
+ BlockHeader clone = header.Clone();
+ clone.ExtraData = SnapshotManager.SliceExtraSealFromExtraData(clone.ExtraData);
+ clone.Hash = headerHash;
+ signature = headerSigner.Sign(clone);
+ }
+ else
+ {
+ signature = _signer.Sign(headerHash);
+ }
+
// Copy signature bytes (R and S)
byte[] signatureBytes = signature.Bytes;
Array.Copy(signatureBytes, 0, header.ExtraData, header.ExtraData.Length - Clique.ExtraSealLength, signatureBytes.Length);
diff --git a/src/Nethermind/Nethermind.Consensus.Clique/ICliqueBlockProducer.cs b/src/Nethermind/Nethermind.Consensus.Clique/ICliqueBlockProducer.cs
index e5e6b742c41..e2fbc43492e 100644
--- a/src/Nethermind/Nethermind.Consensus.Clique/ICliqueBlockProducer.cs
+++ b/src/Nethermind/Nethermind.Consensus.Clique/ICliqueBlockProducer.cs
@@ -6,7 +6,7 @@
namespace Nethermind.Consensus.Clique
{
- public interface ICliqueBlockProducer : IBlockProducer
+ public interface ICliqueBlockProducerRunner : IBlockProducerRunner
{
void CastVote(Address signer, bool vote);
void UncastVote(Address signer);
diff --git a/src/Nethermind/Nethermind.Consensus.Clique/SnapshotManager.cs b/src/Nethermind/Nethermind.Consensus.Clique/SnapshotManager.cs
index 99e68471b15..29b8e19a91f 100644
--- a/src/Nethermind/Nethermind.Consensus.Clique/SnapshotManager.cs
+++ b/src/Nethermind/Nethermind.Consensus.Clique/SnapshotManager.cs
@@ -75,16 +75,21 @@ private int CalculateSignersCount(BlockHeader blockHeader)
public static Hash256 CalculateCliqueHeaderHash(BlockHeader blockHeader)
{
- int extraSeal = 65;
- int shortExtraLength = blockHeader.ExtraData.Length - extraSeal;
byte[] fullExtraData = blockHeader.ExtraData;
- byte[] shortExtraData = blockHeader.ExtraData.Slice(0, shortExtraLength);
+ byte[] shortExtraData = SliceExtraSealFromExtraData(blockHeader.ExtraData);
blockHeader.ExtraData = shortExtraData;
Hash256 sigHash = blockHeader.CalculateHash();
blockHeader.ExtraData = fullExtraData;
return sigHash;
}
+ public static byte[] SliceExtraSealFromExtraData(byte[] extraData)
+ {
+ if (extraData.Length < Clique.ExtraSealLength)
+ new ArgumentException($"Cannot be less than extra seal length ({Clique.ExtraSealLength}).", nameof(extraData));
+ return extraData.Slice(0, extraData.Length - Clique.ExtraSealLength);
+ }
+
private readonly object _snapshotCreationLock = new();
public ulong GetLastSignersCount() => _lastSignersCount;
diff --git a/src/Nethermind/Nethermind.Consensus.Ethash/EthashPlugin.cs b/src/Nethermind/Nethermind.Consensus.Ethash/EthashPlugin.cs
index 89207009a90..dae39105746 100644
--- a/src/Nethermind/Nethermind.Consensus.Ethash/EthashPlugin.cs
+++ b/src/Nethermind/Nethermind.Consensus.Ethash/EthashPlugin.cs
@@ -46,23 +46,19 @@ public Task Init(INethermindApi nethermindApi)
return Task.CompletedTask;
}
- public Task InitBlockProducer(IBlockProductionTrigger? blockProductionTrigger = null, ITxSource? additionalTxSource = null)
+ public IBlockProducer InitBlockProducer(ITxSource? additionalTxSource = null)
{
- return Task.FromResult((IBlockProducer)null);
+ return null;
}
- public Task InitNetworkProtocol()
- {
- return Task.CompletedTask;
- }
+ public string SealEngineType => Core.SealEngineType.Ethash;
- public Task InitRpcModules()
+ public IBlockProducerRunner CreateBlockProducerRunner()
{
- return Task.CompletedTask;
+ return new StandardBlockProducerRunner(
+ _nethermindApi.ManualBlockProductionTrigger,
+ _nethermindApi.BlockTree,
+ _nethermindApi.BlockProducer!);
}
-
- public string SealEngineType => Nethermind.Core.SealEngineType.Ethash;
-
- public IBlockProductionTrigger DefaultBlockProductionTrigger => _nethermindApi.ManualBlockProductionTrigger;
}
}
diff --git a/src/Nethermind/Nethermind.Consensus.Ethash/MinedBlockProducer.cs b/src/Nethermind/Nethermind.Consensus.Ethash/MinedBlockProducer.cs
index 80b111c77ad..2aaa8e1a62e 100644
--- a/src/Nethermind/Nethermind.Consensus.Ethash/MinedBlockProducer.cs
+++ b/src/Nethermind/Nethermind.Consensus.Ethash/MinedBlockProducer.cs
@@ -19,7 +19,6 @@ public MinedBlockProducer(ITxSource txSource,
IBlockchainProcessor processor,
ISealer sealer,
IBlockTree blockTree,
- IBlockProductionTrigger blockProductionTrigger,
IWorldState stateProvider,
IGasLimitCalculator gasLimitCalculator,
ITimestamper timestamper,
@@ -31,7 +30,6 @@ public MinedBlockProducer(ITxSource txSource,
processor,
sealer,
blockTree,
- blockProductionTrigger,
stateProvider,
gasLimitCalculator,
timestamper,
diff --git a/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs b/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs
index 931fc547172..e1ddd19a420 100644
--- a/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs
+++ b/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs
@@ -13,7 +13,9 @@
using Nethermind.Consensus.Producers;
using Nethermind.Consensus.Rewards;
using Nethermind.Consensus.Transactions;
+using Nethermind.Core.Crypto;
using Nethermind.Db;
+using Nethermind.Evm.TransactionProcessing;
using Nethermind.Logging;
using Nethermind.State;
@@ -37,11 +39,11 @@ public Task Init(INethermindApi nethermindApi)
return Task.CompletedTask;
}
- public Task InitBlockProducer(IBlockProductionTrigger? blockProductionTrigger = null, ITxSource? additionalTxSource = null)
+ public IBlockProducer InitBlockProducer(ITxSource? additionalTxSource = null)
{
if (_nethermindApi!.SealEngineType != Nethermind.Core.SealEngineType.NethDev)
{
- return Task.FromResult((IBlockProducer)null);
+ return null;
}
var (getFromApi, _) = _nethermindApi!.ForProducer;
@@ -70,15 +72,16 @@ public Task InitBlockProducer(IBlockProductionTrigger? blockProd
getFromApi.SpecProvider,
getFromApi.LogManager);
+ IReadOnlyTxProcessingScope scope = producerEnv.Build(Keccak.EmptyTreeHash);
+
BlockProcessor producerProcessor = new(
getFromApi!.SpecProvider,
getFromApi!.BlockValidator,
NoBlockRewards.Instance,
- new BlockProcessor.BlockProductionTransactionsExecutor(producerEnv, getFromApi!.SpecProvider, getFromApi.LogManager),
- producerEnv.StateProvider,
+ new BlockProcessor.BlockProductionTransactionsExecutor(scope, getFromApi!.SpecProvider, getFromApi.LogManager),
+ scope.WorldState,
NullReceiptStorage.Instance,
- NullWitnessCollector.Instance,
- new BlockhashStore(getFromApi.BlockTree, getFromApi.SpecProvider, producerEnv.StateProvider),
+ new BlockhashStore(getFromApi.BlockTree, getFromApi.SpecProvider, scope.WorldState),
getFromApi.TransactionProcessor,
getFromApi.LogManager);
@@ -90,35 +93,29 @@ public Task InitBlockProducer(IBlockProductionTrigger? blockProd
getFromApi.LogManager,
BlockchainProcessor.Options.NoReceipts);
- DefaultBlockProductionTrigger = new BuildBlocksRegularly(TimeSpan.FromMilliseconds(200))
- .IfPoolIsNotEmpty(getFromApi.TxPool)
- .Or(getFromApi.ManualBlockProductionTrigger);
-
IBlockProducer blockProducer = new DevBlockProducer(
additionalTxSource.Then(txPoolTxSource).ServeTxsOneByOne(),
producerChainProcessor,
- producerEnv.StateProvider,
+ scope.WorldState,
getFromApi.BlockTree,
- blockProductionTrigger ?? DefaultBlockProductionTrigger,
getFromApi.Timestamper,
getFromApi.SpecProvider,
getFromApi.Config(),
getFromApi.LogManager);
- return Task.FromResult(blockProducer);
+ return blockProducer;
}
public string SealEngineType => Nethermind.Core.SealEngineType.NethDev;
- public IBlockProductionTrigger DefaultBlockProductionTrigger { get; private set; }
-
- public Task InitNetworkProtocol()
- {
- return Task.CompletedTask;
- }
-
- public Task InitRpcModules()
+ public IBlockProducerRunner CreateBlockProducerRunner()
{
- return Task.CompletedTask;
+ IBlockProductionTrigger trigger = new BuildBlocksRegularly(TimeSpan.FromMilliseconds(200))
+ .IfPoolIsNotEmpty(_nethermindApi.TxPool)
+ .Or(_nethermindApi.ManualBlockProductionTrigger);
+ return new StandardBlockProducerRunner(
+ trigger,
+ _nethermindApi.BlockTree,
+ _nethermindApi.BlockProducer!);
}
}
}
diff --git a/src/Nethermind/Nethermind.Consensus.Test/ReadOnlyTxProcessingScopeTests.cs b/src/Nethermind/Nethermind.Consensus.Test/ReadOnlyTxProcessingScopeTests.cs
new file mode 100644
index 00000000000..399523f0e56
--- /dev/null
+++ b/src/Nethermind/Nethermind.Consensus.Test/ReadOnlyTxProcessingScopeTests.cs
@@ -0,0 +1,28 @@
+// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using Nethermind.Consensus.Processing;
+using Nethermind.Core.Test.Builders;
+using Nethermind.Evm.TransactionProcessing;
+using Nethermind.State;
+using NSubstitute;
+using NUnit.Framework;
+
+namespace Nethermind.Consensus.Test;
+
+public class ReadOnlyTxProcessingScopeTests
+{
+ [Test]
+ public void Test_WhenDispose_ThenStateRootWillRevert()
+ {
+ ReadOnlyTxProcessingScope env = new ReadOnlyTxProcessingScope(
+ Substitute.For(),
+ Substitute.For(),
+ TestItem.KeccakB
+ );
+
+ env.Dispose();
+
+ env.WorldState.Received().StateRoot = TestItem.KeccakB;
+ }
+}
diff --git a/src/Nethermind/Nethermind.Consensus/IBlockProducer.cs b/src/Nethermind/Nethermind.Consensus/IBlockProducer.cs
index 2ad56e537c8..ff868005e66 100644
--- a/src/Nethermind/Nethermind.Consensus/IBlockProducer.cs
+++ b/src/Nethermind/Nethermind.Consensus/IBlockProducer.cs
@@ -1,16 +1,19 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
-using System;
+using System.Threading;
using System.Threading.Tasks;
+using Nethermind.Consensus.Producers;
using Nethermind.Core;
+using Nethermind.Evm.Tracing;
namespace Nethermind.Consensus;
public interface IBlockProducer
{
- Task Start();
- Task StopAsync();
- bool IsProducingBlocks(ulong? maxProducingInterval);
- event EventHandler BlockProduced;
+ Task BuildBlock(
+ BlockHeader? parentHeader = null,
+ IBlockTracer? blockTracer = null,
+ PayloadAttributes? payloadAttributes = null,
+ CancellationToken? cancellationToken = null);
}
diff --git a/src/Nethermind/Nethermind.Consensus/IBlockProducerFactory.cs b/src/Nethermind/Nethermind.Consensus/IBlockProducerFactory.cs
index 9897ba185d7..46735b2501a 100644
--- a/src/Nethermind/Nethermind.Consensus/IBlockProducerFactory.cs
+++ b/src/Nethermind/Nethermind.Consensus/IBlockProducerFactory.cs
@@ -12,12 +12,9 @@ public interface IBlockProducerFactory
///
/// Creates a block producer.
///
- /// Optional parameter. If present this should be the only block production trigger for created block producer. If absent should be used.
/// Optional parameter. If present this transaction source should be used before any other transaction sources, except consensus ones. Plugin still should use their own transaction sources.
///
/// Can be called many times, with different parameters, each time should create a new instance. Example usage in MEV plugin.
///
- Task InitBlockProducer(
- IBlockProductionTrigger blockProductionTrigger,
- ITxSource? additionalTxSource = null);
+ IBlockProducer InitBlockProducer(ITxSource? additionalTxSource = null);
}
diff --git a/src/Nethermind/Nethermind.Consensus/IBlockProducerRunner.cs b/src/Nethermind/Nethermind.Consensus/IBlockProducerRunner.cs
new file mode 100644
index 00000000000..e2a1992bb63
--- /dev/null
+++ b/src/Nethermind/Nethermind.Consensus/IBlockProducerRunner.cs
@@ -0,0 +1,16 @@
+// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Threading.Tasks;
+using Nethermind.Core;
+
+namespace Nethermind.Consensus;
+
+public interface IBlockProducerRunner
+{
+ void Start();
+ Task StopAsync();
+ bool IsProducingBlocks(ulong? maxProducingInterval);
+ event EventHandler BlockProduced;
+}
diff --git a/src/Nethermind/Nethermind.Consensus/IHeaderSigner.cs b/src/Nethermind/Nethermind.Consensus/IHeaderSigner.cs
new file mode 100644
index 00000000000..a51b1ca800a
--- /dev/null
+++ b/src/Nethermind/Nethermind.Consensus/IHeaderSigner.cs
@@ -0,0 +1,12 @@
+// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using Nethermind.Core;
+using Nethermind.Core.Crypto;
+
+namespace Nethermind.Consensus;
+public interface IHeaderSigner : ISigner
+{
+ bool CanSignHeader { get; }
+ Signature Sign(BlockHeader header);
+}
diff --git a/src/Nethermind/Nethermind.Consensus/IMiningConfig.cs b/src/Nethermind/Nethermind.Consensus/IMiningConfig.cs
index 9881cf09b8f..4562ab03327 100644
--- a/src/Nethermind/Nethermind.Consensus/IMiningConfig.cs
+++ b/src/Nethermind/Nethermind.Consensus/IMiningConfig.cs
@@ -52,4 +52,9 @@ public interface IMiningConfig : IConfig
[ConfigItem(HiddenFromDocs = true, DisabledForCli = true, DefaultValue = "null")]
IBlocksConfig? BlocksConfig { get; }
+ [ConfigItem(
+ Description = "Url for an external signer like clef: https://github.com/ethereum/go-ethereum/blob/master/cmd/clef/tutorial.md",
+ HiddenFromDocs = false,
+ DefaultValue = "null")]
+ string Signer { get; set; }
}
diff --git a/src/Nethermind/Nethermind.Consensus/ISigner.cs b/src/Nethermind/Nethermind.Consensus/ISigner.cs
index 1174e68a1d0..ec34eafa187 100644
--- a/src/Nethermind/Nethermind.Consensus/ISigner.cs
+++ b/src/Nethermind/Nethermind.Consensus/ISigner.cs
@@ -5,6 +5,7 @@
using Nethermind.Core.Crypto;
using Nethermind.Crypto;
using Nethermind.TxPool;
+using System;
namespace Nethermind.Consensus
{
diff --git a/src/Nethermind/Nethermind.Consensus/MiningConfig.cs b/src/Nethermind/Nethermind.Consensus/MiningConfig.cs
index b3abd0b054e..dbf2398286a 100644
--- a/src/Nethermind/Nethermind.Consensus/MiningConfig.cs
+++ b/src/Nethermind/Nethermind.Consensus/MiningConfig.cs
@@ -70,4 +70,6 @@ public IBlocksConfig? BlocksConfig
return _blocksConfig;
}
}
+
+ public string Signer { get; set; }
}
diff --git a/src/Nethermind/Nethermind.Consensus/NullSigner.cs b/src/Nethermind/Nethermind.Consensus/NullSigner.cs
index a6028d49dec..f4976cac687 100644
--- a/src/Nethermind/Nethermind.Consensus/NullSigner.cs
+++ b/src/Nethermind/Nethermind.Consensus/NullSigner.cs
@@ -22,8 +22,12 @@ public class NullSigner : ISigner, ISignerStore
public PrivateKey? Key { get; } = null;
+ public bool CanSignHeader => false;
+
public void SetSigner(PrivateKey key) { }
public void SetSigner(ProtectedPrivateKey key) { }
+
+ public Signature Sign(BlockHeader header) { return new(new byte[65]); }
}
}
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs
new file mode 100644
index 00000000000..93f3e7a556c
--- /dev/null
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs
@@ -0,0 +1,137 @@
+// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.ObjectPool;
+using Nethermind.Core;
+using Nethermind.Core.Crypto;
+using Nethermind.Core.Specs;
+using Nethermind.Core.Threading;
+using Nethermind.Core.Cpu;
+using Nethermind.Evm;
+using Nethermind.Evm.Tracing;
+using Nethermind.Evm.TransactionProcessing;
+using Nethermind.Logging;
+using Nethermind.State;
+
+namespace Nethermind.Consensus.Processing;
+
+public class BlockCachePreWarmer(ReadOnlyTxProcessingEnvFactory envFactory, ISpecProvider specProvider, ILogManager logManager, IWorldState? targetWorldState = null) : IBlockCachePreWarmer
+{
+ private readonly ObjectPool _envPool = new DefaultObjectPool(new ReadOnlyTxProcessingEnvPooledObjectPolicy(envFactory), Environment.ProcessorCount);
+ private readonly ObjectPool _systemTransactionPool = new DefaultObjectPool(new DefaultPooledObjectPolicy(), Environment.ProcessorCount);
+ private readonly ILogger _logger = logManager.GetClassLogger();
+
+ public Task PreWarmCaches(Block suggestedBlock, Hash256? parentStateRoot, CancellationToken cancellationToken = default)
+ {
+ if (targetWorldState is not null)
+ {
+ if (targetWorldState.ClearCache())
+ {
+ if (_logger.IsWarn) _logger.Warn("Cashes are not empty. Clearing them.");
+ }
+
+ if (!IsGenesisBlock(parentStateRoot) && Environment.ProcessorCount > 2 && !cancellationToken.IsCancellationRequested)
+ {
+ // Do not pass cancellation token to the task, we don't want exceptions to be thrown in main processing thread
+ return Task.Run(() => PreWarmCachesParallel(suggestedBlock, parentStateRoot, cancellationToken));
+ }
+ }
+
+ return Task.CompletedTask;
+ }
+
+ // Parent state root is null for genesis block
+ private bool IsGenesisBlock(Hash256? parentStateRoot) => parentStateRoot is null;
+
+ public void ClearCaches() => targetWorldState?.ClearCache();
+
+ private void PreWarmCachesParallel(Block suggestedBlock, Hash256 parentStateRoot, CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested) return;
+
+ try
+ {
+ ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = Math.Max(1, RuntimeInformation.PhysicalCoreCount - 2), CancellationToken = cancellationToken };
+ IReleaseSpec spec = specProvider.GetSpec(suggestedBlock.Header);
+
+ WarmupTransactions(parallelOptions, spec, suggestedBlock, parentStateRoot);
+ WarmupWithdrawals(parallelOptions, spec, suggestedBlock, parentStateRoot);
+
+ if (_logger.IsDebug) _logger.Debug($"Finished pre-warming caches for block {suggestedBlock.Number}.");
+ }
+ catch (OperationCanceledException)
+ {
+ if (_logger.IsDebug) _logger.Debug($"Pre-warming caches cancelled for block {suggestedBlock.Number}.");
+ }
+
+ void WarmupWithdrawals(ParallelOptions parallelOptions, IReleaseSpec spec, Block block, Hash256 stateRoot)
+ {
+ if (parallelOptions.CancellationToken.IsCancellationRequested) return;
+ if (spec.WithdrawalsEnabled && block.Withdrawals is not null)
+ {
+ Parallel.For(0, block.Withdrawals.Length, parallelOptions,
+ i =>
+ {
+ IReadOnlyTxProcessorSource env = _envPool.Get();
+ using IReadOnlyTxProcessingScope scope = env.Build(stateRoot);
+ try
+ {
+ scope.WorldState.WarmUp(block.Withdrawals[i].Address);
+ }
+ catch (Exception ex)
+ {
+ if (_logger.IsDebug) _logger.Error($"Error pre-warming withdrawal {i}", ex);
+ }
+ finally
+ {
+ _envPool.Return(env);
+ }
+ });
+ }
+ }
+
+ void WarmupTransactions(ParallelOptions parallelOptions, IReleaseSpec spec, Block block, Hash256 stateRoot)
+ {
+ if (parallelOptions.CancellationToken.IsCancellationRequested) return;
+ Parallel.For(0, block.Transactions.Length, parallelOptions, i =>
+ {
+ // If the transaction has already been processed or being processed, exit early
+ if (block.TransactionProcessed >= i) return;
+
+ using ThreadExtensions.Disposable handle = Thread.CurrentThread.BoostPriority();
+ Transaction tx = block.Transactions[i];
+ IReadOnlyTxProcessorSource env = _envPool.Get();
+ SystemTransaction systemTransaction = _systemTransactionPool.Get();
+ try
+ {
+ tx.CopyTo(systemTransaction);
+ using IReadOnlyTxProcessingScope scope = env.Build(stateRoot);
+ if (spec.UseTxAccessLists)
+ {
+ scope.WorldState.WarmUp(tx.AccessList); // eip-2930
+ }
+ TransactionResult result = scope.TransactionProcessor.Trace(systemTransaction, new BlockExecutionContext(block.Header.Clone()), NullTxTracer.Instance);
+ if (_logger.IsTrace) _logger.Trace($"Finished pre-warming cache for tx {tx.Hash} with {result}");
+ }
+ catch (Exception ex)
+ {
+ if (_logger.IsDebug) _logger.Error($"Error pre-warming cache {tx.Hash}", ex);
+ }
+ finally
+ {
+ _systemTransactionPool.Return(systemTransaction);
+ _envPool.Return(env);
+ }
+ });
+ }
+ }
+
+ private class ReadOnlyTxProcessingEnvPooledObjectPolicy(ReadOnlyTxProcessingEnvFactory envFactory) : IPooledObjectPolicy
+ {
+ public IReadOnlyTxProcessorSource Create() => envFactory.Create();
+ public bool Return(IReadOnlyTxProcessorSource obj) => true;
+ }
+}
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionPicker.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionPicker.cs
index 10aa4a3a9e2..e5c1c8d1543 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionPicker.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionPicker.cs
@@ -16,10 +16,12 @@ public partial class BlockProcessor
public class BlockProductionTransactionPicker : IBlockProductionTransactionPicker
{
protected readonly ISpecProvider _specProvider;
+ private readonly bool _ignoreEip3607;
- public BlockProductionTransactionPicker(ISpecProvider specProvider)
+ public BlockProductionTransactionPicker(ISpecProvider specProvider, bool ignoreEip3607 = false)
{
_specProvider = specProvider;
+ _ignoreEip3607 = ignoreEip3607;
}
public event EventHandler? AddingTransaction;
@@ -63,7 +65,7 @@ public virtual AddingTxEventArgs CanAddTransaction(Block block, Transaction curr
return args.Set(TxAction.Skip, $"EIP-3860 - transaction size over max init code size");
}
- if (stateProvider.IsInvalidContractSender(spec, currentTx.SenderAddress))
+ if (!_ignoreEip3607 && stateProvider.IsInvalidContractSender(spec, currentTx.SenderAddress))
{
return args.Set(TxAction.Skip, $"Sender is contract");
}
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionsExecutor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionsExecutor.cs
index 161dd665971..bd8740c7c2f 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionsExecutor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionsExecutor.cs
@@ -26,12 +26,12 @@ public class BlockProductionTransactionsExecutor : IBlockProductionTransactionsE
private readonly ILogger _logger;
public BlockProductionTransactionsExecutor(
- ReadOnlyTxProcessingEnv readOnlyTxProcessingEnv,
+ IReadOnlyTxProcessingScope readOnlyTxProcessingEnv,
ISpecProvider specProvider,
ILogManager logManager)
: this(
readOnlyTxProcessingEnv.TransactionProcessor,
- readOnlyTxProcessingEnv.StateProvider,
+ readOnlyTxProcessingEnv.WorldState,
specProvider,
logManager)
{
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs
index e2e7eb42592..d487cda83fa 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs
@@ -42,13 +42,14 @@ public TxReceipt[] ProcessTransactions(Block block, ProcessingOptions processing
BlockExecutionContext blkCtx = new(block.Header);
for (int i = 0; i < block.Transactions.Length; i++)
{
+ block.TransactionProcessed = i;
Transaction currentTx = block.Transactions[i];
ProcessTransaction(in blkCtx, currentTx, i, receiptsTracer, processingOptions);
}
return receiptsTracer.TxReceipts.ToArray();
}
- private void ProcessTransaction(in BlockExecutionContext blkCtx, Transaction currentTx, int index, BlockReceiptsTracer receiptsTracer, ProcessingOptions processingOptions)
+ protected virtual void ProcessTransaction(in BlockExecutionContext blkCtx, Transaction currentTx, int index, BlockReceiptsTracer receiptsTracer, ProcessingOptions processingOptions)
{
TransactionResult result = _transactionProcessor.ProcessTransaction(in blkCtx, currentTx, receiptsTracer, processingOptions, _stateProvider);
if (!result) ThrowInvalidBlockException(result, blkCtx.Header, currentTx, index);
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
index 1c7d85000ee..7614f95188b 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
@@ -2,10 +2,12 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Threading;
+using System.Threading.Tasks;
using Nethermind.Blockchain;
using Nethermind.Blockchain.BeaconBlockRoot;
using Nethermind.Blockchain.Blocks;
@@ -37,7 +39,6 @@ public partial class BlockProcessor : IBlockProcessor
protected readonly IWorldState _stateProvider;
private readonly IReceiptStorage _receiptStorage;
private readonly IReceiptsRootCalculator _receiptsRootCalculator;
- private readonly IWitnessCollector _witnessCollector;
private readonly IWithdrawalProcessor _withdrawalProcessor;
private readonly IBeaconBlockRootHandler _beaconBlockRootHandler;
private readonly IBlockValidator _blockValidator;
@@ -46,6 +47,7 @@ public partial class BlockProcessor : IBlockProcessor
private readonly IConsensusRequestsProcessor _consensusRequestsProcessor;
private readonly IBlockhashStore _blockhashStore;
+ private readonly IBlockCachePreWarmer? _preWarmer;
private const int MaxUncommittedBlocks = 64;
///
@@ -61,13 +63,13 @@ public BlockProcessor(
IBlockProcessor.IBlockTransactionsExecutor? blockTransactionsExecutor,
IWorldState? stateProvider,
IReceiptStorage? receiptStorage,
- IWitnessCollector? witnessCollector,
IBlockhashStore? blockHashStore,
ITransactionProcessor transactionProcessor,
ILogManager? logManager,
IWithdrawalProcessor? withdrawalProcessor = null,
IBeaconBlockRootHandler? beaconBlockRootHandler = null,
IReceiptsRootCalculator? receiptsRootCalculator = null,
+ IBlockCachePreWarmer? preWarmer = null,
IConsensusRequestsProcessor? consensusRequestsProcessor = null)
{
_logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager));
@@ -75,7 +77,6 @@ public BlockProcessor(
_blockValidator = blockValidator ?? throw new ArgumentNullException(nameof(blockValidator));
_stateProvider = stateProvider ?? throw new ArgumentNullException(nameof(stateProvider));
_receiptStorage = receiptStorage ?? throw new ArgumentNullException(nameof(receiptStorage));
- _witnessCollector = witnessCollector ?? throw new ArgumentNullException(nameof(witnessCollector));
_withdrawalProcessor = withdrawalProcessor ?? new WithdrawalProcessor(stateProvider, logManager);
_rewardCalculator = rewardCalculator ?? throw new ArgumentNullException(nameof(rewardCalculator));
_blockTransactionsExecutor = blockTransactionsExecutor ?? throw new ArgumentNullException(nameof(blockTransactionsExecutor));
@@ -84,10 +85,11 @@ public BlockProcessor(
_consensusRequestsProcessor = consensusRequestsProcessor ?? new ConsensusRequestsProcessor(transactionProcessor);
_blockhashStore = blockHashStore ?? throw new ArgumentNullException(nameof(blockHashStore));
+ _preWarmer = preWarmer;
ReceiptsTracer = new BlockReceiptsTracer();
}
- public event EventHandler BlockProcessed;
+ public event EventHandler? BlockProcessed;
public event EventHandler TransactionProcessed
{
@@ -108,30 +110,34 @@ public Block[] Process(Hash256 newBranchStateRoot, List suggestedBlocks,
the previous head state.*/
Hash256 previousBranchStateRoot = CreateCheckpoint();
InitBranch(newBranchStateRoot);
+ Hash256 preBlockStateRoot = newBranchStateRoot;
bool notReadOnly = !options.ContainsFlag(ProcessingOptions.ReadOnlyChain);
int blocksCount = suggestedBlocks.Count;
Block[] processedBlocks = new Block[blocksCount];
- using IDisposable tracker = _witnessCollector.TrackOnThisThread();
try
{
for (int i = 0; i < blocksCount; i++)
{
+ Block suggestedBlock = suggestedBlocks[i];
if (blocksCount > 64 && i % 8 == 0)
{
- if (_logger.IsInfo) _logger.Info($"Processing part of a long blocks branch {i}/{blocksCount}. Block: {suggestedBlocks[i]}");
+ if (_logger.IsInfo) _logger.Info($"Processing part of a long blocks branch {i}/{blocksCount}. Block: {suggestedBlock}");
}
- _witnessCollector.Reset();
- (Block processedBlock, TxReceipt[] receipts) = ProcessOne(suggestedBlocks[i], options, blockTracer);
+ using CancellationTokenSource cancellationTokenSource = new();
+ Task? preWarmTask = suggestedBlock.Transactions.Length < 3 ?
+ null :
+ _preWarmer?.PreWarmCaches(suggestedBlock, preBlockStateRoot!, cancellationTokenSource.Token);
+ (Block processedBlock, TxReceipt[] receipts) = ProcessOne(suggestedBlock, options, blockTracer);
+ cancellationTokenSource.Cancel();
+ preWarmTask?.GetAwaiter().GetResult();
processedBlocks[i] = processedBlock;
// be cautious here as AuRa depends on processing
- PreCommitBlock(newBranchStateRoot, suggestedBlocks[i].Number);
-
+ PreCommitBlock(newBranchStateRoot, suggestedBlock.Number);
if (notReadOnly)
{
- _witnessCollector.Persist(processedBlock.Hash!);
BlockProcessed?.Invoke(this, new BlockProcessedEventArgs(processedBlock, receipts));
}
@@ -144,9 +150,12 @@ the previous head state.*/
{
if (_logger.IsInfo) _logger.Info($"Commit part of a long blocks branch {i}/{blocksCount}");
previousBranchStateRoot = CreateCheckpoint();
- Hash256? newStateRoot = suggestedBlocks[i].StateRoot;
+ Hash256? newStateRoot = suggestedBlock.StateRoot;
InitBranch(newStateRoot, false);
}
+
+ preBlockStateRoot = processedBlock.StateRoot;
+ _stateProvider.Reset(resizeCollections: true);
}
if (options.ContainsFlag(ProcessingOptions.DoNotUpdateHead))
@@ -160,6 +169,7 @@ the previous head state.*/
{
_logger.Trace($"Encountered exception {ex} while processing blocks.");
RestoreBranch(previousBranchStateRoot);
+ _preWarmer?.ClearCaches();
throw;
}
}
@@ -232,6 +242,9 @@ private void ValidateProcessedBlock(Block suggestedBlock, ProcessingOptions opti
if (_logger.IsWarn) _logger.Warn($"Suggested block TD: {suggestedBlock.TotalDifficulty}, Suggested block IsPostMerge {suggestedBlock.IsPostMerge}, Block TD: {block.TotalDifficulty}, Block IsPostMerge {block.IsPostMerge}");
throw new InvalidBlockException(suggestedBlock, error);
}
+
+ // Block is valid, copy the account changes as we use the suggested block not the processed one
+ suggestedBlock.AccountChanges = block.AccountChanges;
}
private bool ShouldComputeStateRoot(BlockHeader header) =>
@@ -251,7 +264,7 @@ protected virtual TxReceipt[] ProcessBlock(
_beaconBlockRootHandler.ExecuteSystemCall(block, spec);
_blockhashStore.ApplyHistoryBlockHashes(block.Header);
- _stateProvider.Commit(spec);
+ _stateProvider.Commit(spec, commitStorageRoots: false);
TxReceipt[] receipts = _blockTransactionsExecutor.ProcessTransactions(block, options, ReceiptsTracer, spec);
@@ -267,7 +280,13 @@ protected virtual TxReceipt[] ProcessBlock(
ReceiptsTracer.EndBlockTrace();
- _stateProvider.Commit(spec);
+ _stateProvider.Commit(spec, commitStorageRoots: true);
+
+ if (BlockchainProcessor.IsMainProcessingThread)
+ {
+ // Get the accounts that have been changed
+ block.AccountChanges = _stateProvider.GetAccountChanges();
+ }
if (ShouldComputeStateRoot(block.Header))
{
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs
index 97249d25a39..c3cfb0b7234 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs
@@ -430,7 +430,9 @@ private void FireProcessingQueueEmpty()
if (!readonlyChain)
{
- _stats.UpdateStats(lastProcessed, _blockTree, _recoveryQueue.Count, _blockQueue.Count, _stopwatch.ElapsedMicroseconds());
+ Metrics.RecoveryQueueSize = _recoveryQueue.Count;
+ Metrics.ProcessingQueueSize = _blockQueue.Count;
+ _stats.UpdateStats(lastProcessed, _blockTree, _stopwatch.ElapsedMicroseconds());
}
return lastProcessed;
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/IBlockCachePreWarmer.cs b/src/Nethermind/Nethermind.Consensus/Processing/IBlockCachePreWarmer.cs
new file mode 100644
index 00000000000..609e802d44c
--- /dev/null
+++ b/src/Nethermind/Nethermind.Consensus/Processing/IBlockCachePreWarmer.cs
@@ -0,0 +1,15 @@
+// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System.Threading;
+using System.Threading.Tasks;
+using Nethermind.Core;
+using Nethermind.Core.Crypto;
+
+namespace Nethermind.Consensus.Processing;
+
+public interface IBlockCachePreWarmer
+{
+ Task PreWarmCaches(Block suggestedBlock, Hash256 parentStateRoot, CancellationToken cancellationToken = default);
+ void ClearCaches();
+}
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/IBlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/IBlockProcessor.cs
index ceb8da16d7c..88aba737926 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/IBlockProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/IBlockProcessor.cs
@@ -18,9 +18,7 @@ public interface IBlockProcessor
/// Initial state for the processed branch.
/// List of blocks to be processed.
/// Options to use for processor and transaction processor.
- ///
- /// Block tracer to use. By default either or
- ///
+ /// Block tracer to use. By default either or
/// List of processed blocks.
Block[] Process(
Hash256 newBranchStateRoot,
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ProcessingStats.cs b/src/Nethermind/Nethermind.Consensus/Processing/ProcessingStats.cs
index 7ef3faaecb1..d44884f538b 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/ProcessingStats.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/ProcessingStats.cs
@@ -2,8 +2,8 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System;
-using System.Collections.Generic;
using System.Diagnostics;
+using System.Threading;
using Nethermind.Blockchain;
using Nethermind.Core;
using Nethermind.Core.Extensions;
@@ -13,7 +13,7 @@
namespace Nethermind.Consensus.Processing
{
//TODO Consult on disabling of such metrics from configuration
- internal class ProcessingStats
+ internal class ProcessingStats : IThreadPoolWorkItem
{
private readonly ILogger _logger;
private readonly Stopwatch _processingStopwatch = new();
@@ -26,19 +26,25 @@ internal class ProcessingStats
private long _lastTotalEmptyCalls;
private long _lastTotalSLoad;
private long _lastTotalSStore;
- private long _lastStateDbReads;
- private long _lastStateDbWrites;
- private long _lastGen0;
- private long _lastGen1;
- private long _lastGen2;
- private long _lastTreeNodeRlp;
- private long _lastEvmExceptions;
private long _lastSelfDestructs;
- private long _maxMemory;
private long _totalBlocks;
- private long _processingMicroseconds;
+ private long _chunkProcessingMicroseconds;
private long _lastTotalCreates;
private long _lastReportMs;
+ private long _lastContractsAnalysed;
+ private long _lastCachedContractsUsed;
+ private long _blockProcessingMicroseconds;
+ private long _runningMicroseconds;
+ private long _runMicroseconds;
+ private long _reportMs;
+ private Block? _lastBlock;
+ private long _sloadOpcodeProcessing;
+ private long _sstoreOpcodeProcessing;
+ private long _callsProcessing;
+ private long _emptyCallsProcessing;
+ private long _codeDbCacheProcessing;
+ private long _contractAnalysedProcessing;
+ private long _createsProcessing;
public ProcessingStats(ILogger logger)
{
@@ -51,19 +57,8 @@ public ProcessingStats(ILogger logger)
#endif
}
- public void UpdateStats(Block? block, IBlockTree blockTreeCtx, int recoveryQueueSize, int blockQueueSize, long blockProcessingTimeInMicros)
+ public void UpdateStats(Block? block, IBlockTree blockTreeCtx, long blockProcessingTimeInMicros)
{
- const string resetColor = "\u001b[37m";
- const string whiteText = "\u001b[97m";
- const string yellowText = "\u001b[93m";
- const string orangeText = "\u001b[38;5;208m";
- const string redText = "\u001b[38;5;196m";
- const string greenText = "\u001b[92m";
- const string darkGreenText = "\u001b[32m";
- const string darkCyanText = "\u001b[36m";
- const string blueText = "\u001b[94m";
- const string darkGreyText = resetColor; // "\u001b[90m";
-
if (block is null)
{
return;
@@ -76,7 +71,7 @@ public void UpdateStats(Block? block, IBlockTree blockTreeCtx, int recoveryQueue
_lastBlockNumber = block.Number;
}
- _processingMicroseconds += blockProcessingTimeInMicros;
+ _chunkProcessingMicroseconds += blockProcessingTimeInMicros;
Metrics.Mgas += block.GasUsed / 1_000_000.0;
Metrics.Transactions += block.Transactions.Length;
@@ -85,161 +80,192 @@ public void UpdateStats(Block? block, IBlockTree blockTreeCtx, int recoveryQueue
Metrics.LastDifficulty = block.Difficulty;
Metrics.GasUsed = block.GasUsed;
Metrics.GasLimit = block.GasLimit;
- Metrics.RecoveryQueueSize = recoveryQueueSize;
- Metrics.ProcessingQueueSize = blockQueueSize;
Metrics.BlockchainHeight = block.Header.Number;
Metrics.BestKnownBlockNumber = blockTreeCtx.BestKnownNumber;
- long processingMicroseconds = _processingStopwatch.ElapsedMicroseconds();
- long runningMicroseconds = _runStopwatch.ElapsedMicroseconds();
- long runMicroseconds = (runningMicroseconds - _lastElapsedRunningMicroseconds);
+ _blockProcessingMicroseconds = _processingStopwatch.ElapsedMicroseconds();
+ _runningMicroseconds = _runStopwatch.ElapsedMicroseconds();
+ _runMicroseconds = (_runningMicroseconds - _lastElapsedRunningMicroseconds);
- long reportMs = Environment.TickCount64;
+ long reportMs = _reportMs = Environment.TickCount64;
if (reportMs - _lastReportMs > 1000)
{
- long currentStateDbReads = Db.Metrics.DbReads.GetValueOrDefault("StateDb");
- long currentStateDbWrites = Db.Metrics.DbWrites.GetValueOrDefault("StateDb");
- long currentTreeNodeRlp = Trie.Metrics.TreeNodeRlpEncodings + Trie.Metrics.TreeNodeRlpDecodings;
- long evmExceptions = Evm.Metrics.EvmExceptions;
- long currentSelfDestructs = Evm.Metrics.SelfDestructs;
+ _lastReportMs = _reportMs;
+ _lastBlock = block;
+ _sloadOpcodeProcessing = Evm.Metrics.ThreadLocalSLoadOpcode;
+ _sstoreOpcodeProcessing = Evm.Metrics.ThreadLocalSStoreOpcode;
+ _callsProcessing = Evm.Metrics.ThreadLocalCalls;
+ _emptyCallsProcessing = Evm.Metrics.ThreadLocalEmptyCalls;
+ _codeDbCacheProcessing = Db.Metrics.ThreadLocalCodeDbCache;
+ _contractAnalysedProcessing = Evm.Metrics.ThreadLocalContractsAnalysed;
+ _createsProcessing = Evm.Metrics.ThreadLocalCreates;
+ GenerateReport();
+ }
+ }
- long chunkBlocks = Metrics.Blocks - _lastBlockNumber;
- _totalBlocks += chunkBlocks;
+ private void GenerateReport() => ThreadPool.UnsafeQueueUserWorkItem(this, preferLocal: false);
- if (_logger.IsInfo)
- {
- double chunkMicroseconds = _processingMicroseconds;
- double totalMicroseconds = processingMicroseconds;
- long chunkTx = Metrics.Transactions - _lastTotalTx;
- long chunkCalls = Evm.Metrics.Calls - _lastTotalCalls;
- long chunkEmptyCalls = Evm.Metrics.EmptyCalls - _lastTotalEmptyCalls;
- long chunkCreates = Evm.Metrics.Creates - _lastTotalCreates;
- long chunkSload = Evm.Metrics.SloadOpcode - _lastTotalSLoad;
- long chunkSstore = Evm.Metrics.SstoreOpcode - _lastTotalSStore;
- double chunkMGas = Metrics.Mgas - _lastTotalMGas;
- double mgasPerSecond = chunkMicroseconds == 0 ? -1 : chunkMGas / chunkMicroseconds * 1_000_000.0;
- double totalMgasPerSecond = totalMicroseconds == 0 ? -1 : Metrics.Mgas / totalMicroseconds * 1_000_000.0;
- double totalTxPerSecond = totalMicroseconds == 0 ? -1 : Metrics.Transactions / totalMicroseconds * 1_000_000.0;
- double totalBlocksPerSecond = totalMicroseconds == 0 ? -1 : _totalBlocks / totalMicroseconds * 1_000_000.0;
- double txps = chunkMicroseconds == 0 ? -1 : chunkTx / chunkMicroseconds * 1_000_000.0;
- double bps = chunkMicroseconds == 0 ? -1 : chunkBlocks / chunkMicroseconds * 1_000_000.0;
- double chunkMs = (chunkMicroseconds == 0 ? -1 : chunkMicroseconds / 1000.0);
- double runMs = (runMicroseconds == 0 ? -1 : runMicroseconds / 1000.0);
- string blockGas = Evm.Metrics.BlockMinGasPrice != float.MaxValue ? $"⛽ Gas gwei: {Evm.Metrics.BlockMinGasPrice:N2} .. {whiteText}{Math.Max(Evm.Metrics.BlockMinGasPrice, Evm.Metrics.BlockEstMedianGasPrice):N2}{resetColor} ({Evm.Metrics.BlockAveGasPrice:N2}) .. {Evm.Metrics.BlockMaxGasPrice:N2}" : "";
- string mgasColor = whiteText;
+ void IThreadPoolWorkItem.Execute()
+ {
+ const string resetColor = "\u001b[37m";
+ const string whiteText = "\u001b[97m";
+ const string yellowText = "\u001b[93m";
+ const string orangeText = "\u001b[38;5;208m";
+ const string redText = "\u001b[38;5;196m";
+ const string greenText = "\u001b[92m";
+ const string darkGreenText = "\u001b[32m";
+ const string darkCyanText = "\u001b[36m";
+ const string blueText = "\u001b[94m";
+ const string darkGreyText = resetColor; // "\u001b[90m";
+
+ long currentSelfDestructs = Evm.Metrics.SelfDestructs;
+
+ long chunkBlocks = Metrics.Blocks - _lastBlockNumber;
+ _totalBlocks += chunkBlocks;
+
+ double chunkMicroseconds = _chunkProcessingMicroseconds;
+ double chunkMGas = Metrics.Mgas - _lastTotalMGas;
+ double mgasPerSecond;
+ if (chunkMicroseconds == 0)
+ {
+ mgasPerSecond = -1;
+ }
+ else
+ {
+ mgasPerSecond = chunkMGas / chunkMicroseconds * 1_000_000.0;
+ if (chunkMGas != 0)
+ {
Metrics.MgasPerSec = mgasPerSecond;
+ }
+ }
- if (chunkBlocks > 1)
- {
- _logger.Info($"Processed {block.Number - chunkBlocks + 1,9}...{block.Number,9} | {chunkMs,9:N2} ms | slot {runMs,7:N0} ms |{blockGas}");
- }
- else
- {
- mgasColor = (chunkMGas / (block.GasLimit / 16_000_000.0)) switch
- {
- // At 30M gas limit the values are in comments
- > 15 => redText, // 28.125 MGas
- > 14 => orangeText, // 26.25 MGas
- > 13 => yellowText, // 24.375 MGas
- > 10 => darkGreenText, // 18.75 MGas
- > 7 => greenText, // 13.125 MGas
- > 6 => darkGreenText, // 11.25 MGas
- > 5 => whiteText, // 9.375 MGas
- > 4 => resetColor, // 7.5 MGas
- > 3 => darkCyanText, // 5.625 MGas
- _ => blueText
- };
- var chunkColor = chunkMs switch
- {
- < 200 => greenText,
- < 300 => darkGreenText,
- < 500 => whiteText,
- < 1000 => yellowText,
- < 2000 => orangeText,
- _ => redText
- };
- _logger.Info($"Processed {block.Number,9} | {chunkColor}{chunkMs,9:N2}{resetColor} ms | slot {runMs,7:N0} ms |{blockGas}");
- }
-
- string mgasPerSecondColor = (mgasPerSecond / (block.GasLimit / 1_000_000.0)) switch
+ Block? block = Interlocked.Exchange(ref _lastBlock, null);
+ if (block is not null && _logger.IsInfo)
+ {
+ double totalMicroseconds = _blockProcessingMicroseconds;
+ long chunkTx = Metrics.Transactions - _lastTotalTx;
+ long chunkCalls = _callsProcessing - _lastTotalCalls;
+ long chunkEmptyCalls = _emptyCallsProcessing - _lastTotalEmptyCalls;
+ long chunkCreates = _createsProcessing - _lastTotalCreates;
+ long chunkSload = _sloadOpcodeProcessing - _lastTotalSLoad;
+ long chunkSstore = _sstoreOpcodeProcessing - _lastTotalSStore;
+ long contractsAnalysed = _contractAnalysedProcessing - _lastContractsAnalysed;
+ long cachedContractsUsed = _codeDbCacheProcessing - _lastCachedContractsUsed;
+ double totalMgasPerSecond = totalMicroseconds == 0 ? -1 : Metrics.Mgas / totalMicroseconds * 1_000_000.0;
+ double totalTxPerSecond = totalMicroseconds == 0 ? -1 : Metrics.Transactions / totalMicroseconds * 1_000_000.0;
+ double totalBlocksPerSecond = totalMicroseconds == 0 ? -1 : _totalBlocks / totalMicroseconds * 1_000_000.0;
+ double txps = chunkMicroseconds == 0 ? -1 : chunkTx / chunkMicroseconds * 1_000_000.0;
+ double bps = chunkMicroseconds == 0 ? -1 : chunkBlocks / chunkMicroseconds * 1_000_000.0;
+ double chunkMs = (chunkMicroseconds == 0 ? -1 : chunkMicroseconds / 1000.0);
+ double runMs = (_runMicroseconds == 0 ? -1 : _runMicroseconds / 1000.0);
+ string blockGas = Evm.Metrics.BlockMinGasPrice != float.MaxValue ? $"⛽ Gas gwei: {Evm.Metrics.BlockMinGasPrice:N2} .. {whiteText}{Math.Max(Evm.Metrics.BlockMinGasPrice, Evm.Metrics.BlockEstMedianGasPrice):N2}{resetColor} ({Evm.Metrics.BlockAveGasPrice:N2}) .. {Evm.Metrics.BlockMaxGasPrice:N2}" : "";
+ string mgasColor = whiteText;
+
+ if (chunkBlocks > 1)
+ {
+ _logger.Info($"Processed {block.Number - chunkBlocks + 1,10}...{block.Number,9} | {chunkMs,9:N2} ms | slot {runMs,7:N0} ms |{blockGas}");
+ }
+ else
+ {
+ mgasColor = (chunkMGas / (block.GasLimit / 16_000_000.0)) switch
{
// At 30M gas limit the values are in comments
- > 3 => greenText, // 90 MGas/s
- > 2.5f => darkGreenText, // 75 MGas/s
- > 2 => whiteText, // 60 MGas/s
- > 1.5f => resetColor, // 45 MGas/s
- > 1 => yellowText, // 30 MGas/s
- > 0.5f => orangeText, // 15 MGas/s
- _ => redText
- };
- var sstoreColor = chunkBlocks > 1 ? "" : chunkSstore switch
- {
- > 3500 => redText,
- > 2500 => orangeText,
- > 2000 => yellowText,
- > 1500 => whiteText,
- > 900 when chunkCalls > 900 => whiteText,
- _ => ""
- };
- var callsColor = chunkBlocks > 1 ? "" : chunkCalls switch
- {
- > 3500 => redText,
- > 2500 => orangeText,
- > 2000 => yellowText,
- > 1500 => whiteText,
- > 900 when chunkSstore > 900 => whiteText,
- _ => ""
+ > 15 => redText, // 28.125 MGas
+ > 14 => orangeText, // 26.25 MGas
+ > 13 => yellowText, // 24.375 MGas
+ > 10 => darkGreenText, // 18.75 MGas
+ > 7 => greenText, // 13.125 MGas
+ > 6 => darkGreenText, // 11.25 MGas
+ > 5 => whiteText, // 9.375 MGas
+ > 4 => resetColor, // 7.5 MGas
+ > 3 => darkCyanText, // 5.625 MGas
+ _ => blueText
};
- var createsColor = chunkBlocks > 1 ? "" : chunkCreates switch
+ var chunkColor = chunkMs switch
{
- > 300 => redText,
- > 200 => orangeText,
- > 150 => yellowText,
- > 75 => whiteText,
- _ => ""
+ < 200 => greenText,
+ < 300 => darkGreenText,
+ < 500 => whiteText,
+ < 1000 => yellowText,
+ < 2000 => orangeText,
+ _ => redText
};
- _logger.Info($"- Block{(chunkBlocks > 1 ? $"s {chunkBlocks,-9:N0}" : " ")}{(chunkBlocks == 1 ? mgasColor : "")} {chunkMGas,7:F2}{resetColor} MGas | {chunkTx,6:N0} txs | calls {callsColor}{chunkCalls,6:N0}{resetColor} {darkGreyText}({chunkEmptyCalls,3:N0}){resetColor} | sload {chunkSload,7:N0} | sstore {sstoreColor}{chunkSstore,6:N0}{resetColor} | create {createsColor}{chunkCreates,3:N0}{resetColor}{(currentSelfDestructs - _lastSelfDestructs > 0 ? $"{darkGreyText}({-(currentSelfDestructs - _lastSelfDestructs),3:N0}){resetColor}" : "")}");
- _logger.Info($"- Block throughput {mgasPerSecondColor}{mgasPerSecond,7:F2}{resetColor} MGas/s | {txps,9:F2} t/s | {bps,7:F2} Blk/s | recv {recoveryQueueSize,7:N0} | proc {blockQueueSize,6:N0}");
- // Only output the total throughput in debug mode
- if (_logger.IsDebug)
- {
- _logger.Debug($"- Total throughput {totalMgasPerSecond,7:F2} MGas/s | {totalTxPerSecond,9:F2} t/s | {totalBlocksPerSecond,7:F2} Blk/s |⛽ Gas gwei: {Evm.Metrics.MinGasPrice:N2} .. {Math.Max(Evm.Metrics.MinGasPrice, Evm.Metrics.EstMedianGasPrice):N2} ({Evm.Metrics.AveGasPrice:N2}) .. {Evm.Metrics.MaxGasPrice:N2}");
- }
+ _logger.Info($"Processed {block.Number,10} | {chunkColor}{chunkMs,9:N2}{resetColor} ms | slot {runMs,7:N0} ms |{blockGas}");
+ }
- if (_logger.IsTrace)
- {
- long currentGen0 = GC.CollectionCount(0);
- long currentGen1 = GC.CollectionCount(1);
- long currentGen2 = GC.CollectionCount(2);
- long currentMemory = GC.GetTotalMemory(false);
- _maxMemory = Math.Max(_maxMemory, currentMemory);
- _logger.Trace($"Gen0 {currentGen0 - _lastGen0,6}, Gen1 {currentGen1 - _lastGen1,6}, Gen2 {currentGen2 - _lastGen2,6}, maxmem {_maxMemory / 1000000,5}, mem {currentMemory / 1000000,5}, reads {currentStateDbReads - _lastStateDbReads,9}, writes {currentStateDbWrites - _lastStateDbWrites,9}, rlp {currentTreeNodeRlp - _lastTreeNodeRlp,9}, exceptions {evmExceptions - _lastEvmExceptions}, selfdstrcs {currentSelfDestructs - _lastSelfDestructs}");
- _lastGen0 = currentGen0;
- _lastGen1 = currentGen1;
- _lastGen2 = currentGen2;
- }
+ string mgasPerSecondColor = (mgasPerSecond / (block.GasLimit / 1_000_000.0)) switch
+ {
+ // At 30M gas limit the values are in comments
+ > 3 => greenText, // 90 MGas/s
+ > 2.5f => darkGreenText, // 75 MGas/s
+ > 2 => whiteText, // 60 MGas/s
+ > 1.5f => resetColor, // 45 MGas/s
+ > 1 => yellowText, // 30 MGas/s
+ > 0.5f => orangeText, // 15 MGas/s
+ _ => redText
+ };
+ var sstoreColor = chunkBlocks > 1 ? "" : chunkSstore switch
+ {
+ > 3500 => redText,
+ > 2500 => orangeText,
+ > 2000 => yellowText,
+ > 1500 => whiteText,
+ > 900 when chunkCalls > 900 => whiteText,
+ _ => ""
+ };
+ var callsColor = chunkBlocks > 1 ? "" : chunkCalls switch
+ {
+ > 3500 => redText,
+ > 2500 => orangeText,
+ > 2000 => yellowText,
+ > 1500 => whiteText,
+ > 900 when chunkSstore > 900 => whiteText,
+ _ => ""
+ };
+ var createsColor = chunkBlocks > 1 ? "" : chunkCreates switch
+ {
+ > 300 => redText,
+ > 200 => orangeText,
+ > 150 => yellowText,
+ > 75 => whiteText,
+ _ => ""
+ };
+ var recoveryQueue = Metrics.RecoveryQueueSize;
+ var processingQueue = Metrics.ProcessingQueueSize;
+
+ _logger.Info($"- Block{(chunkBlocks > 1 ? $"s {chunkBlocks,-9:N0}" : " ")}{(chunkBlocks == 1 ? mgasColor : "")} {chunkMGas,9:F2}{resetColor} MGas | {chunkTx,6:N0} txs | calls {callsColor}{chunkCalls,6:N0}{resetColor} {darkGreyText}({chunkEmptyCalls,3:N0}){resetColor} | sload {chunkSload,7:N0} | sstore {sstoreColor}{chunkSstore,6:N0}{resetColor} | create {createsColor}{chunkCreates,3:N0}{resetColor}{(currentSelfDestructs - _lastSelfDestructs > 0 ? $"{darkGreyText}({-(currentSelfDestructs - _lastSelfDestructs),3:N0}){resetColor}" : "")}");
+ if (recoveryQueue > 0 || processingQueue > 0)
+ {
+ _logger.Info($"- Block throughput {mgasPerSecondColor}{mgasPerSecond,9:F2}{resetColor} MGas/s{(mgasPerSecond > 1000 ? "🔥" : " ")}| {txps,9:F2} t/s | {bps,7:F2} Blk/s | recover {recoveryQueue,5:N0} | process {processingQueue,5:N0}");
+ }
+ else
+ {
+ _logger.Info($"- Block throughput {mgasPerSecondColor}{mgasPerSecond,9:F2}{resetColor} MGas/s{(mgasPerSecond > 1000 ? "🔥" : " ")}| {txps,9:F2} t/s | {bps,7:F2} Blk/s | exec code {resetColor} from cache {cachedContractsUsed,7:N0} |{resetColor} new {contractsAnalysed,6:N0}");
}
- _lastReportMs = reportMs;
- _lastBlockNumber = Metrics.Blocks;
- _lastTotalMGas = Metrics.Mgas;
- _lastElapsedRunningMicroseconds = runningMicroseconds;
- _lastTotalTx = Metrics.Transactions;
- _lastTotalCalls = Evm.Metrics.Calls;
- _lastTotalEmptyCalls = Evm.Metrics.EmptyCalls;
- _lastTotalCreates = Evm.Metrics.Creates;
- _lastTotalSLoad = Evm.Metrics.SloadOpcode;
- _lastTotalSStore = Evm.Metrics.SstoreOpcode;
- _lastStateDbReads = currentStateDbReads;
- _lastStateDbWrites = currentStateDbWrites;
- _lastTreeNodeRlp = currentTreeNodeRlp;
- _lastEvmExceptions = evmExceptions;
- _lastSelfDestructs = currentSelfDestructs;
- _processingMicroseconds = 0;
+ // Only output the total throughput in debug mode
+ if (_logger.IsDebug)
+ {
+ _logger.Debug($"- Total throughput {totalMgasPerSecond,9:F2} MGas/s | {totalTxPerSecond,9:F2} t/s | {totalBlocksPerSecond,7:F2} Blk/s |⛽ Gas gwei: {Evm.Metrics.MinGasPrice:N2} .. {Math.Max(Evm.Metrics.MinGasPrice, Evm.Metrics.EstMedianGasPrice):N2} ({Evm.Metrics.AveGasPrice:N2}) .. {Evm.Metrics.MaxGasPrice:N2}");
+ }
}
+
+ _lastCachedContractsUsed = _codeDbCacheProcessing;
+ _lastContractsAnalysed = _contractAnalysedProcessing;
+ _lastBlockNumber = Metrics.Blocks;
+ _lastTotalMGas = Metrics.Mgas;
+ _lastElapsedRunningMicroseconds = _runningMicroseconds;
+ _lastTotalTx = Metrics.Transactions;
+ _lastTotalCalls = _callsProcessing;
+ _lastTotalEmptyCalls = _emptyCallsProcessing;
+ _lastTotalCreates = _createsProcessing;
+ _lastTotalSLoad = _sloadOpcodeProcessing;
+ _lastTotalSStore = _sstoreOpcodeProcessing;
+ _lastSelfDestructs = currentSelfDestructs;
+ _chunkProcessingMicroseconds = 0;
}
public void Start()
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyChainProcessingEnv.cs b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyChainProcessingEnv.cs
index 483a410e3ac..9d09f3a888e 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyChainProcessingEnv.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyChainProcessingEnv.cs
@@ -2,12 +2,13 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System;
+using Nethermind.Blockchain;
using Nethermind.Blockchain.Blocks;
using Nethermind.Blockchain.Receipts;
using Nethermind.Consensus.Rewards;
using Nethermind.Consensus.Validators;
using Nethermind.Core.Specs;
-using Nethermind.Db;
+using Nethermind.Evm.TransactionProcessing;
using Nethermind.Logging;
using Nethermind.State;
@@ -18,44 +19,57 @@ namespace Nethermind.Consensus.Processing
///
public class ReadOnlyChainProcessingEnv : IDisposable
{
- private readonly ReadOnlyTxProcessingEnv _txEnv;
-
private readonly BlockchainProcessor _blockProcessingQueue;
public IBlockProcessor BlockProcessor { get; }
public IBlockchainProcessor ChainProcessor { get; }
public IBlockProcessingQueue BlockProcessingQueue { get; }
- public IWorldState StateProvider => _txEnv.StateProvider;
public ReadOnlyChainProcessingEnv(
- ReadOnlyTxProcessingEnv txEnv,
+ IReadOnlyTxProcessingScope scope,
IBlockValidator blockValidator,
IBlockPreprocessorStep recoveryStep,
IRewardCalculator rewardCalculator,
IReceiptStorage receiptStorage,
ISpecProvider specProvider,
+ IBlockTree blockTree,
+ IStateReader stateReader,
ILogManager logManager,
IBlockProcessor.IBlockTransactionsExecutor? blockTransactionsExecutor = null)
{
- _txEnv = txEnv;
-
IBlockProcessor.IBlockTransactionsExecutor transactionsExecutor =
- blockTransactionsExecutor ?? new BlockProcessor.BlockValidationTransactionsExecutor(_txEnv.TransactionProcessor, StateProvider);
+ blockTransactionsExecutor ?? new BlockProcessor.BlockValidationTransactionsExecutor(scope.TransactionProcessor, scope.WorldState);
+
+ BlockProcessor = CreateBlockProcessor(scope, blockTree, blockValidator, rewardCalculator, receiptStorage, specProvider, logManager, transactionsExecutor);
+
+ _blockProcessingQueue = new BlockchainProcessor(blockTree, BlockProcessor, recoveryStep, stateReader, logManager, BlockchainProcessor.Options.NoReceipts);
+ BlockProcessingQueue = _blockProcessingQueue;
+ ChainProcessor = new OneTimeChainProcessor(scope.WorldState, _blockProcessingQueue);
+ _blockProcessingQueue = new BlockchainProcessor(blockTree, BlockProcessor, recoveryStep, stateReader, logManager, BlockchainProcessor.Options.NoReceipts);
+ BlockProcessingQueue = _blockProcessingQueue;
+ ChainProcessor = new OneTimeChainProcessor(scope.WorldState, _blockProcessingQueue);
+ }
- BlockProcessor = new BlockProcessor(
+ protected virtual IBlockProcessor CreateBlockProcessor(
+ IReadOnlyTxProcessingScope scope,
+ IBlockTree blockTree,
+ IBlockValidator blockValidator,
+ IRewardCalculator rewardCalculator,
+ IReceiptStorage receiptStorage,
+ ISpecProvider specProvider,
+ ILogManager logManager,
+ IBlockProcessor.IBlockTransactionsExecutor transactionsExecutor
+ )
+ {
+ return new BlockProcessor(
specProvider,
blockValidator,
rewardCalculator,
transactionsExecutor,
- StateProvider,
+ scope.WorldState,
receiptStorage,
- NullWitnessCollector.Instance,
- new BlockhashStore(txEnv.BlockTree, specProvider, StateProvider),
- _txEnv.TransactionProcessor,
+ new BlockhashStore(blockTree, specProvider, scope.WorldState),
+ scope.TransactionProcessor,
logManager);
-
- _blockProcessingQueue = new BlockchainProcessor(_txEnv.BlockTree, BlockProcessor, recoveryStep, _txEnv.StateReader, logManager, BlockchainProcessor.Options.NoReceipts);
- BlockProcessingQueue = _blockProcessingQueue;
- ChainProcessor = new OneTimeChainProcessor(txEnv.StateProvider, _blockProcessingQueue);
}
public void Dispose()
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs
index 47671734515..dc13eca75dc 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs
@@ -14,43 +14,58 @@
// ReSharper disable UnusedAutoPropertyAccessor.Global
namespace Nethermind.Consensus.Processing
{
- public class ReadOnlyTxProcessingEnv : IReadOnlyTxProcessorSource
+ public class ReadOnlyTxProcessingEnv : ReadOnlyTxProcessingEnvBase, IReadOnlyTxProcessorSource
{
- public IStateReader StateReader { get; }
- public IWorldState StateProvider { get; }
- public ITransactionProcessor TransactionProcessor { get; set; }
- public IBlockTree BlockTree { get; }
- public IBlockhashProvider BlockhashProvider { get; }
+ protected readonly ILogManager _logManager;
+
+ protected ITransactionProcessor? _transactionProcessor;
+ protected ITransactionProcessor TransactionProcessor
+ {
+ get
+ {
+ return _transactionProcessor ??= CreateTransactionProcessor();
+ }
+ }
+
public IVirtualMachine Machine { get; }
+ public ICodeInfoRepository CodeInfoRepository { get; }
public ReadOnlyTxProcessingEnv(
IWorldStateManager worldStateManager,
- IBlockTree? blockTree,
+ IBlockTree blockTree,
ISpecProvider? specProvider,
- ILogManager? logManager)
- : this(worldStateManager, blockTree?.AsReadOnly(), specProvider, logManager)
+ ILogManager? logManager,
+ IWorldState? worldStateToWarmUp = null)
+ : this(worldStateManager, blockTree.AsReadOnly(), specProvider, logManager, worldStateToWarmUp)
{
}
public ReadOnlyTxProcessingEnv(
IWorldStateManager worldStateManager,
- IReadOnlyBlockTree? readOnlyBlockTree,
+ IReadOnlyBlockTree readOnlyBlockTree,
ISpecProvider? specProvider,
- ILogManager? logManager)
+ ILogManager? logManager,
+ IWorldState? worldStateToWarmUp = null
+ ) : base(worldStateManager, readOnlyBlockTree, specProvider, logManager, worldStateToWarmUp)
{
- ArgumentNullException.ThrowIfNull(specProvider);
- ArgumentNullException.ThrowIfNull(worldStateManager);
-
- StateReader = worldStateManager.GlobalStateReader;
- StateProvider = worldStateManager.CreateResettableWorldState();
-
+ CodeInfoRepository = new CodeInfoRepository();
+ Machine = new VirtualMachine(BlockhashProvider, specProvider, CodeInfoRepository, logManager);
BlockTree = readOnlyBlockTree ?? throw new ArgumentNullException(nameof(readOnlyBlockTree));
BlockhashProvider = new BlockhashProvider(BlockTree, specProvider, StateProvider, logManager);
- Machine = new VirtualMachine(BlockhashProvider, specProvider, logManager);
- TransactionProcessor = new TransactionProcessor(specProvider, StateProvider, Machine, logManager);
+ _logManager = logManager;
}
- public IReadOnlyTransactionProcessor Build(Hash256 stateRoot) => new ReadOnlyTransactionProcessor(TransactionProcessor, StateProvider, stateRoot);
+ protected virtual TransactionProcessor CreateTransactionProcessor()
+ {
+ return new TransactionProcessor(SpecProvider, StateProvider, Machine, CodeInfoRepository, _logManager);
+ }
+
+ public IReadOnlyTxProcessingScope Build(Hash256 stateRoot)
+ {
+ Hash256 originalStateRoot = StateProvider.StateRoot;
+ StateProvider.StateRoot = stateRoot;
+ return new ReadOnlyTxProcessingScope(TransactionProcessor, StateProvider, originalStateRoot);
+ }
}
}
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnvBase.cs b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnvBase.cs
new file mode 100644
index 00000000000..058aca9f9c2
--- /dev/null
+++ b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnvBase.cs
@@ -0,0 +1,40 @@
+// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using Nethermind.Blockchain;
+using Nethermind.Core.Specs;
+using Nethermind.Evm;
+using Nethermind.Logging;
+using Nethermind.State;
+
+namespace Nethermind.Consensus.Processing;
+
+public class ReadOnlyTxProcessingEnvBase
+{
+ public IStateReader StateReader { get; protected set; }
+ protected IWorldState StateProvider { get; set; }
+ public IBlockTree BlockTree { get; protected set; }
+ public IBlockhashProvider BlockhashProvider { get; protected set; }
+
+ public ISpecProvider SpecProvider { get; }
+ public ILogManager? LogManager { get; set; }
+
+ protected ReadOnlyTxProcessingEnvBase(
+ IWorldStateManager worldStateManager,
+ IBlockTree readOnlyBlockTree,
+ ISpecProvider? specProvider,
+ ILogManager? logManager,
+ IWorldState? worldStateToWarmUp = null
+ )
+ {
+ ArgumentNullException.ThrowIfNull(specProvider);
+ ArgumentNullException.ThrowIfNull(worldStateManager);
+ SpecProvider = specProvider;
+ StateReader = worldStateManager.GlobalStateReader;
+ StateProvider = worldStateManager.CreateResettableWorldState(worldStateToWarmUp);
+ BlockTree = readOnlyBlockTree ?? throw new ArgumentNullException(nameof(readOnlyBlockTree));
+ BlockhashProvider = new BlockhashProvider(BlockTree, specProvider, StateProvider, logManager);
+ LogManager = logManager;
+ }
+}
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnvFactory.cs b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnvFactory.cs
index 1408e3c547e..93c214be0cd 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnvFactory.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnvFactory.cs
@@ -3,40 +3,27 @@
using Nethermind.Blockchain;
using Nethermind.Core.Specs;
-using Nethermind.Db;
using Nethermind.Logging;
using Nethermind.State;
-using Nethermind.Trie.Pruning;
namespace Nethermind.Consensus.Processing;
-public class ReadOnlyTxProcessingEnvFactory
+public class ReadOnlyTxProcessingEnvFactory(
+ IWorldStateManager worldStateManager,
+ IReadOnlyBlockTree readOnlyBlockTree,
+ ISpecProvider? specProvider,
+ ILogManager? logManager,
+ IWorldState? worldStateToWarmUp = null)
{
- private readonly IWorldStateManager _worldStateManager;
- private readonly IReadOnlyBlockTree? _readOnlyBlockTree;
- private readonly ISpecProvider? _specProvider;
- private readonly ILogManager? _logManager;
-
- public ReadOnlyTxProcessingEnvFactory(
- IWorldStateManager worldStateManager,
- IBlockTree? blockTree,
- ISpecProvider? specProvider,
- ILogManager? logManager)
- : this(worldStateManager, blockTree?.AsReadOnly(), specProvider, logManager)
- {
- }
-
public ReadOnlyTxProcessingEnvFactory(
IWorldStateManager worldStateManager,
- IReadOnlyBlockTree? readOnlyBlockTree,
+ IBlockTree blockTree,
ISpecProvider? specProvider,
- ILogManager? logManager)
+ ILogManager? logManager,
+ IWorldState? worldStateToWarmUp = null)
+ : this(worldStateManager, blockTree.AsReadOnly(), specProvider, logManager, worldStateToWarmUp)
{
- _worldStateManager = worldStateManager;
- _readOnlyBlockTree = readOnlyBlockTree;
- _specProvider = specProvider;
- _logManager = logManager;
}
- public ReadOnlyTxProcessingEnv Create() => new(_worldStateManager, _readOnlyBlockTree, _specProvider, _logManager);
+ public ReadOnlyTxProcessingEnv Create() => new(worldStateManager, readOnlyBlockTree, specProvider, logManager, worldStateToWarmUp);
}
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingScope.cs b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingScope.cs
new file mode 100644
index 00000000000..bf14441b48b
--- /dev/null
+++ b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingScope.cs
@@ -0,0 +1,24 @@
+// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using Nethermind.Core.Crypto;
+using Nethermind.Evm.TransactionProcessing;
+using Nethermind.State;
+
+namespace Nethermind.Consensus.Processing;
+
+public class ReadOnlyTxProcessingScope(
+ ITransactionProcessor transactionProcessor,
+ IWorldState worldState,
+ Hash256 originalStateRoot
+) : IReadOnlyTxProcessingScope
+{
+ public void Dispose()
+ {
+ worldState.StateRoot = originalStateRoot;
+ worldState.Reset();
+ }
+
+ public ITransactionProcessor TransactionProcessor => transactionProcessor;
+ public IWorldState WorldState => worldState;
+}
diff --git a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs
index 2aa2abc4e57..94ae0ee38f0 100644
--- a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs
+++ b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs
@@ -16,14 +16,12 @@
using Nethermind.Int256;
using Nethermind.Logging;
using Nethermind.State;
-using Nethermind.Trie;
using Metrics = Nethermind.Blockchain.Metrics;
namespace Nethermind.Consensus.Producers
{
///
/// I think this class can be significantly simplified if we split the block production into a pipeline:
- /// * signal block needed
/// * prepare block frame
/// * select transactions
/// * seal
@@ -36,7 +34,6 @@ public abstract class BlockProducerBase : IBlockProducer
private IBlockchainProcessor Processor { get; }
protected IBlockTree BlockTree { get; }
private ITimestamper Timestamper { get; }
- public event EventHandler? BlockProduced;
private ISealer Sealer { get; }
private IWorldState StateProvider { get; }
@@ -44,13 +41,8 @@ public abstract class BlockProducerBase : IBlockProducer
private readonly IDifficultyCalculator _difficultyCalculator;
protected readonly ISpecProvider _specProvider;
private readonly ITxSource _txSource;
- private readonly IBlockProductionTrigger _trigger;
- private bool _isRunning;
- protected readonly SemaphoreSlim _producingBlockLock = new(1);
- private CancellationTokenSource? _producerCancellationToken;
-
- private DateTime _lastProducedBlockDateTime;
protected const int BlockProductionTimeout = 2000;
+ protected readonly SemaphoreSlim _producingBlockLock = new(1);
protected ILogger Logger { get; }
protected readonly IBlocksConfig _blocksConfig;
@@ -59,7 +51,6 @@ protected BlockProducerBase(
IBlockchainProcessor? processor,
ISealer? sealer,
IBlockTree? blockTree,
- IBlockProductionTrigger? trigger,
IWorldState? stateProvider,
IGasLimitCalculator? gasLimitCalculator,
ITimestamper? timestamper,
@@ -76,59 +67,21 @@ protected BlockProducerBase(
_gasLimitCalculator = gasLimitCalculator ?? throw new ArgumentNullException(nameof(gasLimitCalculator));
Timestamper = timestamper ?? throw new ArgumentNullException(nameof(timestamper));
_specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider));
- _trigger = trigger ?? throw new ArgumentNullException(nameof(trigger));
_difficultyCalculator = difficultyCalculator ?? throw new ArgumentNullException(nameof(difficultyCalculator));
Logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager));
_blocksConfig = blocksConfig ?? throw new ArgumentNullException(nameof(blocksConfig));
}
- private void OnTriggerBlockProduction(object? sender, BlockProductionEventArgs e)
- {
- BlockHeader? parent = BlockTree.GetProducedBlockParent(e.ParentHeader);
- e.BlockProductionTask = TryProduceAndAnnounceNewBlock(e.CancellationToken, parent, e.BlockTracer, e.PayloadAttributes);
- }
-
- public virtual Task Start()
+ public async Task BuildBlock(BlockHeader? parentHeader = null, IBlockTracer? blockTracer = null,
+ PayloadAttributes? payloadAttributes = null, CancellationToken? token = null)
{
- _producerCancellationToken = new CancellationTokenSource();
- _isRunning = true;
- _trigger.TriggerBlockProduction += OnTriggerBlockProduction;
- _lastProducedBlockDateTime = DateTime.UtcNow;
- return Task.CompletedTask;
- }
-
- public virtual Task StopAsync()
- {
- _producerCancellationToken?.Cancel();
- _isRunning = false;
- _trigger.TriggerBlockProduction -= OnTriggerBlockProduction;
- _producerCancellationToken?.Dispose();
- return Task.CompletedTask;
- }
-
- protected virtual bool IsRunning() => _isRunning;
-
- public bool IsProducingBlocks(ulong? maxProducingInterval)
- {
- if (Logger.IsTrace) Logger.Trace($"Checking IsProducingBlocks: maxProducingInterval {maxProducingInterval}, _lastProducedBlock {_lastProducedBlockDateTime}, IsRunning() {IsRunning()}");
- return IsRunning() && (maxProducingInterval is null || _lastProducedBlockDateTime.AddSeconds(maxProducingInterval.Value) > DateTime.UtcNow);
- }
-
- private async Task TryProduceAndAnnounceNewBlock(CancellationToken token, BlockHeader? parentHeader, IBlockTracer? blockTracer = null, PayloadAttributes? payloadAttributes = null)
- {
- using CancellationTokenSource tokenSource = CancellationTokenSource.CreateLinkedTokenSource(token, _producerCancellationToken!.Token);
- token = tokenSource.Token;
-
+ token ??= default;
Block? block = null;
- if (await _producingBlockLock.WaitAsync(BlockProductionTimeout, token))
+ if (await _producingBlockLock.WaitAsync(BlockProductionTimeout, token.Value))
{
try
{
- block = await TryProduceNewBlock(token, parentHeader, blockTracer, payloadAttributes);
- if (block is not null)
- {
- BlockProduced?.Invoke(this, new BlockEventArgs(block));
- }
+ block = await TryProduceNewBlock(token.Value, parentHeader, blockTracer, payloadAttributes);
}
catch (Exception e) when (!(e is TaskCanceledException))
{
@@ -196,7 +149,6 @@ public bool IsProducingBlocks(ulong? maxProducingInterval)
if (Logger.IsInfo)
Logger.Info($"Produced block {t.Result.ToString(Block.Format.HashNumberDiffAndTx)}");
Metrics.BlocksSealed++;
- _lastProducedBlockDateTime = DateTime.UtcNow;
return t.Result;
}
else
diff --git a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerEnvFactory.cs b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerEnvFactory.cs
index 9c6270a5e19..3cc5cfde05a 100644
--- a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerEnvFactory.cs
+++ b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerEnvFactory.cs
@@ -12,7 +12,9 @@
using Nethermind.Consensus.Transactions;
using Nethermind.Consensus.Validators;
using Nethermind.Consensus.Withdrawals;
+using Nethermind.Core.Crypto;
using Nethermind.Core.Specs;
+using Nethermind.Evm.TransactionProcessing;
using Nethermind.Logging;
using Nethermind.State;
using Nethermind.TxPool;
@@ -73,8 +75,11 @@ public virtual BlockProducerEnv Create(ITxSource? additionalTxSource = null)
ReadOnlyTxProcessingEnv txProcessingEnv =
CreateReadonlyTxProcessingEnv(_worldStateManager, readOnlyBlockTree);
+ IReadOnlyTxProcessingScope scope = txProcessingEnv.Build(Keccak.EmptyTreeHash);
+
BlockProcessor blockProcessor =
- CreateBlockProcessor(txProcessingEnv,
+ CreateBlockProcessor(
+ scope,
_specProvider,
_blockValidator,
_rewardCalculatorSource,
@@ -92,14 +97,14 @@ public virtual BlockProducerEnv Create(ITxSource? additionalTxSource = null)
BlockchainProcessor.Options.NoReceipts);
OneTimeChainProcessor chainProcessor = new(
- txProcessingEnv.StateProvider,
+ scope.WorldState,
blockchainProcessor);
return new BlockProducerEnv
{
BlockTree = readOnlyBlockTree,
ChainProcessor = chainProcessor,
- ReadOnlyStateProvider = txProcessingEnv.StateProvider,
+ ReadOnlyStateProvider = scope.WorldState,
TxSource = CreateTxSourceForProducer(additionalTxSource, txProcessingEnv, _txPool, _blocksConfig, _transactionComparerProvider, _logManager),
ReadOnlyTxProcessingEnv = txProcessingEnv
};
@@ -134,7 +139,8 @@ protected virtual TxPoolTxSource CreateTxPoolTxSource(
protected virtual ITxFilterPipeline CreateTxSourceFilter(IBlocksConfig blocksConfig) =>
TxFilterPipelineBuilder.CreateStandardFilteringPipeline(_logManager, _specProvider, blocksConfig);
- protected virtual BlockProcessor CreateBlockProcessor(ReadOnlyTxProcessingEnv readOnlyTxProcessingEnv,
+ protected virtual BlockProcessor CreateBlockProcessor(
+ IReadOnlyTxProcessingScope readOnlyTxProcessingEnv,
ISpecProvider specProvider,
IBlockValidator blockValidator,
IRewardCalculatorSource rewardCalculatorSource,
@@ -144,14 +150,13 @@ protected virtual BlockProcessor CreateBlockProcessor(ReadOnlyTxProcessingEnv re
blockValidator,
rewardCalculatorSource.Get(readOnlyTxProcessingEnv.TransactionProcessor),
TransactionsExecutorFactory.Create(readOnlyTxProcessingEnv),
- readOnlyTxProcessingEnv.StateProvider,
+ readOnlyTxProcessingEnv.WorldState,
receiptStorage,
- NullWitnessCollector.Instance,
- new BlockhashStore(_blockTree, _specProvider, readOnlyTxProcessingEnv.StateProvider),
+ new BlockhashStore(_blockTree, _specProvider, readOnlyTxProcessingEnv.WorldState),
readOnlyTxProcessingEnv.TransactionProcessor,
logManager,
- new BlockProductionWithdrawalProcessor(new WithdrawalProcessor(readOnlyTxProcessingEnv.StateProvider, logManager)),
- consensusRequestsProcessor: _consensusRequestsProcessor);
-
+ new BlockProductionWithdrawalProcessor(new WithdrawalProcessor(readOnlyTxProcessingEnv.WorldState, logManager)),
+ consensusRequestsProcessor: _consensusRequestsProcessor
+ );
}
}
diff --git a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerTransactionsExecutorFactory.cs b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerTransactionsExecutorFactory.cs
index 3f509d1eb45..5f00e0e76a0 100644
--- a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerTransactionsExecutorFactory.cs
+++ b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerTransactionsExecutorFactory.cs
@@ -3,6 +3,7 @@
using Nethermind.Consensus.Processing;
using Nethermind.Core.Specs;
+using Nethermind.Evm.TransactionProcessing;
using Nethermind.Logging;
namespace Nethermind.Consensus.Producers
@@ -19,7 +20,7 @@ public BlockProducerTransactionsExecutorFactory(ISpecProvider specProvider, ILog
_logManager = logManager;
}
- public IBlockProcessor.IBlockTransactionsExecutor Create(ReadOnlyTxProcessingEnv readOnlyTxProcessingEnv) =>
+ public IBlockProcessor.IBlockTransactionsExecutor Create(IReadOnlyTxProcessingScope readOnlyTxProcessingEnv) =>
new BlockProcessor.BlockProductionTransactionsExecutor(readOnlyTxProcessingEnv, _specProvider, _logManager);
}
}
diff --git a/src/Nethermind/Nethermind.Consensus/Producers/DevBlockProducer.cs b/src/Nethermind/Nethermind.Consensus/Producers/DevBlockProducer.cs
index 162a9e2dfcb..d164fda7537 100644
--- a/src/Nethermind/Nethermind.Consensus/Producers/DevBlockProducer.cs
+++ b/src/Nethermind/Nethermind.Consensus/Producers/DevBlockProducer.cs
@@ -23,7 +23,6 @@ public DevBlockProducer(
IBlockchainProcessor? processor,
IWorldState? stateProvider,
IBlockTree? blockTree,
- IBlockProductionTrigger? trigger,
ITimestamper? timestamper,
ISpecProvider? specProvider,
IBlocksConfig? blockConfig,
@@ -33,7 +32,6 @@ public DevBlockProducer(
processor,
new NethDevSealEngine(),
blockTree,
- trigger,
stateProvider,
new FollowOtherMiners(specProvider!),
timestamper,
diff --git a/src/Nethermind/Nethermind.Consensus/Producers/IBlockProducerInfo.cs b/src/Nethermind/Nethermind.Consensus/Producers/IBlockProducerInfo.cs
index 53c35e52ab8..1df7ce39e70 100644
--- a/src/Nethermind/Nethermind.Consensus/Producers/IBlockProducerInfo.cs
+++ b/src/Nethermind/Nethermind.Consensus/Producers/IBlockProducerInfo.cs
@@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
+using System;
+using Nethermind.Core;
using Nethermind.Evm.Tracing;
namespace Nethermind.Consensus.Producers
@@ -8,7 +10,7 @@ namespace Nethermind.Consensus.Producers
public interface IBlockProducerInfo
{
IBlockProducer BlockProducer { get; }
- IManualBlockProductionTrigger BlockProductionTrigger { get; }
+ IBlockProductionCondition Condition { get; }
IBlockTracer BlockTracer => NullBlockTracer.Instance;
}
}
diff --git a/src/Nethermind/Nethermind.Consensus/Producers/IBlockProductionCondition.cs b/src/Nethermind/Nethermind.Consensus/Producers/IBlockProductionCondition.cs
new file mode 100644
index 00000000000..2c0feb2755d
--- /dev/null
+++ b/src/Nethermind/Nethermind.Consensus/Producers/IBlockProductionCondition.cs
@@ -0,0 +1,21 @@
+// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using Nethermind.Core;
+
+namespace Nethermind.Consensus.Producers;
+
+public interface IBlockProductionCondition
+{
+ bool CanProduce(BlockHeader parentHeader);
+}
+
+public class AlwaysOkBlockProductionCondition : IBlockProductionCondition
+{
+ public static IBlockProductionCondition Instance = new AlwaysOkBlockProductionCondition();
+
+ public bool CanProduce(BlockHeader parentHeader)
+ {
+ return true;
+ }
+}
diff --git a/src/Nethermind/Nethermind.Consensus/Producers/IBlockTransactionsExecutorFactory.cs b/src/Nethermind/Nethermind.Consensus/Producers/IBlockTransactionsExecutorFactory.cs
index 9ffd775764e..d3164780c86 100644
--- a/src/Nethermind/Nethermind.Consensus/Producers/IBlockTransactionsExecutorFactory.cs
+++ b/src/Nethermind/Nethermind.Consensus/Producers/IBlockTransactionsExecutorFactory.cs
@@ -2,11 +2,12 @@
// SPDX-License-Identifier: LGPL-3.0-only
using Nethermind.Consensus.Processing;
+using Nethermind.Evm.TransactionProcessing;
namespace Nethermind.Consensus.Producers
{
public interface IBlockTransactionsExecutorFactory
{
- IBlockProcessor.IBlockTransactionsExecutor Create(ReadOnlyTxProcessingEnv readOnlyTxProcessingEnv);
+ IBlockProcessor.IBlockTransactionsExecutor Create(IReadOnlyTxProcessingScope readOnlyTxProcessingEnv);
}
}
diff --git a/src/Nethermind/Nethermind.Consensus/Producers/MultipleBlockProducer.cs b/src/Nethermind/Nethermind.Consensus/Producers/MultipleBlockProducer.cs
index 116e55bb3e7..57836b2e474 100644
--- a/src/Nethermind/Nethermind.Consensus/Producers/MultipleBlockProducer.cs
+++ b/src/Nethermind/Nethermind.Consensus/Producers/MultipleBlockProducer.cs
@@ -7,84 +7,41 @@
using System.Threading;
using System.Threading.Tasks;
using Nethermind.Core;
+using Nethermind.Evm.Tracing;
using Nethermind.Logging;
namespace Nethermind.Consensus.Producers
{
public abstract class MultipleBlockProducer : IBlockProducer where T : IBlockProducerInfo
{
- private readonly IBlockProductionTrigger _blockProductionTrigger;
private readonly IBestBlockPicker _bestBlockPicker;
private readonly T[] _blockProducers;
private readonly ILogger _logger;
protected MultipleBlockProducer(
- IBlockProductionTrigger blockProductionTrigger,
IBestBlockPicker bestBlockPicker,
ILogManager logManager,
params T[] blockProducers)
{
if (blockProducers.Length == 0) throw new ArgumentException("Collection cannot be empty.", nameof(blockProducers));
- _blockProductionTrigger = blockProductionTrigger;
_bestBlockPicker = bestBlockPicker;
_blockProducers = blockProducers;
_logger = logManager.GetClassLogger();
}
- public Task Start()
- {
- for (int index = 0; index < _blockProducers.Length; index++)
- {
- IBlockProducer blockProducer = _blockProducers[index].BlockProducer;
- blockProducer.Start();
- }
-
- _blockProductionTrigger.TriggerBlockProduction += OnBlockProduction;
- return Task.CompletedTask;
- }
-
- public Task StopAsync()
- {
- _blockProductionTrigger.TriggerBlockProduction -= OnBlockProduction;
-
- IList stopTasks = new List();
- for (int index = 0; index < _blockProducers.Length; index++)
- {
- IBlockProducer blockProducer = _blockProducers[index].BlockProducer;
- stopTasks.Add(blockProducer.StopAsync());
- }
-
- return Task.WhenAll(stopTasks);
- }
-
- public bool IsProducingBlocks(ulong? maxProducingInterval)
- {
- for (int index = 0; index < _blockProducers.Length; index++)
- {
- IBlockProducer blockProducer = _blockProducers[index].BlockProducer;
- if (blockProducer.IsProducingBlocks(maxProducingInterval))
- {
- return true;
- }
- }
-
- return false;
- }
-
- public event EventHandler? BlockProduced;
-
- private void OnBlockProduction(object? sender, BlockProductionEventArgs e)
- {
- e.BlockProductionTask = TryProduceBlock(e.ParentHeader, e.CancellationToken);
- }
-
- private async Task TryProduceBlock(BlockHeader? parentHeader, CancellationToken cancellationToken = default)
+ public async Task BuildBlock(BlockHeader? parentHeader, IBlockTracer? blockTracer = null,
+ PayloadAttributes? payloadAttributes = null, CancellationToken? token = null)
{
Task[] produceTasks = new Task[_blockProducers.Length];
for (int i = 0; i < _blockProducers.Length; i++)
{
T blockProducerInfo = _blockProducers[i];
- produceTasks[i] = blockProducerInfo.BlockProductionTrigger.BuildBlock(parentHeader, cancellationToken, blockProducerInfo.BlockTracer);
+ if (!blockProducerInfo.Condition.CanProduce(parentHeader))
+ {
+ produceTasks[i] = Task.FromResult(null);
+ continue;
+ }
+ produceTasks[i] = blockProducerInfo.BlockProducer.BuildBlock(parentHeader, blockProducerInfo.BlockTracer, cancellationToken: token);
}
IEnumerable<(Block? Block, T BlockProducer)> blocksWithProducers;
@@ -109,8 +66,6 @@ private void OnBlockProduction(object? sender, BlockProductionEventArgs e)
{
if (_logger.IsInfo) _logger.Info($"Picked block {bestBlock} to be included to the chain.");
}
-
- BlockProduced?.Invoke(this, new BlockEventArgs(bestBlock));
}
return bestBlock;
diff --git a/src/Nethermind/Nethermind.Consensus/Producers/ProducedBlockSuggester.cs b/src/Nethermind/Nethermind.Consensus/Producers/ProducedBlockSuggester.cs
index 94c1abbaecc..a061e7f6e8c 100644
--- a/src/Nethermind/Nethermind.Consensus/Producers/ProducedBlockSuggester.cs
+++ b/src/Nethermind/Nethermind.Consensus/Producers/ProducedBlockSuggester.cs
@@ -10,13 +10,13 @@ namespace Nethermind.Consensus.Producers
public class ProducedBlockSuggester : IDisposable
{
private readonly IBlockTree _blockTree;
- private readonly IBlockProducer _blockProducer;
+ private readonly IBlockProducerRunner _blockProducerRunner;
- public ProducedBlockSuggester(IBlockTree blockTree, IBlockProducer blockProducer)
+ public ProducedBlockSuggester(IBlockTree blockTree, IBlockProducerRunner blockProducer)
{
_blockTree = blockTree;
- _blockProducer = blockProducer;
- _blockProducer.BlockProduced += OnBlockProduced;
+ _blockProducerRunner = blockProducer;
+ _blockProducerRunner.BlockProduced += OnBlockProduced;
}
private void OnBlockProduced(object? sender, BlockEventArgs e)
@@ -28,6 +28,6 @@ private void OnBlockProduced(object? sender, BlockEventArgs e)
}
}
- public void Dispose() => _blockProducer.BlockProduced -= OnBlockProduced;
+ public void Dispose() => _blockProducerRunner.BlockProduced -= OnBlockProduced;
}
}
diff --git a/src/Nethermind/Nethermind.Consensus/Signer.cs b/src/Nethermind/Nethermind.Consensus/Signer.cs
index 3a48950a129..0a22c939499 100644
--- a/src/Nethermind/Nethermind.Consensus/Signer.cs
+++ b/src/Nethermind/Nethermind.Consensus/Signer.cs
@@ -21,6 +21,8 @@ public class Signer : ISigner, ISignerStore
public bool CanSign => _key is not null;
+ public bool CanSignHeader => false;
+
public Signer(ulong chainId, PrivateKey? key, ILogManager logManager)
{
_chainId = chainId;
@@ -42,6 +44,11 @@ public Signature Sign(Hash256 message)
return new Signature(rs, v);
}
+ public Signature Sign(BlockHeader header)
+ {
+ return Sign(header.Hash);
+ }
+
public ValueTask Sign(Transaction tx)
{
Hash256 hash = Keccak.Compute(Rlp.Encode(tx, true, true, _chainId).Bytes);
diff --git a/src/Nethermind/Nethermind.Consensus/StandardBlockProducerRunner.cs b/src/Nethermind/Nethermind.Consensus/StandardBlockProducerRunner.cs
new file mode 100644
index 00000000000..25dc0cb8a03
--- /dev/null
+++ b/src/Nethermind/Nethermind.Consensus/StandardBlockProducerRunner.cs
@@ -0,0 +1,79 @@
+// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Nethermind.Blockchain;
+using Nethermind.Consensus.Producers;
+using Nethermind.Core;
+using Nethermind.Evm.Tracing;
+using Nethermind.Logging;
+
+namespace Nethermind.Consensus;
+
+public class StandardBlockProducerRunner(IBlockProductionTrigger trigger, IBlockTree blockTree, IBlockProducer blockProducer) : IBlockProducerRunner
+{
+ private bool _isRunning;
+ private CancellationTokenSource? _producerCancellationToken;
+ private DateTime _lastProducedBlockDateTime;
+ public ILogger Logger { get; }
+
+ private void OnTriggerBlockProduction(object? sender, BlockProductionEventArgs e)
+ {
+ BlockHeader? parent = blockTree.GetProducedBlockParent(e.ParentHeader);
+ e.BlockProductionTask = TryProduceAndAnnounceNewBlock(e.CancellationToken, parent, e.BlockTracer, e.PayloadAttributes);
+ }
+
+ private async Task TryProduceAndAnnounceNewBlock(CancellationToken token, BlockHeader? parentHeader, IBlockTracer? blockTracer = null, PayloadAttributes? payloadAttributes = null)
+ {
+ using CancellationTokenSource tokenSource = CancellationTokenSource.CreateLinkedTokenSource(token, _producerCancellationToken!.Token);
+ token = tokenSource.Token;
+
+ Block? block = null;
+ try
+ {
+ block = await blockProducer.BuildBlock(parentHeader, blockTracer, payloadAttributes, token);
+ if (block is not null)
+ {
+ _lastProducedBlockDateTime = DateTime.UtcNow;
+ BlockProduced?.Invoke(this, new BlockEventArgs(block));
+ }
+ }
+ catch (Exception e) when (!(e is TaskCanceledException))
+ {
+ if (Logger.IsError) Logger.Error("Failed to produce block", e);
+ Metrics.FailedBlockSeals++;
+ throw;
+ }
+
+ return block;
+ }
+
+ public virtual void Start()
+ {
+ _producerCancellationToken = new CancellationTokenSource();
+ _isRunning = true;
+ trigger.TriggerBlockProduction += OnTriggerBlockProduction;
+ _lastProducedBlockDateTime = DateTime.UtcNow;
+ }
+
+ public virtual Task StopAsync()
+ {
+ _producerCancellationToken?.Cancel();
+ _isRunning = false;
+ trigger.TriggerBlockProduction -= OnTriggerBlockProduction;
+ _producerCancellationToken?.Dispose();
+ return Task.CompletedTask;
+ }
+
+ protected virtual bool IsRunning() => _isRunning;
+
+ public bool IsProducingBlocks(ulong? maxProducingInterval)
+ {
+ if (Logger.IsTrace) Logger.Trace($"Checking IsProducingBlocks: maxProducingInterval {maxProducingInterval}, _lastProducedBlock {_lastProducedBlockDateTime}, IsRunning() {IsRunning()}");
+ return IsRunning() && (maxProducingInterval is null || _lastProducedBlockDateTime.AddSeconds(maxProducingInterval.Value) > DateTime.UtcNow);
+ }
+
+ public event EventHandler? BlockProduced;
+}
diff --git a/src/Nethermind/Nethermind.Consensus/Validators/SimulateBlockValidatorProxy.cs b/src/Nethermind/Nethermind.Consensus/Validators/SimulateBlockValidatorProxy.cs
new file mode 100644
index 00000000000..83381ed2271
--- /dev/null
+++ b/src/Nethermind/Nethermind.Consensus/Validators/SimulateBlockValidatorProxy.cs
@@ -0,0 +1,30 @@
+// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using Nethermind.Core;
+
+namespace Nethermind.Consensus.Validators;
+
+public class SimulateBlockValidatorProxy(IBlockValidator baseBlockValidator) : IBlockValidator
+{
+ public bool ValidateWithdrawals(Block block, out string? error) =>
+ baseBlockValidator.ValidateWithdrawals(block, out error);
+
+ public bool ValidateOrphanedBlock(Block block, out string? error) =>
+ baseBlockValidator.ValidateOrphanedBlock(block, out error);
+
+ public bool ValidateSuggestedBlock(Block block, out string? error, bool validateHashes = true) =>
+ baseBlockValidator.ValidateSuggestedBlock(block, out error, validateHashes);
+
+ public bool ValidateProcessedBlock(Block processedBlock, TxReceipt[] receipts, Block suggestedBlock, out string? error)
+ {
+ error = "";
+ return true;
+ }
+
+ public bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, out string? error) =>
+ baseBlockValidator.Validate(header, parent, isUncle, out error);
+
+ public bool Validate(BlockHeader header, bool isUncle, out string? error) =>
+ baseBlockValidator.Validate(header, isUncle, out error);
+}
diff --git a/src/Nethermind/Nethermind.Consensus/Withdrawals/WithdrawalProcessor.cs b/src/Nethermind/Nethermind.Consensus/Withdrawals/WithdrawalProcessor.cs
index c9fe1bddde3..e315c5a5a8e 100644
--- a/src/Nethermind/Nethermind.Consensus/Withdrawals/WithdrawalProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Withdrawals/WithdrawalProcessor.cs
@@ -31,8 +31,10 @@ public void ProcessWithdrawals(Block block, IReleaseSpec spec)
if (block.Withdrawals is not null)
{
- foreach (var withdrawal in block.Withdrawals)
+ Withdrawal[] blockWithdrawals = block.Withdrawals;
+ for (int i = 0; i < blockWithdrawals.Length; i++)
{
+ Withdrawal withdrawal = blockWithdrawals[i];
if (_logger.IsTrace) _logger.Trace($" {withdrawal.AmountInGwei} GWei to account {withdrawal.Address}");
// Consensus clients are using Gwei for withdrawals amount. We need to convert it to Wei before applying state changes https://github.com/ethereum/execution-apis/pull/354
diff --git a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockProducer.cs b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockProducer.cs
index bb4676e4d03..7aa64141a0d 100644
--- a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockProducer.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockProducer.cs
@@ -24,7 +24,6 @@ public TestBlockProducer(
IWorldState stateProvider,
ISealer sealer,
IBlockTree blockTree,
- IBlockProductionTrigger blockProductionTrigger,
ITimestamper timestamper,
ISpecProvider specProvider,
ILogManager logManager,
@@ -34,7 +33,6 @@ public TestBlockProducer(
processor,
sealer,
blockTree,
- blockProductionTrigger,
stateProvider,
new FollowOtherMiners(specProvider),
timestamper,
diff --git a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs
index 715cca275de..8e0d79aff7e 100644
--- a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs
@@ -9,7 +9,10 @@
using Nethermind.Blockchain.Blocks;
using Nethermind.Blockchain.BeaconBlockRoot;
using Nethermind.Blockchain.Find;
+using Nethermind.Blockchain.FullPruning;
+using Nethermind.Blockchain.Headers;
using Nethermind.Blockchain.Receipts;
+using Nethermind.Blockchain.Synchronization;
using Nethermind.Config;
using Nethermind.Consensus;
using Nethermind.Consensus.Comparers;
@@ -76,6 +79,7 @@ public IBlockFinder BlockFinder
public IDb StateDb => DbProvider.StateDb;
public TrieStore TrieStore { get; set; } = null!;
public IBlockProducer BlockProducer { get; private set; } = null!;
+ public IBlockProducerRunner BlockProducerRunner { get; protected set; } = null!;
public IDbProvider DbProvider { get; set; } = null!;
public ISpecProvider SpecProvider { get; set; } = null!;
@@ -117,6 +121,7 @@ protected TestBlockchain()
public ProducedBlockSuggester Suggester { get; protected set; } = null!;
public IConsensusRequestsProcessor? ConsensusRequestsProcessor { get; protected set; } = null!;
+ public ChainLevelInfoRepository ChainLevelInfoRepository { get; protected set; } = null!;
public static TransactionBuilder BuildSimpleTransaction => Builders.Build.A.Transaction.SignedAndResolved(TestItem.PrivateKeyA).To(AccountB);
@@ -128,7 +133,7 @@ protected virtual async Task Build(ISpecProvider? specProvider =
EthereumEcdsa = new EthereumEcdsa(SpecProvider.ChainId, LogManager);
DbProvider = await CreateDbProvider();
TrieStore = new TrieStore(StateDb, LogManager);
- State = new WorldState(TrieStore, DbProvider.CodeDb, LogManager);
+ State = new WorldState(TrieStore, DbProvider.CodeDb, LogManager, new PreBlockCaches());
// Eip4788 precompile state account
if (specProvider?.GenesisSpec?.IsBeaconBlockRootAvailable ?? false)
@@ -161,10 +166,17 @@ protected virtual async Task Build(ISpecProvider? specProvider =
WorldStateManager = new WorldStateManager(State, TrieStore, DbProvider, LimboLogs.Instance);
StateReader = new StateReader(ReadOnlyTrieStore, CodeDb, LogManager);
- BlockTree = Builders.Build.A.BlockTree()
- .WithSpecProvider(SpecProvider)
- .WithoutSettingHead
- .TestObject;
+ ChainLevelInfoRepository = new ChainLevelInfoRepository(this.DbProvider.BlockInfosDb);
+ BlockTree = new BlockTree(new BlockStore(DbProvider.BlocksDb),
+ new HeaderStore(DbProvider.HeadersDb, DbProvider.BlockNumbersDb),
+ DbProvider.BlockInfosDb,
+ DbProvider.MetadataDb,
+ new BlockStore(new TestMemDb(), 100),
+ ChainLevelInfoRepository,
+ SpecProvider,
+ NullBloomStorage.Instance,
+ new SyncConfig(),
+ LimboLogs.Instance);
ReadOnlyState = new ChainHeadReadOnlyStateProvider(BlockTree, StateReader);
TransactionComparerProvider = new TransactionComparerProvider(SpecProvider, BlockTree);
@@ -176,10 +188,11 @@ protected virtual async Task Build(ISpecProvider? specProvider =
NonceManager = new NonceManager(chainHeadInfoProvider.AccountStateProvider);
_trieStoreWatcher = new TrieStoreBoundaryWatcher(WorldStateManager, BlockTree, LogManager);
-
+ CodeInfoRepository codeInfoRepository = new();
ReceiptStorage = new InMemoryReceiptStorage(blockTree: BlockTree);
- VirtualMachine virtualMachine = new(new BlockhashProvider(BlockTree, SpecProvider, State, LogManager), SpecProvider, LogManager);
- TxProcessor = new TransactionProcessor(SpecProvider, State, virtualMachine, LogManager);
+ VirtualMachine virtualMachine = new(new BlockhashProvider(BlockTree, SpecProvider, State, LogManager), SpecProvider, codeInfoRepository, LogManager);
+ TxProcessor = new TransactionProcessor(SpecProvider, State, virtualMachine, codeInfoRepository, LogManager);
+
BlockPreprocessorStep = new RecoverSignatures(EthereumEcdsa, TxPool, SpecProvider, LogManager);
HeaderValidator = new HeaderValidator(BlockTree, Always.Valid, SpecProvider, LogManager);
@@ -211,13 +224,14 @@ protected virtual async Task Build(ISpecProvider? specProvider =
TxPoolTxSource txPoolTxSource = CreateTxPoolTxSource();
ITransactionComparerProvider transactionComparerProvider = new TransactionComparerProvider(SpecProvider, BlockFinder);
BlockProducer = CreateTestBlockProducer(txPoolTxSource, sealer, transactionComparerProvider);
- await BlockProducer.Start();
- Suggester = new ProducedBlockSuggester(BlockTree, BlockProducer);
+ BlockProducerRunner ??= CreateBlockProducerRunner();
+ BlockProducerRunner.Start();
+ Suggester = new ProducedBlockSuggester(BlockTree, BlockProducerRunner);
_resetEvent = new SemaphoreSlim(0);
_suggestedBlockResetEvent = new ManualResetEvent(true);
BlockTree.BlockAddedToMain += BlockAddedToMain;
- BlockProducer.BlockProduced += (s, e) =>
+ BlockProducerRunner.BlockProduced += (s, e) =>
{
_suggestedBlockResetEvent.Set();
};
@@ -287,13 +301,17 @@ protected virtual IBlockProducer CreateTestBlockProducer(TxPoolTxSource txPoolTx
env.ReadOnlyStateProvider,
sealer,
BlockTree,
- BlockProductionTrigger,
Timestamper,
SpecProvider,
LogManager,
blocksConfig);
}
+ protected virtual IBlockProducerRunner CreateBlockProducerRunner()
+ {
+ return new StandardBlockProducerRunner(BlockProductionTrigger, BlockTree, BlockProducer);
+ }
+
public virtual ILogManager LogManager { get; set; } = LimboLogs.Instance;
protected virtual TxPool.TxPool CreateTxPool() =>
@@ -369,7 +387,6 @@ protected virtual IBlockProcessor CreateBlockProcessor() =>
new BlockProcessor.BlockValidationTransactionsExecutor(TxProcessor, State),
State,
ReceiptStorage,
- NullWitnessCollector.Instance,
new BlockhashStore(BlockTree, SpecProvider, State),
TxProcessor,
LogManager,
@@ -429,7 +446,7 @@ public void AddTransactions(params Transaction[] txs)
public virtual void Dispose()
{
- BlockProducer?.StopAsync();
+ BlockProducerRunner?.StopAsync();
if (DbProvider is not null)
{
CodeDb?.Dispose();
diff --git a/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs b/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs
index c8596e8021e..a43039ef8af 100644
--- a/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs
@@ -97,7 +97,7 @@ public BlockBuilder WithTransactions(int txCount, ISpecProvider specProvider)
}
BlockBuilder result = WithTransactions(txs);
- Hash256 receiptHash = ReceiptTrie.CalculateRoot(specProvider.GetSpec(TestObjectInternal.Header), receipts, ReceiptMessageDecoder.Instance);
+ Hash256 receiptHash = ReceiptTrie.CalculateRoot(specProvider.GetSpec(TestObjectInternal.Header), receipts, Rlp.GetStreamDecoder()!);
TestObjectInternal.Header.ReceiptsRoot = receiptHash;
return result;
}
diff --git a/src/Nethermind/Nethermind.Core.Test/Builders/BlockTreeBuilder.cs b/src/Nethermind/Nethermind.Core.Test/Builders/BlockTreeBuilder.cs
index 39cbca5aa2b..1f509b8e621 100644
--- a/src/Nethermind/Nethermind.Core.Test/Builders/BlockTreeBuilder.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Builders/BlockTreeBuilder.cs
@@ -299,8 +299,7 @@ private Block CreateBlock(int splitVariant, int splitFrom, int blockIndex, Block
currentBlock.Header.TxRoot = TxTrie.CalculateRoot(currentBlock.Transactions);
TxReceipt[] txReceipts = receipts.ToArray();
currentBlock.Header.ReceiptsRoot =
- ReceiptTrie.CalculateRoot(_specProvider.GetSpec(currentBlock.Header), txReceipts,
- ReceiptMessageDecoder.Instance);
+ ReceiptTrie.CalculateRoot(_specProvider.GetSpec(currentBlock.Header), txReceipts, Rlp.GetStreamDecoder()!);
currentBlock.Header.Hash = currentBlock.CalculateHash();
foreach (TxReceipt txReceipt in txReceipts)
{
diff --git a/src/Nethermind/Nethermind.Core.Test/Caching/LruCacheLowObjectTests.cs b/src/Nethermind/Nethermind.Core.Test/Caching/LruCacheLowObjectTests.cs
new file mode 100644
index 00000000000..de3864b84f8
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core.Test/Caching/LruCacheLowObjectTests.cs
@@ -0,0 +1,182 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using FluentAssertions;
+using Nethermind.Core;
+using Nethermind.Core.Caching;
+using Nethermind.Core.Test.Builders;
+using Nethermind.Int256;
+using NUnit.Framework;
+
+using Cache = Nethermind.Core.Caching.LruCacheLowObject;
+
+namespace Nethermind.Core.Test.Caching
+{
+ public class LruCacheLowObjectTests
+ {
+ private static Cache Create()
+ {
+ return new Cache(Capacity, "test")!;
+ }
+
+ private const int Capacity = 16;
+
+ private readonly Account[] _accounts = new Account[Capacity * 2];
+ private readonly Address[] _addresses = new Address[Capacity * 2];
+
+ [SetUp]
+ public void Setup()
+ {
+ for (int i = 0; i < Capacity * 2; i++)
+ {
+ _accounts[i] = Build.An.Account.WithBalance((UInt256)i).TestObject;
+ _addresses[i] = Build.An.Address.FromNumber(i).TestObject;
+ }
+ }
+
+ [Test]
+ public void At_capacity()
+ {
+ Cache cache = Create();
+ for (int i = 0; i < Capacity; i++)
+ {
+ cache.Set(_addresses[i], _accounts[i]).Should().BeTrue();
+ }
+
+ Account? account = cache.Get(_addresses[Capacity - 1]);
+ Assert.That(account, Is.EqualTo(_accounts[Capacity - 1]));
+ }
+
+ [Test]
+ public void Can_reset()
+ {
+ Cache cache = Create();
+ cache.Set(_addresses[0], _accounts[0]).Should().BeTrue();
+ cache.Set(_addresses[0], _accounts[1]).Should().BeFalse();
+ cache.Get(_addresses[0]).Should().Be(_accounts[1]);
+ }
+
+ [Test]
+ public void Can_ask_before_first_set()
+ {
+ Cache cache = Create();
+ cache.Get(_addresses[0]).Should().BeNull();
+ }
+
+ [Test]
+ public void Can_clear()
+ {
+ Cache cache = Create();
+ cache.Set(_addresses[0], _accounts[0]).Should().BeTrue();
+ cache.Clear();
+ cache.Get(_addresses[0]).Should().BeNull();
+ cache.Set(_addresses[0], _accounts[1]).Should().BeTrue();
+ cache.Get(_addresses[0]).Should().Be(_accounts[1]);
+ }
+
+ [Test]
+ public void Beyond_capacity()
+ {
+ Cache cache = Create();
+ for (int i = 0; i < Capacity * 2; i++)
+ {
+ cache.Set(_addresses[i], _accounts[i]).Should().BeTrue();
+ }
+
+ Account? account = cache.Get(_addresses[Capacity]);
+ account.Should().Be(_accounts[Capacity]);
+ }
+
+ [Test]
+ public void Beyond_capacity_lru()
+ {
+ Cache cache = Create();
+ for (int i = 0; i < Capacity * 2; i++)
+ {
+ for (int ii = 0; ii < Capacity / 2; ii++)
+ {
+ cache.Set(_addresses[i], _accounts[i]);
+ }
+ cache.Set(_addresses[i], _accounts[i]);
+ }
+ }
+
+ [Test]
+ public void Can_set_and_then_set_null()
+ {
+ Cache cache = Create();
+ cache.Set(_addresses[0], _accounts[0]).Should().BeTrue();
+ cache.Set(_addresses[0], _accounts[0]).Should().BeFalse();
+ cache.Set(_addresses[0], null!).Should().BeTrue();
+ cache.Get(_addresses[0]).Should().Be(null);
+ }
+
+ [Test]
+ public void Can_delete()
+ {
+ Cache cache = Create();
+ cache.Set(_addresses[0], _accounts[0]);
+ cache.Delete(_addresses[0]).Should().BeTrue();
+ cache.Get(_addresses[0]).Should().Be(null);
+ cache.Delete(_addresses[0]).Should().BeFalse();
+ }
+
+ [Test]
+ public void Clear_should_free_all_capacity()
+ {
+ Cache cache = Create();
+ for (int i = 0; i < Capacity; i++)
+ {
+ cache.Set(_addresses[i], _accounts[i]).Should().BeTrue();
+ }
+
+ cache.Clear();
+
+ static int MapForRefill(int index) => (index + 1) % Capacity;
+
+ // fill again
+ for (int i = 0; i < Capacity; i++)
+ {
+ cache.Set(_addresses[i], _accounts[MapForRefill(i)]).Should().BeTrue();
+ }
+
+ // validate
+ for (int i = 0; i < Capacity; i++)
+ {
+ cache.Get(_addresses[i]).Should().Be(_accounts[MapForRefill(i)]);
+ }
+ }
+
+ [Test]
+ public void Delete_keeps_internal_structure()
+ {
+ int maxCapacity = 32;
+ int itemsToKeep = 10;
+ int iterations = 40;
+
+ LruCacheLowObject cache = new(maxCapacity, "test");
+
+ for (int i = 0; i < iterations; i++)
+ {
+ cache.Set(i, i).Should().BeTrue();
+ var remove = i - itemsToKeep;
+ if (remove >= 0)
+ cache.Delete(remove).Should().BeTrue();
+ }
+
+ int count = 0;
+
+ for (int i = 0; i < iterations; i++)
+ {
+ if (cache.TryGet(i, out int val))
+ {
+ count++;
+ val.Should().Be(i);
+ }
+ }
+
+ count.Should().Be(itemsToKeep);
+ }
+ }
+}
diff --git a/src/Nethermind/Nethermind.Core.Test/Caching/LruCacheTests.cs b/src/Nethermind/Nethermind.Core.Test/Caching/LruCacheTests.cs
index 35399b9e56d..95e37aa7c91 100755
--- a/src/Nethermind/Nethermind.Core.Test/Caching/LruCacheTests.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Caching/LruCacheTests.cs
@@ -39,7 +39,7 @@ public void At_capacity()
ICache cache = Create();
for (int i = 0; i < Capacity; i++)
{
- cache.Set(_addresses[i], _accounts[i]);
+ cache.Set(_addresses[i], _accounts[i]).Should().BeTrue();
}
Account? account = cache.Get(_addresses[Capacity - 1]);
@@ -50,8 +50,8 @@ public void At_capacity()
public void Can_reset()
{
ICache cache = Create();
- cache.Set(_addresses[0], _accounts[0]);
- cache.Set(_addresses[0], _accounts[1]);
+ cache.Set(_addresses[0], _accounts[0]).Should().BeTrue();
+ cache.Set(_addresses[0], _accounts[1]).Should().BeFalse();
cache.Get(_addresses[0]).Should().Be(_accounts[1]);
}
@@ -66,21 +66,35 @@ public void Can_ask_before_first_set()
public void Can_clear()
{
ICache cache = Create();
- cache.Set(_addresses[0], _accounts[0]);
+ cache.Set(_addresses[0], _accounts[0]).Should().BeTrue();
cache.Clear();
cache.Get(_addresses[0]).Should().BeNull();
- cache.Set(_addresses[0], _accounts[1]);
+ cache.Set(_addresses[0], _accounts[1]).Should().BeTrue();
cache.Get(_addresses[0]).Should().Be(_accounts[1]);
}
[Test]
- public void Beyond_capacity()
+ public void Beyond_capacity_lru()
{
ICache cache = Create();
for (int i = 0; i < Capacity * 2; i++)
{
+ for (int ii = 0; ii < Capacity / 2; ii++)
+ {
+ cache.Set(_addresses[i], _accounts[i]);
+ }
cache.Set(_addresses[i], _accounts[i]);
}
+ }
+
+ [Test]
+ public void Beyond_capacity()
+ {
+ ICache cache = Create();
+ for (int i = 0; i < Capacity * 2; i++)
+ {
+ cache.Set(_addresses[i], _accounts[i]).Should().BeTrue();
+ }
Account? account = cache.Get(_addresses[Capacity]);
account.Should().Be(_accounts[Capacity]);
diff --git a/src/Nethermind/Nethermind.Core.Test/Caching/LruKeyCacheLowObjectTests.cs b/src/Nethermind/Nethermind.Core.Test/Caching/LruKeyCacheLowObjectTests.cs
new file mode 100644
index 00000000000..cb8b07dc324
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core.Test/Caching/LruKeyCacheLowObjectTests.cs
@@ -0,0 +1,104 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using FluentAssertions;
+using Nethermind.Core.Caching;
+using Nethermind.Core.Test.Builders;
+using Nethermind.Int256;
+using NUnit.Framework;
+
+namespace Nethermind.Core.Test.Caching
+{
+ [TestFixture]
+ public class LruKeyCacheLowObjectTests
+ {
+ private const int Capacity = 16;
+
+ private readonly Account[] _accounts = new Account[Capacity * 2];
+ private readonly Address[] _addresses = new Address[Capacity * 2];
+
+ [SetUp]
+ public void Setup()
+ {
+ for (int i = 0; i < Capacity * 2; i++)
+ {
+ _accounts[i] = Build.An.Account.WithBalance((UInt256)i).TestObject;
+ _addresses[i] = Build.An.Address.FromNumber(i).TestObject;
+ }
+ }
+
+ [Test]
+ public void At_capacity()
+ {
+ LruKeyCacheLowObject cache = new(Capacity, "test");
+ for (int i = 0; i < Capacity; i++)
+ {
+ cache.Set(_addresses[i]);
+ }
+
+ cache.Get(_addresses[Capacity - 1]).Should().BeTrue();
+ }
+
+ [Test]
+ public void Can_reset()
+ {
+ LruKeyCacheLowObject cache = new(Capacity, "test");
+ cache.Set(_addresses[0]).Should().BeTrue();
+ cache.Set(_addresses[0]).Should().BeFalse();
+ cache.Get(_addresses[0]).Should().BeTrue();
+ }
+
+ [Test]
+ public void Can_ask_before_first_set()
+ {
+ LruKeyCacheLowObject cache = new(Capacity, "test");
+ cache.Get(_addresses[0]).Should().BeFalse();
+ }
+
+ [Test]
+ public void Can_clear()
+ {
+ LruKeyCacheLowObject cache = new(Capacity, "test");
+ cache.Set(_addresses[0]).Should().BeTrue();
+ cache.Clear();
+ cache.Get(_addresses[0]).Should().BeFalse();
+ cache.Set(_addresses[0]).Should().BeTrue();
+ cache.Get(_addresses[0]).Should().BeTrue();
+ }
+
+ [Test]
+ public void Beyond_capacity()
+ {
+ LruKeyCacheLowObject cache = new(Capacity, "test");
+ for (int i = 0; i < Capacity * 2; i++)
+ {
+ cache.Set(_addresses[i]);
+ }
+
+ cache.Get(_addresses[Capacity]).Should().BeTrue();
+ }
+
+ [Test]
+ public void Beyond_capacity_lru()
+ {
+ LruKeyCacheLowObject cache = new(Capacity, "test");
+ for (int i = 0; i < Capacity * 2; i++)
+ {
+ for (int ii = 0; ii < Capacity / 2; ii++)
+ {
+ cache.Set(_addresses[i]);
+ }
+ cache.Set(_addresses[i]);
+ }
+ }
+
+ [Test]
+ public void Can_delete()
+ {
+ LruKeyCacheLowObject cache = new(Capacity, "test");
+ cache.Set(_addresses[0]);
+ cache.Delete(_addresses[0]);
+ cache.Get(_addresses[0]).Should().BeFalse();
+ }
+ }
+}
diff --git a/src/Nethermind/Nethermind.Core.Test/Caching/LruKeyCacheNonConcurrentTests.cs b/src/Nethermind/Nethermind.Core.Test/Caching/LruKeyCacheNonConcurrentTests.cs
new file mode 100644
index 00000000000..614ba3cfa4e
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core.Test/Caching/LruKeyCacheNonConcurrentTests.cs
@@ -0,0 +1,104 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using FluentAssertions;
+using Nethermind.Core.Caching;
+using Nethermind.Core.Test.Builders;
+using Nethermind.Int256;
+using NUnit.Framework;
+
+namespace Nethermind.Core.Test.Caching
+{
+ [TestFixture]
+ public class LruKeyCacheNonConcurrentTests
+ {
+ private const int Capacity = 16;
+
+ private readonly Account[] _accounts = new Account[Capacity * 2];
+ private readonly Address[] _addresses = new Address[Capacity * 2];
+
+ [SetUp]
+ public void Setup()
+ {
+ for (int i = 0; i < Capacity * 2; i++)
+ {
+ _accounts[i] = Build.An.Account.WithBalance((UInt256)i).TestObject;
+ _addresses[i] = Build.An.Address.FromNumber(i).TestObject;
+ }
+ }
+
+ [Test]
+ public void At_capacity()
+ {
+ LruKeyCacheNonConcurrent cache = new(Capacity, "test");
+ for (int i = 0; i < Capacity; i++)
+ {
+ cache.Set(_addresses[i]).Should().BeTrue();
+ }
+
+ cache.Get(_addresses[Capacity - 1]).Should().BeTrue();
+ }
+
+ [Test]
+ public void Can_reset()
+ {
+ LruKeyCacheNonConcurrent cache = new(Capacity, "test");
+ cache.Set(_addresses[0]).Should().BeTrue();
+ cache.Set(_addresses[0]).Should().BeFalse();
+ cache.Get(_addresses[0]).Should().BeTrue();
+ }
+
+ [Test]
+ public void Can_ask_before_first_set()
+ {
+ LruKeyCacheNonConcurrent cache = new(Capacity, "test");
+ cache.Get(_addresses[0]).Should().BeFalse();
+ }
+
+ [Test]
+ public void Can_clear()
+ {
+ LruKeyCacheNonConcurrent cache = new(Capacity, "test");
+ cache.Set(_addresses[0]).Should().BeTrue();
+ cache.Clear();
+ cache.Get(_addresses[0]).Should().BeFalse();
+ cache.Set(_addresses[0]).Should().BeTrue();
+ cache.Get(_addresses[0]).Should().BeTrue();
+ }
+
+ [Test]
+ public void Beyond_capacity()
+ {
+ LruKeyCacheNonConcurrent cache = new(Capacity, "test");
+ for (int i = 0; i < Capacity * 2; i++)
+ {
+ cache.Set(_addresses[i]);
+ }
+
+ cache.Get(_addresses[Capacity]).Should().BeTrue();
+ }
+
+ [Test]
+ public void Beyond_capacity_lru()
+ {
+ LruKeyCacheNonConcurrent cache = new(Capacity, "test");
+ for (int i = 0; i < Capacity * 2; i++)
+ {
+ for (int ii = 0; ii < Capacity / 2; ii++)
+ {
+ cache.Set(_addresses[i]);
+ }
+ cache.Set(_addresses[i]);
+ }
+ }
+
+ [Test]
+ public void Can_delete()
+ {
+ LruKeyCacheNonConcurrent cache = new(Capacity, "test");
+ cache.Set(_addresses[0]).Should().BeTrue();
+ cache.Delete(_addresses[0]);
+ cache.Get(_addresses[0]).Should().BeFalse();
+ }
+ }
+}
diff --git a/src/Nethermind/Nethermind.Core.Test/Caching/LruKeyCacheTests.cs b/src/Nethermind/Nethermind.Core.Test/Caching/LruKeyCacheTests.cs
index 05185bfa433..5cf04410450 100644
--- a/src/Nethermind/Nethermind.Core.Test/Caching/LruKeyCacheTests.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Caching/LruKeyCacheTests.cs
@@ -33,7 +33,7 @@ public void At_capacity()
LruKeyCache cache = new(Capacity, "test");
for (int i = 0; i < Capacity; i++)
{
- cache.Set(_addresses[i]);
+ cache.Set(_addresses[i]).Should().BeTrue();
}
cache.Get(_addresses[Capacity - 1]).Should().BeTrue();
@@ -72,17 +72,31 @@ public void Beyond_capacity()
LruKeyCache cache = new(Capacity, "test");
for (int i = 0; i < Capacity * 2; i++)
{
- cache.Set(_addresses[i]);
+ cache.Set(_addresses[i]).Should().BeTrue();
}
cache.Get(_addresses[Capacity]).Should().BeTrue();
}
+ [Test]
+ public void Beyond_capacity_lru()
+ {
+ LruKeyCache cache = new(Capacity, "test");
+ for (int i = 0; i < Capacity * 2; i++)
+ {
+ for (int ii = 0; ii < Capacity / 2; ii++)
+ {
+ cache.Set(_addresses[i]);
+ }
+ cache.Set(_addresses[i]);
+ }
+ }
+
[Test]
public void Can_delete()
{
LruKeyCache cache = new(Capacity, "test");
- cache.Set(_addresses[0]);
+ cache.Set(_addresses[0]).Should().BeTrue();
cache.Delete(_addresses[0]);
cache.Get(_addresses[0]).Should().BeFalse();
}
diff --git a/src/Nethermind/Nethermind.Core.Test/Caching/SpanLruCacheTests.cs b/src/Nethermind/Nethermind.Core.Test/Caching/SpanLruCacheTests.cs
index f30d930bf53..5cf255515f4 100755
--- a/src/Nethermind/Nethermind.Core.Test/Caching/SpanLruCacheTests.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Caching/SpanLruCacheTests.cs
@@ -40,7 +40,7 @@ public void At_capacity()
ISpanCache cache = Create();
for (int i = 0; i < Capacity; i++)
{
- cache.Set(_addresses[i].Bytes, _accounts[i]);
+ cache.Set(_addresses[i].Bytes, _accounts[i]).Should().BeTrue();
}
Account? account = cache.Get(_addresses[Capacity - 1].Bytes);
@@ -51,8 +51,8 @@ public void At_capacity()
public void Can_reset()
{
ISpanCache cache = Create();
- cache.Set(_addresses[0].Bytes, _accounts[0]);
- cache.Set(_addresses[0].Bytes, _accounts[1]);
+ cache.Set(_addresses[0].Bytes, _accounts[0]).Should().BeTrue();
+ cache.Set(_addresses[0].Bytes, _accounts[1]).Should().BeFalse();
cache.Get(_addresses[0].Bytes).Should().Be(_accounts[1]);
}
@@ -67,10 +67,10 @@ public void Can_ask_before_first_set()
public void Can_clear()
{
ISpanCache cache = Create();
- cache.Set(_addresses[0].Bytes, _accounts[0]);
+ cache.Set(_addresses[0].Bytes, _accounts[0]).Should().BeTrue();
cache.Clear();
cache.Get(_addresses[0].Bytes).Should().BeNull();
- cache.Set(_addresses[0].Bytes, _accounts[1]);
+ cache.Set(_addresses[0].Bytes, _accounts[1]).Should().BeTrue();
cache.Get(_addresses[0].Bytes).Should().Be(_accounts[1]);
}
@@ -80,13 +80,27 @@ public void Beyond_capacity()
ISpanCache cache = Create();
for (int i = 0; i < Capacity * 2; i++)
{
- cache.Set(_addresses[i].Bytes, _accounts[i]);
+ cache.Set(_addresses[i].Bytes, _accounts[i]).Should().BeTrue();
}
Account? account = cache.Get(_addresses[Capacity].Bytes);
account.Should().Be(_accounts[Capacity]);
}
+ [Test]
+ public void Beyond_capacity_lru()
+ {
+ ISpanCache cache = Create();
+ for (int i = 0; i < Capacity * 2; i++)
+ {
+ for (int ii = 0; ii < Capacity / 2; ii++)
+ {
+ cache.Set(_addresses[i].Bytes, _accounts[i]);
+ }
+ cache.Set(_addresses[i].Bytes, _accounts[i]);
+ }
+ }
+
[Test]
public void Can_set_and_then_set_null()
{
@@ -101,7 +115,7 @@ public void Can_set_and_then_set_null()
public void Can_delete()
{
ISpanCache cache = Create();
- cache.Set(_addresses[0].Bytes, _accounts[0]);
+ cache.Set(_addresses[0].Bytes, _accounts[0]).Should().BeTrue();
cache.Delete(_addresses[0].Bytes).Should().BeTrue();
cache.Get(_addresses[0].Bytes).Should().Be(null);
cache.Delete(_addresses[0].Bytes).Should().BeFalse();
diff --git a/src/Nethermind/Nethermind.Core.Test/Json/UInt256DictionaryKeyConverterTests.cs b/src/Nethermind/Nethermind.Core.Test/Json/UInt256DictionaryKeyConverterTests.cs
index 533e777f8af..2f37bd6b572 100644
--- a/src/Nethermind/Nethermind.Core.Test/Json/UInt256DictionaryKeyConverterTests.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Json/UInt256DictionaryKeyConverterTests.cs
@@ -115,7 +115,7 @@ public void WriteJson_Dictionary_SerializedCorrectly()
{ new UInt256(1), new UInt256(12345) }
};
string serialised = JsonSerializer.Serialize(dictionary, Options);
-
+ serialised = serialised.Replace("\r\n", "\n");
string expected = """
{
"0x1": "0x3039"
diff --git a/src/Nethermind/Nethermind.Core.Test/KeccakTests.cs b/src/Nethermind/Nethermind.Core.Test/KeccakTests.cs
index a02f5663e31..d0bfa06581a 100644
--- a/src/Nethermind/Nethermind.Core.Test/KeccakTests.cs
+++ b/src/Nethermind/Nethermind.Core.Test/KeccakTests.cs
@@ -110,5 +110,13 @@ public void Span()
Assert.That(Keccak.Compute(byteArray.AsSpan()), Is.EqualTo(Keccak.Compute(byteArray)));
}
+
+ [TestCase("0xAAAAAAAAAAAA", "f8e06bc47a06f221f1523d3b646226e6cdb322619be1da7bafd113e459bf4140")]
+ public void Sanity_check(string hexString, string expected)
+ {
+ byte[] bytes = Bytes.FromHexString(hexString);
+ ValueHash256 h = ValueKeccak.Compute(bytes);
+ h.Bytes.ToHexString().Should().Be(expected);
+ }
}
}
diff --git a/src/Nethermind/Nethermind.Core.Test/SequenceTests.cs b/src/Nethermind/Nethermind.Core.Test/SequenceTests.cs
new file mode 100644
index 00000000000..d44ba71dda4
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core.Test/SequenceTests.cs
@@ -0,0 +1,33 @@
+// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Buffers;
+using FluentAssertions;
+using Nethermind.Core.Extensions;
+using NUnit.Framework;
+
+namespace Nethermind.Core.Test;
+
+public class SequenceTests
+{
+ [Test]
+ public void Sequence_whitespace_slice()
+ {
+ var end = new TestReadOnlySequenceSegment("\r\nabc"u8.ToArray(), 2);
+ var start = new TestReadOnlySequenceSegment(" "u8.ToArray(), 0, end);
+ ReadOnlySequence sequence = new ReadOnlySequence(start, 0, end, 5);
+
+ sequence.TrimStart().ToArray().Should().Equal("abc"u8.ToArray());
+ }
+
+ private class TestReadOnlySequenceSegment : ReadOnlySequenceSegment
+ {
+ public TestReadOnlySequenceSegment(Memory memory, long runningIndex = 0, ReadOnlySequenceSegment? next = null)
+ {
+ Memory = memory;
+ Next = next;
+ RunningIndex = runningIndex;
+ }
+ }
+}
diff --git a/src/Nethermind/Nethermind.Core/Account.cs b/src/Nethermind/Nethermind.Core/Account.cs
index 41279ec2b7b..dbe8d959740 100644
--- a/src/Nethermind/Nethermind.Core/Account.cs
+++ b/src/Nethermind/Nethermind.Core/Account.cs
@@ -154,8 +154,8 @@ public bool IsNull
//
// Method Nethermind.Core.AccountStruct:get_IsNull():bool:this (FullOpts)
// G_M000_IG01:
- // vzeroupper
- //
+ // vzeroupper
+ //
// G_M000_IG02:
// vmovups ymm0, ymmword ptr [rcx]
// vpor ymm0, ymm0, ymmword ptr [rcx+0x20]
@@ -164,10 +164,10 @@ public bool IsNull
// vptest ymm0, ymm0
// sete al
// movzx rax, al
- //
+ //
// G_M000_IG03: ;; offset=0x0021
- // vzeroupper
- // ret
+ // vzeroupper
+ // ret
// ; Total bytes of code: 37
return (Unsafe.As>(ref Unsafe.AsRef(in _balance)) |
diff --git a/src/Nethermind/Nethermind.Core/Address.cs b/src/Nethermind/Nethermind.Core/Address.cs
index d56cda23269..79acbe7d5ff 100644
--- a/src/Nethermind/Nethermind.Core/Address.cs
+++ b/src/Nethermind/Nethermind.Core/Address.cs
@@ -35,9 +35,9 @@ public class Address : IEquatable, IComparable
public byte[] Bytes { get; }
- public Address(Hash256 keccak) : this(keccak.Bytes.Slice(12, Size).ToArray()) { }
+ public Address(Hash256 hash) : this(hash.Bytes.Slice(12, Size).ToArray()) { }
- public Address(in ValueHash256 keccak) : this(keccak.BytesAsSpan.Slice(12, Size).ToArray()) { }
+ public Address(in ValueHash256 hash) : this(hash.BytesAsSpan.Slice(12, Size).ToArray()) { }
public byte this[int index] => Bytes[index];
@@ -235,6 +235,14 @@ public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destina
}
public Hash256 ToAccountPath => Keccak.Compute(Bytes);
+
+ [SkipLocalsInit]
+ public ValueHash256 ToHash()
+ {
+ Span addressBytes = stackalloc byte[Hash256.Size];
+ Bytes.CopyTo(addressBytes.Slice(Hash256.Size - Address.Size));
+ return new ValueHash256(addressBytes);
+ }
}
public readonly struct AddressAsKey(Address key) : IEquatable
diff --git a/src/Nethermind/Nethermind.Core/Block.cs b/src/Nethermind/Nethermind.Core/Block.cs
index c77e9c27c5c..609455b96d3 100644
--- a/src/Nethermind/Nethermind.Core/Block.cs
+++ b/src/Nethermind/Nethermind.Core/Block.cs
@@ -7,6 +7,8 @@
using System.Linq;
using System.Text;
using Nethermind.Core.ConsensusRequests;
+using System.Text.Json.Serialization;
+using Nethermind.Core.Collections;
using Nethermind.Core.Crypto;
using Nethermind.Int256;
@@ -117,6 +119,10 @@ public Transaction[] Transactions
public Hash256? RequestsRoot => Header.RequestsRoot; // do not add setter here
+ [JsonIgnore]
+ public ArrayPoolList? AccountChanges { get; set; }
+ [JsonIgnore]
+ internal volatile int TransactionProcessed;
public override string ToString() => ToString(Format.Short);
diff --git a/src/Nethermind/Nethermind.Core/Bloom.cs b/src/Nethermind/Nethermind.Core/Bloom.cs
index 7437a25286c..f980e1b4a0e 100644
--- a/src/Nethermind/Nethermind.Core/Bloom.cs
+++ b/src/Nethermind/Nethermind.Core/Bloom.cs
@@ -126,9 +126,10 @@ public void Add(LogEntry[] logEntries, Bloom? blockBloom = null)
LogEntry logEntry = logEntries[entryIndex];
byte[] addressBytes = logEntry.LoggersAddress.Bytes;
Set(addressBytes, blockBloom);
- for (int topicIndex = 0; topicIndex < logEntry.Topics.Length; topicIndex++)
+ Hash256[] topics = logEntry.Topics;
+ for (int topicIndex = 0; topicIndex < topics.Length; topicIndex++)
{
- Hash256 topic = logEntry.Topics[topicIndex];
+ Hash256 topic = topics[topicIndex];
Set(topic.Bytes, blockBloom);
}
}
@@ -148,9 +149,10 @@ public bool Matches(LogEntry logEntry)
{
if (Matches(logEntry.LoggersAddress))
{
- for (int topicIndex = 0; topicIndex < logEntry.Topics.Length; topicIndex++)
+ Hash256[] topics = logEntry.Topics;
+ for (int topicIndex = 0; topicIndex < topics.Length; topicIndex++)
{
- if (!Matches(logEntry.Topics[topicIndex]))
+ if (!Matches(topics[topicIndex]))
{
return false;
}
@@ -285,9 +287,10 @@ public readonly bool Matches(LogEntry logEntry)
{
if (Matches(logEntry.LoggersAddress))
{
- for (int topicIndex = 0; topicIndex < logEntry.Topics.Length; topicIndex++)
+ Hash256[] topics = logEntry.Topics;
+ for (int topicIndex = 0; topicIndex < topics.Length; topicIndex++)
{
- if (!Matches(logEntry.Topics[topicIndex]))
+ if (!Matches(topics[topicIndex]))
{
return false;
}
diff --git a/src/Nethermind/Nethermind.Core/Buffers/CappedArray.cs b/src/Nethermind/Nethermind.Core/Buffers/CappedArray.cs
index 0d909d05077..9dfa54cf9a0 100644
--- a/src/Nethermind/Nethermind.Core/Buffers/CappedArray.cs
+++ b/src/Nethermind/Nethermind.Core/Buffers/CappedArray.cs
@@ -110,4 +110,14 @@ public readonly Span AsSpan(int start, int length)
if (_length == array.Length) return array;
return AsSpan().ToArray();
}
+
+ public readonly ArraySegment AsArraySegment()
+ {
+ return AsArraySegment(0, _length);
+ }
+
+ public readonly ArraySegment AsArraySegment(int start, int length)
+ {
+ return new ArraySegment(_array!, start, length);
+ }
}
diff --git a/src/Nethermind/Nethermind.Core/Caching/LinkedListNode.cs b/src/Nethermind/Nethermind.Core/Caching/LinkedListNode.cs
index 93011a77bb6..7a882123e39 100644
--- a/src/Nethermind/Nethermind.Core/Caching/LinkedListNode.cs
+++ b/src/Nethermind/Nethermind.Core/Caching/LinkedListNode.cs
@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
+using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
@@ -21,7 +22,10 @@ public static void MoveToMostRecent([NotNull] ref LinkedListNode? leastRecent
{
if (node.Next == node)
{
- Debug.Assert(leastRecentlyUsed == node, "this should only be true for a list with only one node");
+ if (leastRecentlyUsed != node)
+ {
+ InvalidNotSingleNodeList();
+ }
// Do nothing only one node
}
else
@@ -33,10 +37,16 @@ public static void MoveToMostRecent([NotNull] ref LinkedListNode? leastRecent
public static void Remove(ref LinkedListNode? leastRecentlyUsed, LinkedListNode node)
{
- Debug.Assert(leastRecentlyUsed is not null, "This method shouldn't be called on empty list!");
+ if (leastRecentlyUsed is null)
+ {
+ InvalidRemoveFromEmptyList();
+ }
if (node.Next == node)
{
- Debug.Assert(leastRecentlyUsed == node, "this should only be true for a list with only one node");
+ if (leastRecentlyUsed != node)
+ {
+ InvalidNotSingleNodeList();
+ }
leastRecentlyUsed = null;
}
else
@@ -48,6 +58,20 @@ public static void Remove(ref LinkedListNode? leastRecentlyUsed, LinkedListNo
leastRecentlyUsed = node.Next;
}
}
+
+ [DoesNotReturn]
+ [StackTraceHidden]
+ static void InvalidRemoveFromEmptyList()
+ {
+ throw new InvalidOperationException("This method shouldn't be called on empty list");
+ }
+ }
+
+ [DoesNotReturn]
+ [StackTraceHidden]
+ static void InvalidNotSingleNodeList()
+ {
+ throw new InvalidOperationException("This should only be true for a list with only one node");
}
public static void AddMostRecent([NotNull] ref LinkedListNode? leastRecentlyUsed, LinkedListNode node)
diff --git a/src/Nethermind/Nethermind.Core/Caching/LruCacheLowObject.cs b/src/Nethermind/Nethermind.Core/Caching/LruCacheLowObject.cs
new file mode 100644
index 00000000000..bbdceab425f
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core/Caching/LruCacheLowObject.cs
@@ -0,0 +1,274 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using Nethermind.Core.Threading;
+
+namespace Nethermind.Core.Caching
+{
+ public sealed class LruCacheLowObject
+ where TKey : struct, IEquatable
+ {
+ private readonly int _maxCapacity;
+ private readonly Dictionary _cacheMap;
+ private readonly McsLock _lock = new();
+ private readonly string _name;
+ private int _leastRecentlyUsed = -1;
+ private Stack _freeOffsets = new();
+ private readonly LruCacheItem[] _items;
+
+ public LruCacheLowObject(int maxCapacity, string name)
+ {
+ ArgumentOutOfRangeException.ThrowIfLessThan(maxCapacity, 1);
+
+ _name = name;
+ _maxCapacity = maxCapacity;
+ _cacheMap = new Dictionary(maxCapacity / 2);
+ _items = new LruCacheItem[maxCapacity];
+ }
+
+ public void Clear()
+ {
+ using var lockRelease = _lock.Acquire();
+
+ _leastRecentlyUsed = -1;
+ _cacheMap.Clear();
+ _freeOffsets.Clear();
+ if (RuntimeHelpers.IsReferenceOrContainsReferences())
+ {
+ _items.AsSpan().Clear();
+ }
+ }
+
+ public TValue Get(TKey key)
+ {
+ using var lockRelease = _lock.Acquire();
+
+ if (_cacheMap.TryGetValue(key, out int offset))
+ {
+ ref var node = ref _items[offset];
+ TValue value = node.Value;
+ MoveToMostRecent(ref node, offset);
+ return value;
+ }
+
+ return default!;
+ }
+
+ public bool TryGet(TKey key, out TValue value)
+ {
+ using var lockRelease = _lock.Acquire();
+
+ if (_cacheMap.TryGetValue(key, out int offset))
+ {
+ ref var node = ref _items[offset];
+ value = node.Value;
+ MoveToMostRecent(ref node, offset);
+ return true;
+ }
+
+ value = default!;
+ return false;
+ }
+
+ public bool Set(TKey key, TValue val)
+ {
+ using var lockRelease = _lock.Acquire();
+
+ if (val is null)
+ {
+ return DeleteNoLock(key);
+ }
+
+ if (_cacheMap.TryGetValue(key, out int offset))
+ {
+ ref var node = ref _items[offset];
+ node.Value = val;
+ MoveToMostRecent(ref node, offset);
+ return false;
+ }
+
+ if (_cacheMap.Count >= _maxCapacity)
+ {
+ Replace(key, val);
+ }
+ else
+ {
+ if (_freeOffsets.Count > 0)
+ {
+ offset = _freeOffsets.Pop();
+ }
+ else
+ {
+ offset = _cacheMap.Count;
+ }
+ ref LruCacheItem newNode = ref _items[offset];
+ newNode = new(key, val);
+ AddMostRecent(ref newNode, offset);
+ _cacheMap.Add(key, offset);
+ }
+
+ return true;
+ }
+
+ public bool Delete(TKey key)
+ {
+ using var lockRelease = _lock.Acquire();
+
+ return DeleteNoLock(key);
+ }
+
+ private bool DeleteNoLock(TKey key)
+ {
+ if (_cacheMap.TryGetValue(key, out int offset))
+ {
+ ref var node = ref _items[offset];
+ Remove(ref node, offset);
+ _cacheMap.Remove(key);
+ node = default;
+ _freeOffsets.Push(offset);
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool Contains(TKey key)
+ {
+ using var lockRelease = _lock.Acquire();
+
+ return _cacheMap.ContainsKey(key);
+ }
+
+ public int Size
+ {
+ get
+ {
+ return _cacheMap.Count;
+ }
+ }
+
+ private void Replace(TKey key, TValue value)
+ {
+ if (_leastRecentlyUsed < 0)
+ {
+ ThrowInvalidOperationException();
+ }
+
+ int offset = _leastRecentlyUsed;
+ ref var node = ref _items[offset];
+
+ _cacheMap.Remove(node.Key);
+ node = new(key, value)
+ {
+ Next = node.Next,
+ Prev = node.Prev
+ };
+
+ MoveToMostRecent(ref node, offset);
+ _cacheMap.Add(key, offset);
+
+ [DoesNotReturn]
+ static void ThrowInvalidOperationException()
+ {
+ throw new InvalidOperationException(
+ $"{nameof(LruCache)} called {nameof(Replace)} when empty.");
+ }
+ }
+
+
+ private void MoveToMostRecent(ref LruCacheItem node, int offset)
+ {
+ if (node.Next == offset)
+ {
+ if (_leastRecentlyUsed != offset)
+ {
+ InvalidNotSingleNodeList();
+ }
+ // Do nothing only one node
+ }
+ else
+ {
+ Remove(ref node, offset);
+ AddMostRecent(ref node, offset);
+ }
+ }
+
+ private void Remove(ref LruCacheItem node, int offset)
+ {
+ if (_leastRecentlyUsed < 0)
+ {
+ InvalidRemoveFromEmptyList();
+ }
+ if (node.Next == offset)
+ {
+ if (_leastRecentlyUsed != offset)
+ {
+ InvalidNotSingleNodeList();
+ }
+ _leastRecentlyUsed = -1;
+ }
+ else
+ {
+ _items[node.Next].Prev = node.Prev;
+ _items[node.Prev].Next = node.Next;
+ if (_leastRecentlyUsed == offset)
+ {
+ _leastRecentlyUsed = node.Next;
+ }
+ }
+
+ static void InvalidRemoveFromEmptyList()
+ {
+ throw new InvalidOperationException("This method shouldn't be called on empty list");
+ }
+ }
+
+ [DoesNotReturn]
+ [StackTraceHidden]
+ static void InvalidNotSingleNodeList()
+ {
+ throw new InvalidOperationException("This should only be true for a list with only one node");
+ }
+
+ private void AddMostRecent(ref LruCacheItem node, int offset)
+ {
+ if (_leastRecentlyUsed < 0)
+ {
+ SetFirst(ref node, offset);
+ }
+ else
+ {
+ InsertMostRecent(ref node, offset);
+ }
+ }
+
+ private void InsertMostRecent(ref LruCacheItem newNode, int offset)
+ {
+ newNode.Next = _leastRecentlyUsed;
+ ref var node = ref _items[_leastRecentlyUsed];
+ newNode.Prev = node.Prev;
+ _items[node.Prev].Next = offset;
+ node.Prev = offset;
+ }
+
+ private void SetFirst(ref LruCacheItem newNode, int offset)
+ {
+ newNode.Next = offset;
+ newNode.Prev = offset;
+ _leastRecentlyUsed = offset;
+ }
+
+ private struct LruCacheItem(TKey k, TValue v)
+ {
+ public readonly TKey Key = k;
+ public TValue Value = v;
+ public int Next;
+ public int Prev;
+ }
+ }
+}
diff --git a/src/Nethermind/Nethermind.Core/Caching/LruKeyCache.cs b/src/Nethermind/Nethermind.Core/Caching/LruKeyCache.cs
index cc58f807a16..d5f25705b0b 100644
--- a/src/Nethermind/Nethermind.Core/Caching/LruKeyCache.cs
+++ b/src/Nethermind/Nethermind.Core/Caching/LruKeyCache.cs
@@ -109,17 +109,5 @@ static void ThrowInvalidOperation()
$"{nameof(LruKeyCache)} called {nameof(Replace)} when empty.");
}
}
-
- public long MemorySize => CalculateMemorySize(0, _cacheMap.Count);
-
- // TODO: memory size on the KeyCache will be smaller because we do not create LruCacheItems
- public static long CalculateMemorySize(int keyPlusValueSize, int currentItemsCount)
- {
- // it may actually be different if the initial capacity not equal to max (depending on the dictionary growth path)
-
- const int preInit = 48 /* LinkedList */ + 80 /* Dictionary */ + 24;
- int postInit = 52 /* lazy init of two internal dictionary arrays + dictionary size times (entry size + int) */ + MemorySizes.FindNextPrime(currentItemsCount) * 28 + currentItemsCount * 80 /* LinkedListNode and CacheItem times items count */;
- return MemorySizes.Align(preInit + postInit + keyPlusValueSize * currentItemsCount);
- }
}
}
diff --git a/src/Nethermind/Nethermind.Core/Caching/LruKeyCacheLowObject.cs b/src/Nethermind/Nethermind.Core/Caching/LruKeyCacheLowObject.cs
new file mode 100644
index 00000000000..dd8e3af89eb
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core/Caching/LruKeyCacheLowObject.cs
@@ -0,0 +1,248 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using Nethermind.Core.Threading;
+
+namespace Nethermind.Core.Caching
+{
+ public sealed class LruKeyCacheLowObject
+ where TKey : struct, IEquatable
+ {
+ private readonly int _maxCapacity;
+ private readonly Dictionary _cacheMap;
+ private readonly McsLock _lock = new();
+ private readonly string _name;
+ private int _leastRecentlyUsed = -1;
+ private Stack _freeOffsets = new();
+ private readonly LruCacheItem[] _items;
+
+ public LruKeyCacheLowObject(int maxCapacity, string name)
+ {
+ ArgumentOutOfRangeException.ThrowIfLessThan(maxCapacity, 1);
+
+ _name = name;
+ _maxCapacity = maxCapacity;
+ _cacheMap = new Dictionary(maxCapacity / 2); // do not initialize it at the full capacity
+ _items = new LruCacheItem[maxCapacity];
+ }
+
+ public void Clear()
+ {
+ using var lockRelease = _lock.Acquire();
+
+ _leastRecentlyUsed = -1;
+ _cacheMap.Clear();
+ _freeOffsets.Clear();
+ if (RuntimeHelpers.IsReferenceOrContainsReferences())
+ {
+ _items.AsSpan().Clear();
+ }
+ }
+
+ public bool Get(TKey key)
+ {
+ using var lockRelease = _lock.Acquire();
+
+ if (_cacheMap.TryGetValue(key, out int offset))
+ {
+ ref var node = ref _items[offset];
+ MoveToMostRecent(ref node, offset);
+ return true;
+ }
+
+ return false!;
+ }
+
+ public bool Set(TKey key)
+ {
+ using var lockRelease = _lock.Acquire();
+
+ if (_cacheMap.TryGetValue(key, out int offset))
+ {
+ ref var node = ref _items[offset];
+ MoveToMostRecent(ref node, offset);
+ return false;
+ }
+
+ if (_cacheMap.Count >= _maxCapacity)
+ {
+ Replace(key);
+ }
+ else
+ {
+ if (_freeOffsets.Count > 0)
+ {
+ offset = _freeOffsets.Pop();
+ }
+ else
+ {
+ offset = _cacheMap.Count;
+ }
+ ref LruCacheItem newNode = ref _items[offset];
+ newNode = new(key);
+ AddMostRecent(ref newNode, offset);
+ _cacheMap.Add(key, offset);
+ }
+
+ return true;
+ }
+
+ public void Delete(TKey key)
+ {
+ using var lockRelease = _lock.Acquire();
+
+ DeleteNoLock(key);
+ }
+
+ private bool DeleteNoLock(TKey key)
+ {
+ if (_cacheMap.TryGetValue(key, out int offset))
+ {
+ ref var node = ref _items[offset];
+ Remove(ref node, offset);
+ _cacheMap.Remove(key);
+ node = default;
+ _freeOffsets.Push(offset);
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool Contains(TKey key)
+ {
+ using var lockRelease = _lock.Acquire();
+
+ return _cacheMap.ContainsKey(key);
+ }
+
+ public int Size
+ {
+ get
+ {
+ return _cacheMap.Count;
+ }
+ }
+
+ private void Replace(TKey key)
+ {
+ if (_leastRecentlyUsed < 0)
+ {
+ ThrowInvalidOperationException();
+ }
+
+ int offset = _leastRecentlyUsed;
+ ref var node = ref _items[offset];
+
+ _cacheMap.Remove(node.Key);
+ node = new(key)
+ {
+ Next = node.Next,
+ Prev = node.Prev
+ };
+
+ MoveToMostRecent(ref node, offset);
+ _cacheMap.Add(key, offset);
+
+ [DoesNotReturn]
+ static void ThrowInvalidOperationException()
+ {
+ throw new InvalidOperationException($"Called {nameof(Replace)} when empty.");
+ }
+ }
+
+ private void MoveToMostRecent(ref LruCacheItem node, int offset)
+ {
+ if (node.Next == offset)
+ {
+ if (_leastRecentlyUsed != offset)
+ {
+ InvalidNotSingleNodeList();
+ }
+ // Do nothing only one node
+ }
+ else
+ {
+ Remove(ref node, offset);
+ AddMostRecent(ref node, offset);
+ }
+ }
+
+ private void Remove(ref LruCacheItem node, int offset)
+ {
+ if (_leastRecentlyUsed < 0)
+ {
+ InvalidRemoveFromEmptyList();
+ }
+ if (node.Next == offset)
+ {
+ if (_leastRecentlyUsed != offset)
+ {
+ InvalidNotSingleNodeList();
+ }
+ _leastRecentlyUsed = -1;
+ }
+ else
+ {
+ _items[node.Next].Prev = node.Prev;
+ _items[node.Prev].Next = node.Next;
+ if (_leastRecentlyUsed == offset)
+ {
+ _leastRecentlyUsed = node.Next;
+ }
+ }
+
+ static void InvalidRemoveFromEmptyList()
+ {
+ throw new InvalidOperationException("This method shouldn't be called on empty list");
+ }
+ }
+
+ [DoesNotReturn]
+ [StackTraceHidden]
+ static void InvalidNotSingleNodeList()
+ {
+ throw new InvalidOperationException("This should only be true for a list with only one node");
+ }
+
+ private void AddMostRecent(ref LruCacheItem node, int offset)
+ {
+ if (_leastRecentlyUsed < 0)
+ {
+ SetFirst(ref node, offset);
+ }
+ else
+ {
+ InsertMostRecent(ref node, offset);
+ }
+ }
+
+ private void InsertMostRecent(ref LruCacheItem newNode, int offset)
+ {
+ newNode.Next = _leastRecentlyUsed;
+ ref var node = ref _items[_leastRecentlyUsed];
+ newNode.Prev = node.Prev;
+ _items[node.Prev].Next = offset;
+ node.Prev = offset;
+ }
+
+ private void SetFirst(ref LruCacheItem newNode, int offset)
+ {
+ newNode.Next = offset;
+ newNode.Prev = offset;
+ _leastRecentlyUsed = offset;
+ }
+
+ private struct LruCacheItem(TKey k)
+ {
+ public readonly TKey Key = k;
+ public int Next;
+ public int Prev;
+ }
+ }
+}
diff --git a/src/Nethermind/Nethermind.Core/Caching/LruKeyCacheNonConcurrent.cs b/src/Nethermind/Nethermind.Core/Caching/LruKeyCacheNonConcurrent.cs
new file mode 100644
index 00000000000..ef5a2e49d2b
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core/Caching/LruKeyCacheNonConcurrent.cs
@@ -0,0 +1,115 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using Nethermind.Core.Extensions;
+
+namespace Nethermind.Core.Caching
+{
+ public sealed class LruKeyCacheNonConcurrent where TKey : notnull
+ {
+ private readonly int _maxCapacity;
+ private readonly string _name;
+ private readonly Dictionary> _cacheMap;
+ private LinkedListNode? _leastRecentlyUsed;
+
+ public LruKeyCacheNonConcurrent(int maxCapacity, int startCapacity, string name)
+ {
+ _maxCapacity = maxCapacity;
+ _name = name ?? throw new ArgumentNullException(nameof(name));
+ _cacheMap = typeof(TKey) == typeof(byte[])
+ ? new Dictionary>((IEqualityComparer)Bytes.EqualityComparer)
+ : new Dictionary>(startCapacity); // do not initialize it at the full capacity
+ }
+
+ public LruKeyCacheNonConcurrent(int maxCapacity, string name)
+ : this(maxCapacity, 0, name)
+ {
+ }
+
+ public void Clear()
+ {
+ _leastRecentlyUsed = null;
+ _cacheMap.Clear();
+ }
+
+ public bool Get(TKey key)
+ {
+ if (_cacheMap.TryGetValue(key, out LinkedListNode? node))
+ {
+ LinkedListNode.MoveToMostRecent(ref _leastRecentlyUsed, node);
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool Set(TKey key)
+ {
+ if (_cacheMap.TryGetValue(key, out LinkedListNode? node))
+ {
+ LinkedListNode.MoveToMostRecent(ref _leastRecentlyUsed, node);
+ return false;
+ }
+ else
+ {
+ if (_cacheMap.Count >= _maxCapacity)
+ {
+ Replace(key);
+ }
+ else
+ {
+ LinkedListNode newNode = new(key);
+ LinkedListNode.AddMostRecent(ref _leastRecentlyUsed, newNode);
+ _cacheMap.Add(key, newNode);
+ }
+
+ return true;
+ }
+ }
+
+ public void Delete(TKey key)
+ {
+ if (_cacheMap.TryGetValue(key, out LinkedListNode