From 49e4fd860290cd31e52be536df7751089b359f7e Mon Sep 17 00:00:00 2001 From: matkt Date: Thu, 7 Jul 2022 18:27:44 +0200 Subject: [PATCH 001/109] fix parent world state is not available issue on bonsai (#4069) Signed-off-by: Karim TAAM --- CHANGELOG.md | 4 +- .../bonsai/BonsaiPersistedWorldState.java | 17 ++++--- .../bonsai/BonsaiWorldStateArchiveTest.java | 49 +++++++++++++++++++ 3 files changed, 63 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f89af17c25b..c43b55ba33e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ ### Additions and Improvements +### Bug Fixes +- Fixed a trie log layer issue on bonsai during reorg [#4069](https://github.com/hyperledger/besu/pull/4069) + ## 22.7.0-RC1 ### Additions and Improvements @@ -11,7 +14,6 @@ - When on PoS the head can be only be updated by ForkchoiceUpdate [#3994](https://github.com/hyperledger/besu/pull/3994) - Version information available in metrics [#3997](https://github.com/hyperledger/besu/pull/3997) - Add TTD and DNS to Sepolia config [#4024](https://github.com/hyperledger/besu/pull/4024) -- Add terminal block hash and number to Ropsten genesis file [#4026](https://github.com/hyperledger/besu/pull/4026) - Return `type` with value `0x0` when serializing legacy transactions [#4027](https://github.com/hyperledger/besu/pull/4027) - Ignore `ForkchoiceUpdate` if `newHead` is an ancestor of the chain head [#4055](https://github.com/hyperledger/besu/pull/4055) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiPersistedWorldState.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiPersistedWorldState.java index 7ab3df82ece..9fd7b479b07 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiPersistedWorldState.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiPersistedWorldState.java @@ -252,9 +252,17 @@ public void persist(final BlockHeader blockHeader) { // then persist the TrieLog for that transition. // If specified but not a direct descendant simply store the new block hash. if (blockHeader != null) { - final TrieLogLayer trieLog = - prepareTrieLog(blockHeader, localUpdater, newWorldStateRootHash); - persistTrieLog(blockHeader, newWorldStateRootHash, trieLog, stateUpdater); + // do not overwrite a trielog layer that already exists in the database. + // if it's only in memory we need to save it + // for example, like that in case of reorg we don't replace a trielog layer + if (worldStateStorage.getTrieLog(blockHeader.getHash()).isEmpty()) { + final TrieLogLayer trieLog = + prepareTrieLog(blockHeader, localUpdater, newWorldStateRootHash); + persistTrieLog(blockHeader, newWorldStateRootHash, trieLog, stateUpdater); + } + stateUpdater + .getTrieBranchStorageTransaction() + .put(WORLD_BLOCK_HASH_KEY, blockHeader.getHash().toArrayUnsafe()); worldStateBlockHash = blockHeader.getHash(); } else { stateUpdater.getTrieBranchStorageTransaction().remove(WORLD_BLOCK_HASH_KEY); @@ -310,9 +318,6 @@ private void persistTrieLog( "Persisting trie log for block hash {} and world state root {}", blockHeader::toLogString, worldStateRootHash::toHexString); - stateUpdater - .getTrieBranchStorageTransaction() - .put(WORLD_BLOCK_HASH_KEY, blockHeader.getHash().toArrayUnsafe()); final BytesValueRLPOutput rlpLog = new BytesValueRLPOutput(); trieLog.writeTo(rlpLog); stateUpdater diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchiveTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchiveTest.java index 57da55cda1b..925b0e548cd 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchiveTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchiveTest.java @@ -21,6 +21,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -200,4 +201,52 @@ public void testGetMutableWithStorageConsistencyToRollbackAndRollForwardTheState verify(updater, times(1)).rollBack(any()); verify(updater, times(1)).rollForward(any()); } + + @SuppressWarnings({"unchecked"}) + @Test + public void testGetMutableWithRollbackNotOverrideTrieLogLayer() { + final KeyValueStorageTransaction keyValueStorageTransaction = + mock(KeyValueStorageTransaction.class); + when(keyValueStorage.startTransaction()).thenReturn(keyValueStorageTransaction); + final BlockHeader genesis = blockBuilder.number(0).buildHeader(); + final BlockHeader blockHeaderChainA = + blockBuilder.number(1).timestamp(1).parentHash(genesis.getHash()).buildHeader(); + final BlockHeader blockHeaderChainB = + blockBuilder.number(1).timestamp(2).parentHash(genesis.getHash()).buildHeader(); + + final Map layeredWorldStatesByHash = mock(HashMap.class); + when(layeredWorldStatesByHash.containsKey(any(Bytes32.class))).thenReturn(true); + when(layeredWorldStatesByHash.get(eq(blockHeaderChainA.getHash()))) + .thenReturn(mock(BonsaiLayeredWorldState.class, Answers.RETURNS_MOCKS)); + when(layeredWorldStatesByHash.get(eq(blockHeaderChainB.getHash()))) + .thenReturn(mock(BonsaiLayeredWorldState.class, Answers.RETURNS_MOCKS)); + + bonsaiWorldStateArchive = + spy(new BonsaiWorldStateArchive(storageProvider, blockchain, 12, layeredWorldStatesByHash)); + var updater = spy(bonsaiWorldStateArchive.getUpdater()); + when(bonsaiWorldStateArchive.getUpdater()).thenReturn(updater); + + // initial persisted state hash key + when(blockchain.getBlockHeader(eq(Hash.ZERO))).thenReturn(Optional.of(blockHeaderChainA)); + // fake trie log layer + final BytesValueRLPOutput rlpLogBlockB = new BytesValueRLPOutput(); + final TrieLogLayer trieLogLayerBlockB = new TrieLogLayer(); + trieLogLayerBlockB.setBlockHash(blockHeaderChainB.getHash()); + trieLogLayerBlockB.writeTo(rlpLogBlockB); + when(keyValueStorage.get(blockHeaderChainB.getHash().toArrayUnsafe())) + .thenReturn(Optional.of(rlpLogBlockB.encoded().toArrayUnsafe())); + + when(blockchain.getBlockHeader(eq(blockHeaderChainB.getHash()))) + .thenReturn(Optional.of(blockHeaderChainB)); + when(blockchain.getBlockHeader(eq(genesis.getHash()))).thenReturn(Optional.of(genesis)); + + assertThat(bonsaiWorldStateArchive.getMutable(null, blockHeaderChainB.getHash())) + .containsInstanceOf(BonsaiPersistedWorldState.class); + + // verify is not persisting if already present + verify(keyValueStorageTransaction, never()) + .put(eq(blockHeaderChainA.getHash().toArrayUnsafe()), any()); + verify(keyValueStorageTransaction, never()) + .put(eq(blockHeaderChainB.getHash().toArrayUnsafe()), any()); + } } From 93b877002272e76b24571eec8996ed595f52c905 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 8 Jul 2022 11:19:36 +0200 Subject: [PATCH 002/109] After merge add a rule to check that the current block is more recent than its parent (#4066) * After merge add a rule to check that the current block is more recent than its parent Signed-off-by: Fabio Di Fabio * Update CHANGELOG Signed-off-by: Fabio Di Fabio * Unit test Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 3 +- .../merge/MergeValidationRulesetFactory.java | 4 +- .../IncrementalTimestampRule.java | 51 +++++++++++ .../MergeConsensusRule.java | 2 +- .../merge/blockcreation/MergeReorgTest.java | 2 + .../IncrementalTimestampValidationTest.java | 89 +++++++++++++++++++ .../backwardsync/BackwardSyncContext.java | 3 +- 7 files changed, 149 insertions(+), 5 deletions(-) create mode 100644 consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/headervalidationrules/IncrementalTimestampRule.java create mode 100644 consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/headervalidationrules/IncrementalTimestampValidationTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index c43b55ba33e..7c9631fedf1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ ### Additions and Improvements ### Bug Fixes +- Return the correct latest valid hash in case of bad block when calling engine methods [#4056](https://github.com/hyperledger/besu/pull/4056) +- Add a PoS block header rule to check that the current block is more recent than its parent [#4066](https://github.com/hyperledger/besu/pull/4066) - Fixed a trie log layer issue on bonsai during reorg [#4069](https://github.com/hyperledger/besu/pull/4069) ## 22.7.0-RC1 @@ -22,7 +24,6 @@ - Support free gas networks in the London fee market [#4003](https://github.com/hyperledger/besu/pull/4003) - Limit the size of outgoing eth subprotocol messages. [#4034](https://github.com/hyperledger/besu/pull/4034) - Fixed a state root mismatch issue on bonsai that may appear occasionally [#4041](https://github.com/hyperledger/besu/pull/4041) -- Return the correct latest valid hash in case of bad block when calling engine methods [#4056](https://github.com/hyperledger/besu/pull/4056) ### Download links - https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/22.7.0-RC1/besu-22.7.0-RC1.tar.gz / sha256: `60ad8b53402beb62c24ad791799d9cfe444623a58f6f6cf1d0728459cb641e63` diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeValidationRulesetFactory.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeValidationRulesetFactory.java index 447937bf7da..1c26bdcd50d 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeValidationRulesetFactory.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeValidationRulesetFactory.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.consensus.merge; import org.hyperledger.besu.consensus.merge.headervalidationrules.ConstantOmmersHashRule; +import org.hyperledger.besu.consensus.merge.headervalidationrules.IncrementalTimestampRule; import org.hyperledger.besu.consensus.merge.headervalidationrules.MergeUnfinalizedValidationRule; import org.hyperledger.besu.consensus.merge.headervalidationrules.NoDifficultyRule; import org.hyperledger.besu.consensus.merge.headervalidationrules.NoNonceRule; @@ -59,7 +60,8 @@ public static BlockHeaderValidator.Builder mergeBlockHeaderValidator(final FeeMa .addRule(new MergeUnfinalizedValidationRule()) .addRule(new ConstantOmmersHashRule()) .addRule(new NoNonceRule()) - .addRule(new NoDifficultyRule()); + .addRule(new NoDifficultyRule()) + .addRule(new IncrementalTimestampRule()); } } } diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/headervalidationrules/IncrementalTimestampRule.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/headervalidationrules/IncrementalTimestampRule.java new file mode 100644 index 00000000000..c09c8e23943 --- /dev/null +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/headervalidationrules/IncrementalTimestampRule.java @@ -0,0 +1,51 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hyperledger.besu.consensus.merge.headervalidationrules; + +import static org.hyperledger.besu.consensus.merge.TransitionUtils.isTerminalProofOfWorkBlock; + +import org.hyperledger.besu.ethereum.ProtocolContext; +import org.hyperledger.besu.ethereum.core.BlockHeader; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class IncrementalTimestampRule extends MergeConsensusRule { + + private static final Logger LOG = LoggerFactory.getLogger(IncrementalTimestampRule.class); + + @Override + public boolean validate( + final BlockHeader header, final BlockHeader parent, final ProtocolContext protocolContext) { + + if (super.shouldUsePostMergeRules(header, protocolContext) + && !isTerminalProofOfWorkBlock(header, protocolContext)) { + final long blockTimestamp = header.getTimestamp(); + final long parentTimestamp = parent.getTimestamp(); + final boolean isMoreRecent = blockTimestamp > parentTimestamp; + + LOG.trace( + "Is block timestamp more recent that its parent? {}, [block timestamp {}, parent timestamp {}]", + isMoreRecent, + blockTimestamp, + parentTimestamp); + + return isMoreRecent; + } else { + return true; + } + } +} diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/headervalidationrules/MergeConsensusRule.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/headervalidationrules/MergeConsensusRule.java index 37faa0dfc01..c4131efa7cf 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/headervalidationrules/MergeConsensusRule.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/headervalidationrules/MergeConsensusRule.java @@ -56,7 +56,7 @@ protected boolean shouldUsePostMergeRules( if (parentChainTotalDifficulty .get() .add(header.getDifficulty() == null ? Difficulty.ZERO : header.getDifficulty()) - .greaterThan(configuredTotalTerminalDifficulty)) { + .greaterOrEqualThan(configuredTotalTerminalDifficulty)) { return true; } else { // still PoWing return false; diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java index 3ced3e74965..50fbb03a4bc 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java @@ -169,6 +169,7 @@ private List subChain( 0, 15000000)) .gasLimit(newParent.getGasLimit()) + .timestamp(newParent.getTimestamp() + 1) .stateRoot(newParent.getStateRoot()); if (each.greaterOrEqualThan(Difficulty.ZERO)) { headerGenerator.difficulty(each); @@ -194,6 +195,7 @@ private BlockHeader terminalPowBlock(final BlockHeader parent, final Difficulty 0, 15000000l)) .gasLimit(parent.getGasLimit()) + .timestamp(parent.getTimestamp() + 1) .stateRoot(parent.getStateRoot()) .buildHeader(); return terminal; diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/headervalidationrules/IncrementalTimestampValidationTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/headervalidationrules/IncrementalTimestampValidationTest.java new file mode 100644 index 00000000000..a4fbcdfecd8 --- /dev/null +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/headervalidationrules/IncrementalTimestampValidationTest.java @@ -0,0 +1,89 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hyperledger.besu.consensus.merge.headervalidationrules; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.consensus.merge.MergeContext; +import org.hyperledger.besu.ethereum.ProtocolContext; +import org.hyperledger.besu.ethereum.chain.MutableBlockchain; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.Difficulty; + +import java.util.Optional; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class IncrementalTimestampValidationTest { + + @Mock private ProtocolContext protocolContext; + @Mock private MutableBlockchain blockchain; + @Mock private MergeContext mergeContext; + + @Before + public void setUp() { + when(blockchain.getTotalDifficultyByHash(any())).thenReturn(Optional.of(Difficulty.ONE)); + when(protocolContext.getBlockchain()).thenReturn(blockchain); + when(mergeContext.getTerminalTotalDifficulty()).thenReturn(Difficulty.ZERO); + when(protocolContext.getConsensusContext(MergeContext.class)).thenReturn(mergeContext); + } + + @Test + public void validWhenTimestampMoreRecentThanParent() { + final IncrementalTimestampRule rule = new IncrementalTimestampRule(); + final long now = System.currentTimeMillis(); + final BlockHeader parentHeader = mock(BlockHeader.class); + when(parentHeader.getTimestamp()).thenReturn(now); + final BlockHeader validHeader = mock(BlockHeader.class); + when(validHeader.getNumber()).thenReturn(1337L); + when(validHeader.getTimestamp()).thenReturn(now + 1); + + assertThat(rule.validate(validHeader, parentHeader, protocolContext)).isTrue(); + } + + @Test + public void invalidWhenTimestampNotMoreRecentThanParent() { + final IncrementalTimestampRule rule = new IncrementalTimestampRule(); + final long now = System.currentTimeMillis(); + final BlockHeader parentHeader = mock(BlockHeader.class); + when(parentHeader.getTimestamp()).thenReturn(now); + final BlockHeader validHeader = mock(BlockHeader.class); + when(validHeader.getNumber()).thenReturn(1337L); + when(validHeader.getTimestamp()).thenReturn(now); + + assertThat(rule.validate(validHeader, parentHeader, protocolContext)).isFalse(); + } + + @Test + public void alwaysValidWhenTTDNotReached() { + when(mergeContext.getTerminalTotalDifficulty()).thenReturn(Difficulty.of(2L)); + + final IncrementalTimestampRule rule = new IncrementalTimestampRule(); + final BlockHeader parentHeader = mock(BlockHeader.class); + final BlockHeader validHeader = mock(BlockHeader.class); + when(validHeader.getNumber()).thenReturn(1337L); + + assertThat(rule.validate(validHeader, parentHeader, protocolContext)).isTrue(); + } +} diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java index fd9a42e6bc3..55e779a70fd 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java @@ -261,11 +261,10 @@ protected Void saveBlock(final Block block) { getBackwardChain().addBadChainToManager(badBlocksManager, block.getHash()); throw new BackwardSyncException( "Cannot save block " - + block.getHash() + + block.toLogString() + " because of " + optResult.errorMessage.orElseThrow()); } - optResult.blockProcessingOutputs.ifPresent(result -> {}); return null; } From 08fedc68637ca87ff50b9d103355e26c52c26917 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Sat, 9 Jul 2022 01:59:23 +0200 Subject: [PATCH 003/109] Fix transition protocol schedule (#4078) * Fix to return pre-merge protocol schedule when block difficulty is less that TTD Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 1 + .../merge/TransitionProtocolSchedule.java | 3 +- .../merge/TransitionProtocolScheduleTest.java | 150 ++++++++++++++++++ 3 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/TransitionProtocolScheduleTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c9631fedf1..9e7b1f21eec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Return the correct latest valid hash in case of bad block when calling engine methods [#4056](https://github.com/hyperledger/besu/pull/4056) - Add a PoS block header rule to check that the current block is more recent than its parent [#4066](https://github.com/hyperledger/besu/pull/4066) - Fixed a trie log layer issue on bonsai during reorg [#4069](https://github.com/hyperledger/besu/pull/4069) +- Fix transition protocol schedule to return the pre Merge schedule when reorg pre TTD [#4078](https://github.com/hyperledger/besu/pull/4078) ## 22.7.0-RC1 diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java index 5c05a501044..75e03ae4dfb 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java @@ -86,8 +86,7 @@ public ProtocolSpec getByBlockHeader( () -> thisDifficulty); // if this block is pre-merge or a TTD block - if ((thisDifficulty.lessOrEqualThan(terminalDifficulty) - && thisDifficulty.greaterThan(parentDifficulty)) + if (thisDifficulty.lessThan(terminalDifficulty) || TransitionUtils.isTerminalProofOfWorkBlock(blockHeader, protocolContext)) { debugLambda( LOG, diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/TransitionProtocolScheduleTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/TransitionProtocolScheduleTest.java new file mode 100644 index 00000000000..66aa2a31ce0 --- /dev/null +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/TransitionProtocolScheduleTest.java @@ -0,0 +1,150 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.consensus.merge; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.ProtocolContext; +import org.hyperledger.besu.ethereum.chain.MutableBlockchain; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; + +import java.util.Optional; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class TransitionProtocolScheduleTest { + + @Mock ProtocolContext protocolContext; + @Mock MutableBlockchain blockchain; + @Mock MergeContext mergeContext; + @Mock ProtocolSchedule preMergeProtocolSchedule; + @Mock ProtocolSchedule postMergeProtocolSchedule; + @Mock BlockHeader blockHeader; + + private static final Difficulty TTD = Difficulty.of(100L); + private static final long BLOCK_NUMBER = 29L; + private TransitionProtocolSchedule transitionProtocolSchedule; + + @Before + public void setUp() { + when(protocolContext.getBlockchain()).thenReturn(blockchain); + when(protocolContext.getConsensusContext(MergeContext.class)).thenReturn(mergeContext); + when(mergeContext.getTerminalTotalDifficulty()).thenReturn(TTD); + + transitionProtocolSchedule = + new TransitionProtocolSchedule( + preMergeProtocolSchedule, postMergeProtocolSchedule, mergeContext); + } + + @Test + public void returnPostMergeIfFinalizedExists() { + when(mergeContext.getFinalized()).thenReturn(Optional.of(mock(BlockHeader.class))); + when(blockHeader.getNumber()).thenReturn(BLOCK_NUMBER); + + transitionProtocolSchedule.getByBlockHeader(protocolContext, blockHeader); + + verifyPostMergeProtocolScheduleReturned(); + } + + @Test + public void returnPreMergeIfBeforeMerge() { + when(mergeContext.getFinalized()).thenReturn(Optional.empty()); + when(mergeContext.isPostMerge()).thenReturn(false); + + when(blockHeader.getNumber()).thenReturn(BLOCK_NUMBER); + + transitionProtocolSchedule.getByBlockHeader(protocolContext, blockHeader); + + verifyPreMergeProtocolScheduleReturned(); + } + + @Test + public void returnPreMergeIfTerminalPoWBlock() { + + when(mergeContext.getFinalized()).thenReturn(Optional.empty()); + when(mergeContext.isPostMerge()).thenReturn(true); + + final Hash parentHash = Hash.fromHexStringLenient("0xabc123"); + + when(blockHeader.getNumber()).thenReturn(BLOCK_NUMBER); + when(blockHeader.getParentHash()).thenReturn(parentHash); + when(blockHeader.getDifficulty()).thenReturn(Difficulty.of(10L)); + when(blockchain.getTotalDifficultyByHash(parentHash)) + .thenReturn(Optional.of(Difficulty.of(95L))); + + transitionProtocolSchedule.getByBlockHeader(protocolContext, blockHeader); + + verifyPreMergeProtocolScheduleReturned(); + } + + @Test + public void returnPreMergeIfAfterMergeButReorgPreTTD() { + + when(mergeContext.getFinalized()).thenReturn(Optional.empty()); + when(mergeContext.isPostMerge()).thenReturn(true); + + final Hash parentHash = Hash.fromHexStringLenient("0xabc123"); + + when(blockHeader.getNumber()).thenReturn(BLOCK_NUMBER); + when(blockHeader.getParentHash()).thenReturn(parentHash); + when(blockHeader.getDifficulty()).thenReturn(Difficulty.of(2L)); + when(blockchain.getTotalDifficultyByHash(parentHash)) + .thenReturn(Optional.of(Difficulty.of(95L))); + + transitionProtocolSchedule.getByBlockHeader(protocolContext, blockHeader); + + verifyPreMergeProtocolScheduleReturned(); + } + + @Test + public void returnPostMergeIfAfterMergeButReorgPostTTD() { + + when(mergeContext.getFinalized()).thenReturn(Optional.empty()); + when(mergeContext.isPostMerge()).thenReturn(true); + + final Hash parentHash = Hash.fromHexStringLenient("0xabc123"); + + when(blockHeader.getNumber()).thenReturn(BLOCK_NUMBER); + when(blockHeader.getParentHash()).thenReturn(parentHash); + when(blockHeader.getDifficulty()).thenReturn(Difficulty.ZERO); + when(blockchain.getTotalDifficultyByHash(parentHash)) + .thenReturn(Optional.of(Difficulty.of(105L))); + + transitionProtocolSchedule.getByBlockHeader(protocolContext, blockHeader); + + verifyPostMergeProtocolScheduleReturned(); + } + + private void verifyPreMergeProtocolScheduleReturned() { + verify(preMergeProtocolSchedule).getByBlockNumber(BLOCK_NUMBER); + verifyNoInteractions(postMergeProtocolSchedule); + } + + private void verifyPostMergeProtocolScheduleReturned() { + verify(postMergeProtocolSchedule).getByBlockNumber(BLOCK_NUMBER); + verifyNoInteractions(preMergeProtocolSchedule); + } +} From a60a286f9318f982d9eff12eda40dceeb2f85513 Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Mon, 11 Jul 2022 09:03:37 +1000 Subject: [PATCH 004/109] no need to register peers connect/disconnect for Snap as well (#4073) Signed-off-by: Sally MacFarlane --- .../eth/manager/snap/SnapProtocolManager.java | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/SnapProtocolManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/SnapProtocolManager.java index b6873a76808..314801b5a45 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/SnapProtocolManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/SnapProtocolManager.java @@ -42,7 +42,6 @@ public class SnapProtocolManager implements ProtocolManager { private static final Logger LOG = LoggerFactory.getLogger(SnapProtocolManager.class); - private final List peerValidators; private final List supportedCapabilities; private final EthPeers ethPeers; private final EthMessages snapMessages; @@ -52,7 +51,6 @@ public SnapProtocolManager( final EthPeers ethPeers, final EthMessages snapMessages, final WorldStateArchive worldStateArchive) { - this.peerValidators = peerValidators; this.ethPeers = ethPeers; this.snapMessages = snapMessages; this.supportedCapabilities = calculateCapabilities(); @@ -136,21 +134,11 @@ public void processMessage(final Capability cap, final Message message) { } @Override - public void handleNewConnection(final PeerConnection connection) { - ethPeers.registerConnection(connection, peerValidators); - } + public void handleNewConnection(final PeerConnection connection) {} @Override public void handleDisconnect( final PeerConnection connection, final DisconnectReason reason, - final boolean initiatedByPeer) { - ethPeers.registerDisconnect(connection); - LOG.debug( - "Disconnect - {} - {} - {} - {} peers left", - initiatedByPeer ? "Inbound" : "Outbound", - reason, - connection.getPeerInfo(), - ethPeers.peerCount()); - } + final boolean initiatedByPeer) {} } From 1a62d2a6c22e5fbd452cb39b29a6f66956c60990 Mon Sep 17 00:00:00 2001 From: Justin Florentine Date: Mon, 11 Jul 2022 13:34:39 -0400 Subject: [PATCH 005/109] 3943 stop blocks on finalized (#4058) * adds interfaces for tracking merge state and forchoices * after 2 finalizations from fcu, disconnect any peers sending new blocks, or connecting with td > ttd * tests for preventing pow peers from joining * refactored to separate out merge logic Signed-off-by: Justin Florentine --- .../controller/BesuControllerBuilder.java | 8 +- ...onsensusScheduleBesuControllerBuilder.java | 7 +- .../IbftLegacyBesuControllerBuilder.java | 4 +- .../MergeBesuControllerBuilder.java | 46 +++++++- .../TransitionBesuControllerBuilder.java | 5 +- .../protocol/Istanbul99ProtocolManager.java | 2 + .../merge/FinalizedBlockHashSupplier.java | 3 +- .../besu/consensus/merge/MergeContext.java | 16 +-- .../consensus/merge/PostMergeContext.java | 15 +-- .../consensus/merge/TransitionContext.java | 8 +- .../consensus/merge/PostMergeContextTest.java | 8 +- .../merge/ForkchoiceMessageListener.java | 29 +++++ .../consensus/merge/MergeStateHandler.java | 26 +++++ .../eth/manager/EthProtocolManager.java | 24 ++++- .../ethereum/eth/manager/MergePeerFilter.java | 102 ++++++++++++++++++ .../task/AbstractRetryingPeerTask.java | 2 +- .../eth/manager/task/WaitForPeersTask.java | 4 +- .../eth/manager/EthProtocolManagerTest.java | 83 +++++++++++--- .../manager/EthProtocolManagerTestUtil.java | 36 +++++++ .../ethereum/eth/transactions/TestNode.java | 2 + .../TransactionPoolFactoryTest.java | 1 + 21 files changed, 368 insertions(+), 63 deletions(-) create mode 100644 ethereum/eth/src/main/java/org/hyperledger/besu/consensus/merge/ForkchoiceMessageListener.java create mode 100644 ethereum/eth/src/main/java/org/hyperledger/besu/consensus/merge/MergeStateHandler.java create mode 100644 ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/MergePeerFilter.java diff --git a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java index 2ba399ed82f..f74c33db83a 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java @@ -49,6 +49,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; +import org.hyperledger.besu.ethereum.eth.manager.MergePeerFilter; import org.hyperledger.besu.ethereum.eth.manager.snap.SnapProtocolManager; import org.hyperledger.besu.ethereum.eth.peervalidation.CheckpointBlocksPeerValidator; import org.hyperledger.besu.ethereum.eth.peervalidation.ClassicForkPeerValidator; @@ -401,7 +402,8 @@ public BesuController build() { ethContext, ethMessages, scheduler, - peerValidators); + peerValidators, + Optional.empty()); final Optional maybeSnapProtocolManager = createSnapProtocolManager(peerValidators, ethPeers, snapMessages, worldStateArchive); @@ -559,7 +561,8 @@ protected EthProtocolManager createEthProtocolManager( final EthContext ethContext, final EthMessages ethMessages, final EthScheduler scheduler, - final List peerValidators) { + final List peerValidators, + final Optional mergePeerFilter) { return new EthProtocolManager( protocolContext.getBlockchain(), networkId, @@ -570,6 +573,7 @@ protected EthProtocolManager createEthProtocolManager( ethMessages, ethContext, peerValidators, + mergePeerFilter, fastSyncEnabled, scheduler, genesisConfig.getForks()); diff --git a/besu/src/main/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilder.java index 45f21195135..ecf42731f3a 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilder.java @@ -46,6 +46,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; +import org.hyperledger.besu.ethereum.eth.manager.MergePeerFilter; import org.hyperledger.besu.ethereum.eth.manager.snap.SnapProtocolManager; import org.hyperledger.besu.ethereum.eth.peervalidation.PeerValidator; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; @@ -232,7 +233,8 @@ protected EthProtocolManager createEthProtocolManager( final EthContext ethContext, final EthMessages ethMessages, final EthScheduler scheduler, - final List peerValidators) { + final List peerValidators, + final Optional mergePeerFilter) { return besuControllerBuilderSchedule .get(0L) .createEthProtocolManager( @@ -244,7 +246,8 @@ protected EthProtocolManager createEthProtocolManager( ethContext, ethMessages, scheduler, - peerValidators); + peerValidators, + mergePeerFilter); } @Override diff --git a/besu/src/main/java/org/hyperledger/besu/controller/IbftLegacyBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/IbftLegacyBesuControllerBuilder.java index e595411007c..fe3e405f51c 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/IbftLegacyBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/IbftLegacyBesuControllerBuilder.java @@ -36,6 +36,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; +import org.hyperledger.besu.ethereum.eth.manager.MergePeerFilter; import org.hyperledger.besu.ethereum.eth.manager.snap.SnapProtocolManager; import org.hyperledger.besu.ethereum.eth.peervalidation.PeerValidator; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; @@ -125,7 +126,8 @@ protected EthProtocolManager createEthProtocolManager( final EthContext ethContext, final EthMessages ethMessages, final EthScheduler scheduler, - final List peerValidators) { + final List peerValidators, + final Optional mergePeerFilter) { LOG.info("Operating on IBFT-1.0 network."); return new Istanbul99ProtocolManager( protocolContext.getBlockchain(), diff --git a/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java index 6519e2f31a5..1876de302ee 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java @@ -25,7 +25,13 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.MiningParameters; +import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; +import org.hyperledger.besu.ethereum.eth.manager.EthContext; +import org.hyperledger.besu.ethereum.eth.manager.EthMessages; +import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; +import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; +import org.hyperledger.besu.ethereum.eth.manager.MergePeerFilter; import org.hyperledger.besu.ethereum.eth.peervalidation.PeerValidator; import org.hyperledger.besu.ethereum.eth.peervalidation.RequiredBlocksPeerValidator; import org.hyperledger.besu.ethereum.eth.sync.backwardsync.BackwardChain; @@ -62,7 +68,6 @@ protected MiningCoordinator createMiningCoordinator( transactionPool, miningParameters, syncState, - ethProtocolManager, new BackwardSyncContext( protocolContext, protocolSchedule, @@ -73,13 +78,50 @@ protected MiningCoordinator createMiningCoordinator( storageProvider, ScheduleBasedBlockHeaderFunctions.create(protocolSchedule)))); } + @Override + protected EthProtocolManager createEthProtocolManager( + final ProtocolContext protocolContext, + final boolean fastSyncEnabled, + final TransactionPool transactionPool, + final EthProtocolConfiguration ethereumWireProtocolConfiguration, + final EthPeers ethPeers, + final EthContext ethContext, + final EthMessages ethMessages, + final EthScheduler scheduler, + final List peerValidators, + final Optional mergePeerFilter) { + + if (mergePeerFilter.isPresent()) { + protocolContext + .getConsensusContext(MergeContext.class) + .observeNewIsPostMergeState(mergePeerFilter.get()); + protocolContext + .getConsensusContext(MergeContext.class) + .addNewForkchoiceMessageListener(mergePeerFilter.get()); + } + + EthProtocolManager ethProtocolManager = + super.createEthProtocolManager( + protocolContext, + fastSyncEnabled, + transactionPool, + ethereumWireProtocolConfiguration, + ethPeers, + ethContext, + ethMessages, + scheduler, + peerValidators, + mergePeerFilter); + + return ethProtocolManager; + } + protected MiningCoordinator createTransitionMiningCoordinator( final ProtocolSchedule protocolSchedule, final ProtocolContext protocolContext, final TransactionPool transactionPool, final MiningParameters miningParameters, final SyncState syncState, - final EthProtocolManager ethProtocolManager, final BackwardSyncContext backwardSyncContext) { this.syncState.set(syncState); diff --git a/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java index 3e257cbc30c..a859ee65e89 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java @@ -114,7 +114,6 @@ protected MiningCoordinator createMiningCoordinator( transactionPool, transitionMiningParameters, syncState, - ethProtocolManager, transitionBackwardsSyncContext)); initTransitionWatcher(protocolContext, composedCoordinator); return composedCoordinator; @@ -150,8 +149,8 @@ private void initTransitionWatcher( PostMergeContext postMergeContext = protocolContext.getConsensusContext(PostMergeContext.class); postMergeContext.observeNewIsPostMergeState( - newIsPostMergeState -> { - if (newIsPostMergeState) { + (isPoS, difficultyStoppedAt) -> { + if (isPoS) { // if we transitioned to post-merge, stop and disable any mining composedCoordinator.getPreMergeObject().disable(); composedCoordinator.getPreMergeObject().stop(); diff --git a/consensus/ibftlegacy/src/main/java/org/hyperledger/besu/consensus/ibftlegacy/protocol/Istanbul99ProtocolManager.java b/consensus/ibftlegacy/src/main/java/org/hyperledger/besu/consensus/ibftlegacy/protocol/Istanbul99ProtocolManager.java index bf0a7a1799f..d52cbef4b3e 100644 --- a/consensus/ibftlegacy/src/main/java/org/hyperledger/besu/consensus/ibftlegacy/protocol/Istanbul99ProtocolManager.java +++ b/consensus/ibftlegacy/src/main/java/org/hyperledger/besu/consensus/ibftlegacy/protocol/Istanbul99ProtocolManager.java @@ -30,6 +30,7 @@ import java.math.BigInteger; import java.util.List; +import java.util.Optional; /** This allows for interoperability with Quorum, but shouldn't be used otherwise. */ public class Istanbul99ProtocolManager extends EthProtocolManager { @@ -56,6 +57,7 @@ public Istanbul99ProtocolManager( ethMessages, ethContext, peerValidators, + Optional.empty(), fastSyncEnabled, scheduler); } diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/FinalizedBlockHashSupplier.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/FinalizedBlockHashSupplier.java index 46d9172cabc..7fe3317cc6c 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/FinalizedBlockHashSupplier.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/FinalizedBlockHashSupplier.java @@ -14,7 +14,6 @@ */ package org.hyperledger.besu.consensus.merge; -import org.hyperledger.besu.consensus.merge.MergeContext.NewForkchoiceMessageListener; import org.hyperledger.besu.datatypes.Hash; import java.util.Optional; @@ -24,7 +23,7 @@ import org.slf4j.LoggerFactory; public class FinalizedBlockHashSupplier - implements Supplier>, NewForkchoiceMessageListener { + implements Supplier>, ForkchoiceMessageListener { private static final Logger LOG = LoggerFactory.getLogger(FinalizedBlockHashSupplier.class); private volatile Optional lastAnnouncedFinalizedBlockHash = Optional.empty(); diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeContext.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeContext.java index ba6af5b0dd8..069c84ae4ba 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeContext.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeContext.java @@ -36,10 +36,9 @@ public interface MergeContext extends ConsensusContext { boolean isSyncing(); - void observeNewIsPostMergeState(final NewMergeStateCallback newMergeStateCallback); + void observeNewIsPostMergeState(final MergeStateHandler mergeStateHandler); - long addNewForkchoiceMessageListener( - final NewForkchoiceMessageListener newForkchoiceMessageListener); + long addNewForkchoiceMessageListener(final ForkchoiceMessageListener forkchoiceMessageListener); void removeNewForkchoiceMessageListener(final long subscriberId); @@ -67,15 +66,4 @@ void fireNewUnverifiedForkchoiceMessageEvent( final Hash headBlockHash, final Optional maybeFinalizedBlockHash, final Hash safeBlockHash); - - interface NewMergeStateCallback { - void onNewIsPostMergeState(final boolean newIsPostMergeState); - } - - interface NewForkchoiceMessageListener { - void onNewForkchoiceMessage( - final Hash headBlockHash, - final Optional maybeFinalizedBlockHash, - final Hash safeBlockHash); - } } diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PostMergeContext.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PostMergeContext.java index 3babd1bf85e..ab9b1cde600 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PostMergeContext.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PostMergeContext.java @@ -41,9 +41,9 @@ public class PostMergeContext implements MergeContext { // initial postMerge state is indeterminate until it is set: private final AtomicReference> isPostMerge = new AtomicReference<>(Optional.empty()); - private final Subscribers newMergeStateCallbackSubscribers = + private final Subscribers newMergeStateCallbackSubscribers = Subscribers.create(); - private final Subscribers newForkchoiceMessageCallbackSubscribers = + private final Subscribers newForkchoiceMessageCallbackSubscribers = Subscribers.create(); private final EvictingQueue blocksInProgress = @@ -99,7 +99,8 @@ public void setIsPostMerge(final Difficulty totalDifficulty) { if (oldState.isEmpty() || oldState.get() != newState) { newMergeStateCallbackSubscribers.forEach( - newMergeStateCallback -> newMergeStateCallback.onNewIsPostMergeState(newState)); + newMergeStateCallback -> + newMergeStateCallback.mergeStateChanged(newState, Optional.of(totalDifficulty))); } } @@ -123,14 +124,14 @@ public boolean isSyncing() { } @Override - public void observeNewIsPostMergeState(final NewMergeStateCallback newMergeStateCallback) { - newMergeStateCallbackSubscribers.subscribe(newMergeStateCallback); + public void observeNewIsPostMergeState(final MergeStateHandler mergeStateHandler) { + newMergeStateCallbackSubscribers.subscribe(mergeStateHandler); } @Override public long addNewForkchoiceMessageListener( - final NewForkchoiceMessageListener newForkchoiceMessageListener) { - return newForkchoiceMessageCallbackSubscribers.subscribe(newForkchoiceMessageListener); + final ForkchoiceMessageListener forkchoiceMessageListener) { + return newForkchoiceMessageCallbackSubscribers.subscribe(forkchoiceMessageListener); } @Override diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionContext.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionContext.java index 79cb554902d..9a53186c119 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionContext.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionContext.java @@ -68,14 +68,14 @@ public boolean isSyncing() { } @Override - public void observeNewIsPostMergeState(final NewMergeStateCallback newMergeStateCallback) { - postMergeContext.observeNewIsPostMergeState(newMergeStateCallback); + public void observeNewIsPostMergeState(final MergeStateHandler mergeStateHandler) { + postMergeContext.observeNewIsPostMergeState(mergeStateHandler); } @Override public long addNewForkchoiceMessageListener( - final NewForkchoiceMessageListener newForkchoiceMessageListener) { - return postMergeContext.addNewForkchoiceMessageListener(newForkchoiceMessageListener); + final ForkchoiceMessageListener forkchoiceMessageListener) { + return postMergeContext.addNewForkchoiceMessageListener(forkchoiceMessageListener); } @Override diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/PostMergeContextTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/PostMergeContextTest.java index 4c548efc728..6505d6f2e6e 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/PostMergeContextTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/PostMergeContextTest.java @@ -22,7 +22,6 @@ import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; -import org.hyperledger.besu.consensus.merge.MergeContext.NewMergeStateCallback; import org.hyperledger.besu.consensus.merge.blockcreation.PayloadIdentifier; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -169,12 +168,13 @@ public void tryingToRetrieveABlockPutButEvictedReturnsEmpty() { assertThat(postMergeContext.retrieveBlockById(evictedPayloadId)).isEmpty(); } - private static class MergeStateChangeCollector implements NewMergeStateCallback { + private static class MergeStateChangeCollector implements MergeStateHandler { final List stateChanges = new ArrayList<>(); @Override - public void onNewIsPostMergeState(final boolean newIsPostMergeState) { - stateChanges.add(newIsPostMergeState); + public void mergeStateChanged( + final boolean isPoS, final Optional difficultyStoppedAt) { + stateChanges.add(isPoS); } public void reset() { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/consensus/merge/ForkchoiceMessageListener.java b/ethereum/eth/src/main/java/org/hyperledger/besu/consensus/merge/ForkchoiceMessageListener.java new file mode 100644 index 00000000000..0ebced15eb8 --- /dev/null +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/consensus/merge/ForkchoiceMessageListener.java @@ -0,0 +1,29 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.hyperledger.besu.consensus.merge; + +import org.hyperledger.besu.datatypes.Hash; + +import java.util.Optional; + +public interface ForkchoiceMessageListener { + + void onNewForkchoiceMessage( + final Hash headBlockHash, + final Optional maybeFinalizedBlockHash, + final Hash safeBlockHash); +} diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/consensus/merge/MergeStateHandler.java b/ethereum/eth/src/main/java/org/hyperledger/besu/consensus/merge/MergeStateHandler.java new file mode 100644 index 00000000000..4dd8210eadd --- /dev/null +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/consensus/merge/MergeStateHandler.java @@ -0,0 +1,26 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.hyperledger.besu.consensus.merge; + +import org.hyperledger.besu.ethereum.core.Difficulty; + +import java.util.Optional; + +public interface MergeStateHandler { + + void mergeStateChanged(final boolean isPoS, final Optional difficultyStoppedAt); +} diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java index d27037b663e..c6a3d54f475 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java @@ -73,6 +73,7 @@ public class EthProtocolManager implements ProtocolManager, MinedBlockObserver { private final List peerValidators; // The max size of messages (in bytes) private final int maxMessageSize; + private final Optional mergePeerFilter; public EthProtocolManager( final Blockchain blockchain, @@ -84,6 +85,7 @@ public EthProtocolManager( final EthMessages ethMessages, final EthContext ethContext, final List peerValidators, + final Optional mergePeerFilter, final boolean fastSyncEnabled, final EthScheduler scheduler, final ForkIdManager forkIdManager) { @@ -92,9 +94,9 @@ public EthProtocolManager( this.scheduler = scheduler; this.blockchain = blockchain; this.maxMessageSize = ethereumWireProtocolConfiguration.getMaxMessageSize(); - + this.mergePeerFilter = mergePeerFilter; this.shutdown = new CountDownLatch(1); - genesisHash = blockchain.getBlockHashByNumber(0L).get(); + this.genesisHash = blockchain.getBlockHashByNumber(0L).orElse(Hash.ZERO); this.forkIdManager = forkIdManager; @@ -131,6 +133,7 @@ public EthProtocolManager( final EthMessages ethMessages, final EthContext ethContext, final List peerValidators, + final Optional mergePeerFilter, final boolean fastSyncEnabled, final EthScheduler scheduler) { this( @@ -143,6 +146,7 @@ public EthProtocolManager( ethMessages, ethContext, peerValidators, + mergePeerFilter, fastSyncEnabled, scheduler, new ForkIdManager( @@ -161,6 +165,7 @@ public EthProtocolManager( final EthMessages ethMessages, final EthContext ethContext, final List peerValidators, + final Optional mergePeerFilter, final boolean fastSyncEnabled, final EthScheduler scheduler, final List forks) { @@ -174,6 +179,7 @@ public EthProtocolManager( ethMessages, ethContext, peerValidators, + mergePeerFilter, fastSyncEnabled, scheduler, new ForkIdManager( @@ -240,7 +246,7 @@ public void processMessage(final Capability cap, final Message message) { final EthPeer ethPeer = ethPeers.peer(message.getConnection()); if (ethPeer == null) { LOG.debug( - "Ignoring message received from unknown peer connection: " + message.getConnection()); + "Ignoring message received from unknown peer connection: {}", message.getConnection()); return; } @@ -271,6 +277,13 @@ public void processMessage(final Capability cap, final Message message) { return; } + if (this.mergePeerFilter.isPresent()) { + if (this.mergePeerFilter.get().disconnectIfGossipingBlocks(message, ethPeer)) { + handleDisconnect(ethPeer.getConnection(), DisconnectReason.SUBPROTOCOL_TRIGGERED, false); + return; + } + } + final EthMessage ethMessage = new EthMessage(ethPeer, messageData); if (!ethPeer.validateReceivedMessage(ethMessage, getSupportedProtocol())) { @@ -377,6 +390,11 @@ private void handleStatusMessage(final EthPeer peer, final MessageData data) { networkId, status.genesisHash()); peer.disconnect(DisconnectReason.SUBPROTOCOL_TRIGGERED); + } else if (mergePeerFilter.isPresent()) { + boolean disconnected = mergePeerFilter.get().disconnectIfPoW(status, peer); + if (disconnected) { + handleDisconnect(peer.getConnection(), DisconnectReason.SUBPROTOCOL_TRIGGERED, false); + } } else { LOG.debug("Received status message from {}: {}", peer, status); peer.registerStatusReceived( diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/MergePeerFilter.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/MergePeerFilter.java new file mode 100644 index 00000000000..884bf78253f --- /dev/null +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/MergePeerFilter.java @@ -0,0 +1,102 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.hyperledger.besu.ethereum.eth.manager; + +import org.hyperledger.besu.consensus.merge.ForkchoiceMessageListener; +import org.hyperledger.besu.consensus.merge.MergeStateHandler; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.eth.messages.EthPV62; +import org.hyperledger.besu.ethereum.eth.messages.StatusMessage; +import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Message; +import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage.DisconnectReason; + +import java.util.Optional; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.StampedLock; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MergePeerFilter implements MergeStateHandler, ForkchoiceMessageListener { + + private Optional powTerminalDifficulty = Optional.of(Difficulty.MAX_VALUE); + private final StampedLock powTerminalDifficultyLock = new StampedLock(); + private Hash lastFinalized = Hash.ZERO; + private final AtomicLong numFinalizedSeen = new AtomicLong(0); + private static final Logger LOG = LoggerFactory.getLogger(MergePeerFilter.class); + + public boolean disconnectIfPoW(final StatusMessage status, final EthPeer peer) { + long lockStamp = this.powTerminalDifficultyLock.readLock(); + try { + if (this.powTerminalDifficulty.isPresent() + && status.totalDifficulty().greaterThan(this.powTerminalDifficulty.get())) { + LOG.debug( + "Disconnecting peer with difficulty {}, likely still on PoW chain", + status.totalDifficulty()); + peer.disconnect(DisconnectReason.SUBPROTOCOL_TRIGGERED); + return true; + } else { + return false; + } + } finally { + this.powTerminalDifficultyLock.unlockRead(lockStamp); + } + } + + public boolean disconnectIfGossipingBlocks(final Message message, final EthPeer peer) { + final int code = message.getData().getCode(); + if (isFinalized() && (code == EthPV62.NEW_BLOCK || code == EthPV62.NEW_BLOCK_HASHES)) { + LOG.debug("disconnecting peer for sending new blocks after transition to PoS"); + peer.disconnect(DisconnectReason.SUBPROTOCOL_TRIGGERED); + return true; + } else { + return false; + } + } + + private boolean isFinalized() { + return this.numFinalizedSeen.get() > 1; + } + + @Override + public void onNewForkchoiceMessage( + final Hash headBlockHash, + final Optional maybeFinalizedBlockHash, + final Hash safeBlockHash) { + if (maybeFinalizedBlockHash.isPresent() + && !maybeFinalizedBlockHash.get().equals(this.lastFinalized)) { + this.lastFinalized = maybeFinalizedBlockHash.get(); + this.numFinalizedSeen.getAndIncrement(); + LOG.debug("have seen {} finalized blocks", this.numFinalizedSeen); + } + } + + @Override + public void mergeStateChanged( + final boolean isPoS, final Optional difficultyStoppedAt) { + if (isPoS && difficultyStoppedAt.isPresent()) { + LOG.debug("terminal difficulty set to {}", difficultyStoppedAt.get().getValue()); + long lockStamp = this.powTerminalDifficultyLock.writeLock(); + try { + this.powTerminalDifficulty = difficultyStoppedAt; + } finally { + this.powTerminalDifficultyLock.unlockWrite(lockStamp); + } + } + } +} diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTask.java index 0e2d923ec10..5822ee367d8 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTask.java @@ -113,7 +113,7 @@ protected void handleTaskError(final Throwable error) { } if (cause instanceof NoAvailablePeersException) { - LOG.info( + LOG.debug( "No useful peer found, checking remaining current peers for usefulness: {}", ethContext.getEthPeers().peerCount()); // Wait for new peer to connect diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/WaitForPeersTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/WaitForPeersTask.java index 8bd6cd71648..6cfd3d719d9 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/WaitForPeersTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/WaitForPeersTask.java @@ -60,11 +60,11 @@ protected void executeTask() { (peer) -> { final int peerCount = ethPeers.peerCount(); if (peerCount >= targetPeerCount) { - LOG.info("Complete: {} peers connected.", targetPeerCount); + LOG.debug("Complete: {} peers connected.", targetPeerCount); // We hit our target result.complete(null); } else { - LOG.info( + LOG.debug( "Waiting for {} total peers to connect. {} peers currently connected.", targetPeerCount, peerCount); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java index 2fefaff37b8..1f4eaaef172 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java @@ -65,6 +65,7 @@ import org.hyperledger.besu.ethereum.p2p.rlpx.wire.DefaultMessage; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.RawMessage; +import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage.DisconnectReason; import org.hyperledger.besu.ethereum.worldstate.DataStorageFormat; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; @@ -77,6 +78,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -219,6 +221,55 @@ public void disconnectOnVeryLargeMessage() { } } + @Test + public void disconnectNewPoWPeers() { + MergePeerFilter mergePeerFilter = new MergePeerFilter(); + try (final EthProtocolManager ethManager = + EthProtocolManagerTestUtil.create( + blockchain, + protocolContext.getWorldStateArchive(), + transactionPool, + EthProtocolConfiguration.defaultConfig(), + Optional.of(mergePeerFilter))) { + + final MockPeerConnection workPeer = setupPeer(ethManager, (cap, msg, conn) -> {}); + final MockPeerConnection stakePeer = setupPeer(ethManager, (cap, msg, conn) -> {}); + + final StatusMessage workPeerStatus = + StatusMessage.create( + EthProtocol.EthVersion.V63, + BigInteger.ONE, + blockchain.getChainHead().getTotalDifficulty().add(20), + blockchain.getChainHeadHash(), + blockchain.getBlockHeader(BlockHeader.GENESIS_BLOCK_NUMBER).get().getHash()); + + final StatusMessage stakePeerStatus = + StatusMessage.create( + EthProtocol.EthVersion.V63, + BigInteger.ONE, + blockchain.getChainHead().getTotalDifficulty(), + blockchain.getChainHeadHash(), + blockchain.getBlockHeader(BlockHeader.GENESIS_BLOCK_NUMBER).get().getHash()); + + ethManager.processMessage(EthProtocol.ETH63, new DefaultMessage(stakePeer, stakePeerStatus)); + + mergePeerFilter.mergeStateChanged( + true, Optional.of(blockchain.getChainHead().getTotalDifficulty())); + mergePeerFilter.onNewForkchoiceMessage( + Hash.EMPTY, Optional.of(Hash.hash(Bytes.of(1))), Hash.EMPTY); + mergePeerFilter.onNewForkchoiceMessage( + Hash.EMPTY, Optional.of(Hash.hash(Bytes.of(2))), Hash.EMPTY); + + ethManager.processMessage(EthProtocol.ETH63, new DefaultMessage(workPeer, workPeerStatus)); + assertThat(workPeer.isDisconnected()).isTrue(); + assertThat(workPeer.getDisconnectReason()).isPresent(); + assertThat(workPeer.getDisconnectReason()) + .get() + .isEqualTo(DisconnectReason.SUBPROTOCOL_TRIGGERED); + assertThat(stakePeer.isDisconnected()).isFalse(); + } + } + @Test public void doNotDisconnectOnLargeMessageWithinLimits() { try (final EthProtocolManager ethManager = @@ -311,7 +362,7 @@ public void respondToGetHeaders() throws ExecutionException, InterruptedExceptio final BlockHeadersMessage headersMsg = BlockHeadersMessage.readFrom(message); final List headers = Lists.newArrayList(headersMsg.getHeaders(protocolSchedule)); - assertThat(headers.size()).isEqualTo(blockCount); + assertThat(headers).hasSize(blockCount); for (int i = 0; i < blockCount; i++) { assertThat(headers.get(i).getNumber()).isEqualTo(startBlock + i); } @@ -350,7 +401,7 @@ public void respondToGetHeadersWithinLimits() throws ExecutionException, Interru final BlockHeadersMessage headersMsg = BlockHeadersMessage.readFrom(message); final List headers = Lists.newArrayList(headersMsg.getHeaders(protocolSchedule)); - assertThat(headers.size()).isEqualTo(limit); + assertThat(headers).hasSize(limit); for (int i = 0; i < limit; i++) { assertThat(headers.get(i).getNumber()).isEqualTo(startBlock + i); } @@ -386,7 +437,7 @@ public void respondToGetHeadersReversed() throws ExecutionException, Interrupted final BlockHeadersMessage headersMsg = BlockHeadersMessage.readFrom(message); final List headers = Lists.newArrayList(headersMsg.getHeaders(protocolSchedule)); - assertThat(headers.size()).isEqualTo(blockCount); + assertThat(headers).hasSize(blockCount); for (int i = 0; i < blockCount; i++) { assertThat(headers.get(i).getNumber()).isEqualTo(endBlock - i); } @@ -424,7 +475,7 @@ public void respondToGetHeadersWithSkip() throws ExecutionException, Interrupted final BlockHeadersMessage headersMsg = BlockHeadersMessage.readFrom(message); final List headers = Lists.newArrayList(headersMsg.getHeaders(protocolSchedule)); - assertThat(headers.size()).isEqualTo(blockCount); + assertThat(headers).hasSize(blockCount); for (int i = 0; i < blockCount; i++) { assertThat(headers.get(i).getNumber()).isEqualTo(startBlock + i * (skip + 1)); } @@ -463,7 +514,7 @@ public void respondToGetHeadersReversedWithSkip() final BlockHeadersMessage headersMsg = BlockHeadersMessage.readFrom(message); final List headers = Lists.newArrayList(headersMsg.getHeaders(protocolSchedule)); - assertThat(headers.size()).isEqualTo(blockCount); + assertThat(headers).hasSize(blockCount); for (int i = 0; i < blockCount; i++) { assertThat(headers.get(i).getNumber()).isEqualTo(endBlock - i * (skip + 1)); } @@ -522,7 +573,7 @@ public void respondToGetHeadersPartial() throws ExecutionException, InterruptedE final BlockHeadersMessage headersMsg = BlockHeadersMessage.readFrom(message); final List headers = Lists.newArrayList(headersMsg.getHeaders(protocolSchedule)); - assertThat(headers.size()).isEqualTo(2); + assertThat(headers).hasSize(2); for (int i = 0; i < 2; i++) { assertThat(headers.get(i).getNumber()).isEqualTo(startBlock + i); } @@ -559,7 +610,7 @@ public void respondToGetHeadersEmpty() throws ExecutionException, InterruptedExc final BlockHeadersMessage headersMsg = BlockHeadersMessage.readFrom(message); final List headers = Lists.newArrayList(headersMsg.getHeaders(protocolSchedule)); - assertThat(headers.size()).isEqualTo(0); + assertThat(headers).isEmpty(); done.complete(null); }; final PeerConnection peer = setupPeer(ethManager, onSend); @@ -603,7 +654,7 @@ public void respondToGetBodies() throws ExecutionException, InterruptedException final BlockBodiesMessage blocksMessage = BlockBodiesMessage.readFrom(message); final List bodies = Lists.newArrayList(blocksMessage.bodies(protocolSchedule)); - assertThat(bodies.size()).isEqualTo(blockCount); + assertThat(bodies).hasSize(blockCount); for (int i = 0; i < blockCount; i++) { assertThat(expectedBlocks[i].getBody()).isEqualTo(bodies.get(i)); } @@ -654,7 +705,7 @@ public void respondToGetBodiesWithinLimits() throws ExecutionException, Interrup final BlockBodiesMessage blocksMessage = BlockBodiesMessage.readFrom(message); final List bodies = Lists.newArrayList(blocksMessage.bodies(protocolSchedule)); - assertThat(bodies.size()).isEqualTo(limit); + assertThat(bodies).hasSize(limit); for (int i = 0; i < limit; i++) { assertThat(expectedBlocks[i].getBody()).isEqualTo(bodies.get(i)); } @@ -698,7 +749,7 @@ public void respondToGetBodiesPartial() throws ExecutionException, InterruptedEx final BlockBodiesMessage blocksMessage = BlockBodiesMessage.readFrom(message); final List bodies = Lists.newArrayList(blocksMessage.bodies(protocolSchedule)); - assertThat(bodies.size()).isEqualTo(1); + assertThat(bodies).hasSize(1); assertThat(expectedBlock.getBody()).isEqualTo(bodies.get(0)); done.complete(null); }; @@ -743,7 +794,7 @@ public void respondToGetReceipts() throws ExecutionException, InterruptedExcepti final ReceiptsMessage receiptsMessage = ReceiptsMessage.readFrom(message); final List> receipts = Lists.newArrayList(receiptsMessage.receipts()); - assertThat(receipts.size()).isEqualTo(blockCount); + assertThat(receipts).hasSize(blockCount); for (int i = 0; i < blockCount; i++) { assertThat(expectedReceipts.get(i)).isEqualTo(receipts.get(i)); } @@ -793,7 +844,7 @@ public void respondToGetReceiptsWithinLimits() throws ExecutionException, Interr final ReceiptsMessage receiptsMessage = ReceiptsMessage.readFrom(message); final List> receipts = Lists.newArrayList(receiptsMessage.receipts()); - assertThat(receipts.size()).isEqualTo(limit); + assertThat(receipts).hasSize(limit); for (int i = 0; i < limit; i++) { assertThat(expectedReceipts.get(i)).isEqualTo(receipts.get(i)); } @@ -837,7 +888,7 @@ public void respondToGetReceiptsPartial() throws ExecutionException, Interrupted final ReceiptsMessage receiptsMessage = ReceiptsMessage.readFrom(message); final List> receipts = Lists.newArrayList(receiptsMessage.receipts()); - assertThat(receipts.size()).isEqualTo(1); + assertThat(receipts).hasSize(1); assertThat(expectedReceipts).isEqualTo(receipts.get(0)); done.complete(null); }; @@ -885,7 +936,7 @@ public void respondToGetNodeData() throws Exception { assertThat(message.getCode()).isEqualTo(EthPV63.NODE_DATA); final NodeDataMessage receiptsMessage = NodeDataMessage.readFrom(message); final List nodeData = receiptsMessage.nodeData(); - assertThat(nodeData.size()).isEqualTo(blockCount); + assertThat(nodeData).hasSize(blockCount); for (int i = 0; i < blockCount; i++) { assertThat(expectedResults.get(i)).isEqualTo(nodeData.get(i)); } @@ -952,7 +1003,7 @@ public void newBlockMinedSendsNewBlockMessageToAllPeers() { assertThat(msg.totalDifficulty(protocolSchdeule)).isEqualTo(expectedTotalDifficulty); } - assertThat(receivingPeerCaptor.getAllValues().containsAll(peers)).isTrue(); + assertThat(receivingPeerCaptor.getAllValues()).containsAll(peers); } } @@ -994,7 +1045,7 @@ public void shouldSuccessfullyRespondToGetHeadersRequestLessThanZero() final BlockHeadersMessage headersMsg = BlockHeadersMessage.readFrom(message); final List headers = Lists.newArrayList(headersMsg.getHeaders(protocolSchedule)); - assertThat(headers.size()).isEqualTo(receivedBlockCount); + assertThat(headers).hasSize(receivedBlockCount); for (int i = 0; i < receivedBlockCount; i++) { assertThat(headers.get(i).getNumber()).isEqualTo(receivedBlockCount - 1 - i); } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTestUtil.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTestUtil.java index 39e4a711da9..6a3c546c01b 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTestUtil.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTestUtil.java @@ -40,6 +40,7 @@ import java.math.BigInteger; import java.util.Collections; +import java.util.Optional; import java.util.OptionalLong; public class EthProtocolManagerTestUtil { @@ -58,6 +59,40 @@ public static EthProtocolManager create( ethereumWireProtocolConfiguration); } + public static EthProtocolManager create( + final Blockchain blockchain, + final WorldStateArchive worldStateArchive, + final TransactionPool transactionPool, + final EthProtocolConfiguration ethereumWireProtocolConfiguration, + final Optional mergePeerFilter) { + + EthPeers peers = + new EthPeers( + EthProtocol.NAME, + TestClock.fixed(), + new NoOpMetricsSystem(), + 25, + EthProtocolConfiguration.DEFAULT_MAX_MESSAGE_SIZE); + EthMessages messages = new EthMessages(); + EthScheduler ethScheduler = new DeterministicEthScheduler(TimeoutPolicy.NEVER_TIMEOUT); + EthContext ethContext = new EthContext(peers, messages, ethScheduler); + + return new EthProtocolManager( + blockchain, + BigInteger.ONE, + worldStateArchive, + transactionPool, + ethereumWireProtocolConfiguration, + peers, + messages, + ethContext, + Collections.emptyList(), + mergePeerFilter, + false, + ethScheduler, + new ForkIdManager(blockchain, Collections.emptyList(), false)); + } + public static EthProtocolManager create( final Blockchain blockchain, final EthScheduler ethScheduler, @@ -101,6 +136,7 @@ public static EthProtocolManager create( ethMessages, ethContext, Collections.emptyList(), + Optional.empty(), false, ethScheduler, forkIdManager); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java index 39d4837fbba..b7726d4c18f 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java @@ -67,6 +67,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import java.util.concurrent.CompletableFuture; import io.vertx.core.Vertx; @@ -157,6 +158,7 @@ public TestNode( ethMessages, ethContext, Collections.emptyList(), + Optional.empty(), false, scheduler); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java index ceb2202a542..b47080abcc9 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java @@ -115,6 +115,7 @@ public void testDisconnect() { mock(EthMessages.class), ethContext, Collections.emptyList(), + Optional.empty(), true, mock(EthScheduler.class), mock(ForkIdManager.class)); From 750580dcca349d22d024cc14a8171b2fa74b505a Mon Sep 17 00:00:00 2001 From: Daniel Lehrner Date: Mon, 11 Jul 2022 22:21:38 +0200 Subject: [PATCH 006/109] New payload: add invalid to bad blocks (#4080) * if block did not descend from the terminal block add it to the bad blocks Signed-off-by: Daniel Lehrner --- CHANGELOG.md | 1 + .../merge/blockcreation/MergeCoordinator.java | 15 +++++++++------ .../blockcreation/MergeMiningCoordinator.java | 2 ++ .../blockcreation/TransitionCoordinator.java | 5 +++++ .../internal/methods/engine/EngineNewPayload.java | 1 + .../methods/engine/EngineNewPayloadTest.java | 3 +++ 6 files changed, 21 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e7b1f21eec..ae61ab9d4b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 22.7.0-RC2 ### Additions and Improvements +- Add a block to the bad blocks if it did not descend from the terminal block [#4080](https://github.com/hyperledger/besu/pull/4080) ### Bug Fixes - Return the correct latest valid hash in case of bad block when calling engine methods [#4056](https://github.com/hyperledger/besu/pull/4056) diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java index 9de9d5a6b9b..e079b662602 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java @@ -260,12 +260,7 @@ public Result validateBlock(final Block block) { HeaderValidationMode.NONE, false); - validationResult.errorMessage.ifPresent( - errMsg -> - protocolSchedule - .getByBlockNumber(chain.getChainHeadBlockNumber()) - .getBadBlocksManager() - .addBadBlock(block)); + validationResult.errorMessage.ifPresent(errMsg -> addBadBlock(block)); return validationResult; } @@ -546,6 +541,14 @@ interface MergeBlockCreatorFactory { MergeBlockCreator forParams(BlockHeader header, Optional
feeRecipient); } + @Override + public void addBadBlock(final Block block) { + protocolSchedule + .getByBlockNumber(protocolContext.getBlockchain().getChainHeadBlockNumber()) + .getBadBlocksManager() + .addBadBlock(block); + } + @Override public boolean isBadBlock(final Hash blockHash) { final BadBlockManager badBlocksManager = diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeMiningCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeMiningCoordinator.java index 96ddadc0a8a..836aa74fb90 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeMiningCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeMiningCoordinator.java @@ -64,6 +64,8 @@ ForkchoiceResult updateForkChoice( Optional getOrSyncHeaderByHash(Hash blockHash, Hash finalizedBlockHash); + void addBadBlock(final Block block); + boolean isBadBlock(Hash blockHash); class ForkchoiceResult { diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java index bca8331a38f..01ee8c4afc2 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java @@ -199,6 +199,11 @@ public boolean isDescendantOf(final BlockHeader ancestorBlock, final BlockHeader return mergeCoordinator.isDescendantOf(ancestorBlock, newBlock); } + @Override + public void addBadBlock(final Block block) { + mergeCoordinator.addBadBlock(block); + } + @Override public boolean isBadBlock(final Hash blockHash) { return mergeCoordinator.isBadBlock(blockHash); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java index 7ec5c68d7b6..59bff87e2d0 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java @@ -171,6 +171,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) // TODO: post-merge cleanup if (!mergeCoordinator.latestValidAncestorDescendsFromTerminal(newBlockHeader)) { + mergeCoordinator.addBadBlock(block); return respondWithInvalid( reqId, blockParam, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java index 5dc05662804..5e25fef895e 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java @@ -21,8 +21,10 @@ import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.SYNCING; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.VALID; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.hyperledger.besu.consensus.merge.MergeContext; @@ -177,6 +179,7 @@ public void shouldReturnInvalidOnBadTerminalBlock() { EnginePayloadStatusResult res = fromSuccessResp(resp); assertThat(res.getLatestValidHash()).isEqualTo(Optional.of(Hash.ZERO)); assertThat(res.getStatusAsString()).isEqualTo(INVALID.name()); + verify(mergeCoordinator, atLeastOnce()).addBadBlock(any()); } @Test From e97ed8d944cdb6b5754a8ed586ccf8c2b8a6d721 Mon Sep 17 00:00:00 2001 From: Justin Florentine Date: Tue, 12 Jul 2022 16:21:59 -0400 Subject: [PATCH 007/109] host header parse error (#4083) * adds test coverage for bug * corrects root issue and covers the bug Signed-off-by: Justin Florentine --- .../ethereum/api/jsonrpc/JsonRpcService.java | 7 +- .../api/jsonrpc/websocket/JsonRpcJWTTest.java | 136 ++++++++++++++++++ 2 files changed, 140 insertions(+), 3 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcService.java index 97342294e00..883528c2a6b 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcService.java @@ -604,10 +604,11 @@ private Optional getAndValidateHostHeader(final RoutingContext event) { final Iterable splitHostHeader = Splitter.on(':').split(hostname); final long hostPieces = stream(splitHostHeader).count(); // If the host contains a colon, verify the host is correctly formed - host [ ":" port ] - if (hostPieces > 2 || !Iterables.get(splitHostHeader, 1).matches("\\d{1,5}+")) { - return Optional.empty(); + if (hostPieces > 1) { + if (hostPieces > 2 || !Iterables.get(splitHostHeader, 1).matches("\\d{1,5}+")) { + return Optional.empty(); + } } - return Optional.ofNullable(Iterables.get(splitHostHeader, 0)); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/JsonRpcJWTTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/JsonRpcJWTTest.java index 0df9e4a1ed4..965e32eb3ae 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/JsonRpcJWTTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/JsonRpcJWTTest.java @@ -16,6 +16,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; +import static org.mockito.Mockito.spy; import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration; import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcService; @@ -44,9 +45,13 @@ import java.util.Map; import java.util.Optional; +import io.vertx.core.MultiMap; import io.vertx.core.Vertx; import io.vertx.core.http.HttpClient; import io.vertx.core.http.HttpClientOptions; +import io.vertx.core.http.HttpClientRequest; +import io.vertx.core.http.HttpHeaders; +import io.vertx.core.http.HttpMethod; import io.vertx.core.http.WebSocket; import io.vertx.core.http.WebSocketConnectOptions; import io.vertx.core.json.Json; @@ -216,6 +221,7 @@ public void httpRequestWithDefaultHeaderAndValidJWTIsAccepted(final TestContext wsOpts.setURI("/"); wsOpts.addHeader( "Authorization", "Bearer " + ((EngineAuthService) jwtAuth.get()).createToken()); + wsOpts.addHeader(HttpHeaders.HOST, "anything"); final Async async = context.async(); httpClient.webSocket( @@ -246,6 +252,136 @@ public void httpRequestWithDefaultHeaderAndValidJWTIsAccepted(final TestContext httpClient.close(); } + @Test + public void wsRequestFromBadHostAndValidJWTIsDenied(final TestContext context) { + + JsonRpcConfiguration strictHost = JsonRpcConfiguration.createEngineDefault(); + strictHost.setHostsAllowlist(List.of("localhost")); + strictHost.setPort(0); + try { + strictHost.setAuthenticationPublicKeyFile( + new File(this.getClass().getResource("jwt.hex").toURI())); + } catch (URISyntaxException e) { + fail("didn't parse jwt"); + } + + JsonRpcService jsonRpcService = + spy( + new JsonRpcService( + vertx, + bufferDir, + strictHost, + new NoOpMetricsSystem(), + new NatService(Optional.empty(), true), + websocketMethods, + Optional.empty(), + scheduler, + jwtAuth, + healthy, + healthy)); + + jsonRpcService.start().join(); + + final InetSocketAddress inetSocketAddress = jsonRpcService.socketAddress(); + int listenPort = inetSocketAddress.getPort(); + + final HttpClientOptions httpClientOptions = + new HttpClientOptions().setDefaultHost(HOSTNAME).setDefaultPort(listenPort); + + httpClient = vertx.createHttpClient(httpClientOptions); + + WebSocketConnectOptions wsOpts = new WebSocketConnectOptions(); + wsOpts.setPort(listenPort); + wsOpts.setHost(HOSTNAME); + wsOpts.setURI("/"); + wsOpts.addHeader( + "Authorization", "Bearer " + ((EngineAuthService) jwtAuth.get()).createToken()); + wsOpts.addHeader(HttpHeaders.HOST, "bogushost"); + + final Async async = context.async(); + httpClient.webSocket( + wsOpts, + connected -> { + if (connected.failed()) { + connected.cause().printStackTrace(); + } + assertThat(connected.succeeded()).isFalse(); + async.complete(); + }); + + async.awaitSuccess(10000); + jsonRpcService.stop(); + + httpClient.close(); + } + + @Test + public void httpRequestFromBadHostAndValidJWTIsDenied(final TestContext context) { + + JsonRpcConfiguration strictHost = JsonRpcConfiguration.createEngineDefault(); + strictHost.setHostsAllowlist(List.of("localhost")); + strictHost.setPort(0); + try { + strictHost.setAuthenticationPublicKeyFile( + new File(this.getClass().getResource("jwt.hex").toURI())); + } catch (URISyntaxException e) { + fail("didn't parse jwt"); + } + + JsonRpcService jsonRpcService = + spy( + new JsonRpcService( + vertx, + bufferDir, + strictHost, + new NoOpMetricsSystem(), + new NatService(Optional.empty(), true), + websocketMethods, + Optional.empty(), + scheduler, + jwtAuth, + healthy, + healthy)); + + jsonRpcService.start().join(); + + final InetSocketAddress inetSocketAddress = jsonRpcService.socketAddress(); + int listenPort = inetSocketAddress.getPort(); + + final HttpClientOptions httpClientOptions = + new HttpClientOptions().setDefaultHost(HOSTNAME).setDefaultPort(listenPort); + + httpClient = vertx.createHttpClient(httpClientOptions); + + MultiMap headers = + HttpHeaders.set( + "Authorization", "Bearer " + ((EngineAuthService) jwtAuth.get()).createToken()) + .set(HttpHeaders.HOST, "bogushost"); + + final Async async = context.async(); + httpClient.request( + HttpMethod.GET, + "/", + connected -> { + if (connected.failed()) { + connected.cause().printStackTrace(); + } + HttpClientRequest request = connected.result(); + request.headers().addAll(headers); + request.send( + response -> { + assertThat(response.result().statusCode()).isNotEqualTo(500); + assertThat(response.result().statusCode()).isEqualTo(403); + async.complete(); + }); + }); + + async.awaitSuccess(10000); + jsonRpcService.stop(); + + httpClient.close(); + } + @Test public void httpRequestWithDefaultHeaderAndInvalidJWTIsDenied(final TestContext context) { From b85b39d3078a2815079146a4af0d2caf903bfe81 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Wed, 13 Jul 2022 12:43:00 +0200 Subject: [PATCH 008/109] Revert "Add terminal block hash and number to Ropsten genesis file (#4026)" (#4093) This reverts commit 27fc468624d4a19067b076567ea9e1578217d34e. Signed-off-by: Fabio Di Fabio --- .../besu/controller/BesuControllerBuilder.java | 13 ------------- .../test/java/org/hyperledger/besu/ForkIdsTest.java | 4 ++-- config/src/main/resources/ropsten.json | 2 -- 3 files changed, 2 insertions(+), 17 deletions(-) diff --git a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java index f74c33db83a..612fb3fdfbd 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java @@ -634,19 +634,6 @@ protected List createPeerValidators(final ProtocolSchedule protoc protocolSchedule, metricsSystem, requiredBlock.getKey(), requiredBlock.getValue())); } - final Optional terminalBlockHash = configOptionsSupplier.get().getTerminalBlockHash(); - if (terminalBlockHash.isPresent() && !terminalBlockHash.get().equals(Hash.ZERO)) { - final OptionalLong terminalBlockNumber = configOptionsSupplier.get().getTerminalBlockNumber(); - if (terminalBlockNumber.isPresent()) { - validators.add( - new RequiredBlocksPeerValidator( - protocolSchedule, - metricsSystem, - terminalBlockNumber.getAsLong(), - terminalBlockHash.get())); - } - } - final CheckpointConfigOptions checkpointConfigOptions = genesisConfig.getConfigOptions(genesisConfigOverrides).getCheckpointOptions(); if (SyncMode.X_CHECKPOINT.equals(syncConfig.getSyncMode()) diff --git a/besu/src/test/java/org/hyperledger/besu/ForkIdsTest.java b/besu/src/test/java/org/hyperledger/besu/ForkIdsTest.java index cef9a121a7a..98940b4981d 100644 --- a/besu/src/test/java/org/hyperledger/besu/ForkIdsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/ForkIdsTest.java @@ -67,8 +67,8 @@ public static Collection parameters() { new ForkId(Bytes.ofUnsignedInt(0x4bc66396L), 7117117L), new ForkId(Bytes.ofUnsignedInt(0x6727ef90L), 9812189L), new ForkId(Bytes.ofUnsignedInt(0xa157d377L), 10499401L), - new ForkId(Bytes.ofUnsignedInt(0x7119b6b3L), 12350712L), - new ForkId(Bytes.ofUnsignedInt(0xaae42f33L), 0L)) + new ForkId(Bytes.ofUnsignedInt(0x7119b6b3L), 0L), + new ForkId(Bytes.ofUnsignedInt(0x7119b6b3L), 0L)) }, new Object[] { NetworkName.RINKEBY, diff --git a/config/src/main/resources/ropsten.json b/config/src/main/resources/ropsten.json index 3e67901012e..3912705c18e 100644 --- a/config/src/main/resources/ropsten.json +++ b/config/src/main/resources/ropsten.json @@ -11,8 +11,6 @@ "berlinBlock": 9812189, "londonBlock": 10499401, "terminalTotalDifficulty": 50000000000000000, - "terminalBlockHash": "0x5010949c3acdf1d076c9e4ee8aedbb539aca48ebe19638330bc02c5b1bfb953d", - "terminalBlockNumber": 12350712, "ethash": { }, "discovery": { From a1af83b8de06f169bd450bd565e33e868358ef45 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Thu, 14 Jul 2022 00:57:27 +0200 Subject: [PATCH 009/109] Backward sync exception improvements (#4092) * Remove backward sync exception recursive nesting Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 1 + .../merge/blockcreation/MergeCoordinator.java | 13 +++- .../blockcreation/MergeCoordinatorTest.java | 6 +- .../methods/engine/EngineNewPayload.java | 8 +- .../methods/engine/EngineNewPayloadTest.java | 7 +- .../eth/sync/backwardsync/BackwardChain.java | 22 +++--- .../backwardsync/BackwardSyncContext.java | 76 +++++++++++-------- .../InMemoryBackwardChainTest.java | 4 +- 8 files changed, 87 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae61ab9d4b0..32c3bbcd0e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Additions and Improvements - Add a block to the bad blocks if it did not descend from the terminal block [#4080](https://github.com/hyperledger/besu/pull/4080) +- Backward sync exception improvements [#4092](https://github.com/hyperledger/besu/pull/4092) ### Bug Fixes - Return the correct latest valid hash in case of bad block when calling engine methods [#4056](https://github.com/hyperledger/besu/pull/4056) diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java index e079b662602..cd4643a0a3d 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java @@ -217,7 +217,9 @@ public Optional getOrSyncHeaderByHash(final Hash blockHash) { debugLambda(LOG, "BlockHeader {} is already present", () -> optHeader.get().toLogString()); } else { debugLambda(LOG, "appending block hash {} to backward sync", blockHash::toHexString); - backwardSyncContext.syncBackwardsUntil(blockHash); + backwardSyncContext + .syncBackwardsUntil(blockHash) + .exceptionally(e -> logSyncException(blockHash, e)); } return optHeader; } @@ -233,11 +235,18 @@ public Optional getOrSyncHeaderByHash( } else { debugLambda(LOG, "appending block hash {} to backward sync", blockHash::toHexString); backwardSyncContext.updateHeads(blockHash, finalizedBlockHash); - backwardSyncContext.syncBackwardsUntil(blockHash); + backwardSyncContext + .syncBackwardsUntil(blockHash) + .exceptionally(e -> logSyncException(blockHash, e)); } return optHeader; } + private Void logSyncException(final Hash blockHash, final Throwable exception) { + LOG.warn("Sync to block hash " + blockHash.toHexString() + " failed", exception); + return null; + } + @Override public Result validateBlock(final Block block) { diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java index 58ff9d35839..e5923cf5d18 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java @@ -23,7 +23,6 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -50,6 +49,7 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import java.util.Optional; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicLong; import org.apache.tuweni.bytes.Bytes32; @@ -280,10 +280,12 @@ public void assertGetOrSyncForBlockAlreadyPresent() { public void assertGetOrSyncForBlockNotPresent() { BlockHeader mockHeader = headerGenerator.parentHash(Hash.fromHexStringLenient("0xbeef")).buildHeader(); + when(backwardSyncContext.syncBackwardsUntil(mockHeader.getBlockHash())) + .thenReturn(CompletableFuture.completedFuture(null)); + var res = coordinator.getOrSyncHeaderByHash(mockHeader.getHash()); assertThat(res).isNotPresent(); - verify(backwardSyncContext, times(1)).syncBackwardsUntil(mockHeader.getHash()); } @Test diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java index 59bff87e2d0..dc1002a769e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java @@ -165,7 +165,13 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) new Block(newBlockHeader, new BlockBody(transactions, Collections.emptyList())); if (mergeContext.isSyncing() || parentHeader.isEmpty()) { - mergeCoordinator.appendNewPayloadToSync(block); + mergeCoordinator + .appendNewPayloadToSync(block) + .exceptionally( + exception -> { + LOG.warn("Sync to block " + block.toLogString() + " failed", exception); + return null; + }); return respondWith(reqId, blockParam, null, SYNCING); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java index 5e25fef895e..e17cc083854 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java @@ -52,6 +52,7 @@ import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.concurrent.CompletableFuture; import io.vertx.core.Vertx; import org.apache.tuweni.bytes.Bytes32; @@ -263,7 +264,8 @@ public void shouldRespondWithSyncingDuringForwardSync() { BlockHeader mockHeader = new BlockHeaderTestFixture().baseFeePerGas(Wei.ONE).buildHeader(); when(blockchain.getBlockByHash(any())).thenReturn(Optional.empty()); when(mergeContext.isSyncing()).thenReturn(Boolean.TRUE); - + when(mergeCoordinator.appendNewPayloadToSync(any())) + .thenReturn(CompletableFuture.completedFuture(null)); var resp = resp(mockPayload(mockHeader, Collections.emptyList())); EnginePayloadStatusResult res = fromSuccessResp(resp); @@ -275,7 +277,8 @@ public void shouldRespondWithSyncingDuringForwardSync() { @Test public void shouldRespondWithSyncingDuringBackwardsSync() { BlockHeader mockHeader = new BlockHeaderTestFixture().baseFeePerGas(Wei.ONE).buildHeader(); - + when(mergeCoordinator.appendNewPayloadToSync(any())) + .thenReturn(CompletableFuture.completedFuture(null)); var resp = resp(mockPayload(mockHeader, Collections.emptyList())); EnginePayloadStatusResult res = fromSuccessResp(resp); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardChain.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardChain.java index db47c0b7c3c..eb083223b38 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardChain.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardChain.java @@ -97,19 +97,19 @@ public synchronized void prependAncestorsHeader(final BlockHeader blockHeader) { BlockHeader firstHeader = firstStoredAncestor.get(); if (firstHeader.getNumber() != blockHeader.getNumber() + 1) { throw new BackwardSyncException( - "Wrong height of header " - + blockHeader.getHash().toHexString() - + " is " - + blockHeader.getNumber() - + " when we were expecting " - + (firstHeader.getNumber() - 1)); + "Block " + + firstHeader.toLogString() + + " has a wrong height, we were expecting " + + (blockHeader.getNumber() + 1)); } if (!firstHeader.getParentHash().equals(blockHeader.getHash())) { throw new BackwardSyncException( - "Hash of header does not match our expectations, was " - + blockHeader.toLogString() - + " when we expected " - + firstHeader.getParentHash().toHexString()); + "For block " + + firstHeader.toLogString() + + " we were expecting the parent with hash " + + firstHeader.getParentHash().toHexString() + + " while as parent we found " + + blockHeader.toLogString()); } headers.put(blockHeader.getHash(), blockHeader); chainStorage.put(blockHeader.getHash(), firstStoredAncestor.get().getHash()); @@ -117,7 +117,7 @@ public synchronized void prependAncestorsHeader(final BlockHeader blockHeader) { debugLambda( LOG, "Added header {} on height {} to backward chain led by pivot {} on height {}", - () -> blockHeader.toLogString(), + blockHeader::toLogString, blockHeader::getNumber, () -> lastStoredPivot.orElseThrow().toLogString(), firstHeader::getNumber); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java index 55e779a70fd..6d5a3c8a621 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java @@ -15,7 +15,6 @@ package org.hyperledger.besu.ethereum.eth.sync.backwardsync; import static org.hyperledger.besu.util.Slf4jLambdaHelper.debugLambda; -import static org.hyperledger.besu.util.Slf4jLambdaHelper.infoLambda; import static org.hyperledger.besu.util.Slf4jLambdaHelper.traceLambda; import org.hyperledger.besu.datatypes.Hash; @@ -96,27 +95,33 @@ public synchronized void updateHeads(final Hash head, final Hash finalizedBlockH } public synchronized CompletableFuture syncBackwardsUntil(final Hash newBlockHash) { - final CompletableFuture future = this.currentBackwardSyncFuture.get(); - if (isTrusted(newBlockHash)) return future; - backwardChain.addNewHash(newBlockHash); - if (future != null) { - return future; + Optional> maybeFuture = + Optional.ofNullable(this.currentBackwardSyncFuture.get()); + if (isTrusted(newBlockHash)) { + return maybeFuture.orElseGet(() -> CompletableFuture.completedFuture(null)); } - infoLambda(LOG, "Starting new backward sync towards a pivot {}", newBlockHash::toHexString); - this.currentBackwardSyncFuture.set(prepareBackwardSyncFutureWithRetry()); - return this.currentBackwardSyncFuture.get(); + backwardChain.addNewHash(newBlockHash); + return maybeFuture.orElseGet( + () -> { + CompletableFuture future = prepareBackwardSyncFutureWithRetry(); + this.currentBackwardSyncFuture.set(future); + return future; + }); } public synchronized CompletableFuture syncBackwardsUntil(final Block newPivot) { - final CompletableFuture future = this.currentBackwardSyncFuture.get(); - if (isTrusted(newPivot.getHash())) return future; - backwardChain.appendTrustedBlock(newPivot); - if (future != null) { - return future; + Optional> maybeFuture = + Optional.ofNullable(this.currentBackwardSyncFuture.get()); + if (isTrusted(newPivot.getHash())) { + return maybeFuture.orElseGet(() -> CompletableFuture.completedFuture(null)); } - infoLambda(LOG, "Starting new backward sync towards a pivot {}", newPivot::toLogString); - this.currentBackwardSyncFuture.set(prepareBackwardSyncFutureWithRetry()); - return this.currentBackwardSyncFuture.get(); + backwardChain.appendTrustedBlock(newPivot); + return maybeFuture.orElseGet( + () -> { + CompletableFuture future = prepareBackwardSyncFutureWithRetry(); + this.currentBackwardSyncFuture.set(future); + return future; + }); } private boolean isTrusted(final Hash hash) { @@ -149,7 +154,8 @@ private CompletableFuture prepareBackwardSyncFutureWithRetry() { (unused, throwable) -> { this.currentBackwardSyncFuture.set(null); if (throwable != null) { - throw new BackwardSyncException(throwable); + throw extractBackwardSyncException(throwable) + .orElse(new BackwardSyncException(throwable)); } return null; }); @@ -157,25 +163,35 @@ private CompletableFuture prepareBackwardSyncFutureWithRetry() { @VisibleForTesting protected void processException(final Throwable throwable) { + extractBackwardSyncException(throwable) + .ifPresentOrElse( + backwardSyncException -> { + if (backwardSyncException.shouldRestart()) { + LOG.info( + "Backward sync failed ({}). Current Peers: {}. Retrying in few seconds...", + backwardSyncException.getMessage(), + ethContext.getEthPeers().peerCount()); + return; + } else { + throw backwardSyncException; + } + }, + () -> + LOG.warn( + "There was an uncaught exception during Backwards Sync. Retrying in few seconds...", + throwable)); + } + + private Optional extractBackwardSyncException(final Throwable throwable) { Throwable currentCause = throwable; while (currentCause != null) { if (currentCause instanceof BackwardSyncException) { - if (((BackwardSyncException) currentCause).shouldRestart()) { - LOG.info( - "Backward sync failed ({}). Current Peers: {}. Retrying in few seconds... ", - currentCause.getMessage(), - ethContext.getEthPeers().peerCount()); - return; - } else { - throw new BackwardSyncException(throwable); - } + return Optional.of((BackwardSyncException) currentCause); } currentCause = currentCause.getCause(); } - LOG.warn( - "There was an uncaught exception during Backwards Sync... Retrying in few seconds...", - throwable); + return Optional.empty(); } private CompletableFuture prepareBackwardSyncFuture() { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/InMemoryBackwardChainTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/InMemoryBackwardChainTest.java index 3ea0cccfdb7..c1dc0057c6b 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/InMemoryBackwardChainTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/InMemoryBackwardChainTest.java @@ -103,7 +103,7 @@ public void shouldNotSaveHeadersWhenWrongHeight() { assertThatThrownBy( () -> backwardChain.prependAncestorsHeader(blocks.get(blocks.size() - 5).getHeader())) .isInstanceOf(BackwardSyncException.class) - .hasMessageContaining("Wrong height of header"); + .hasMessageContaining("has a wrong height"); BlockHeader firstHeader = backwardChain.getFirstAncestorHeader().orElseThrow(); assertThat(firstHeader).isEqualTo(blocks.get(blocks.size() - 3).getHeader()); } @@ -116,7 +116,7 @@ public void shouldNotSaveHeadersWhenWrongHash() { BlockHeader wrongHashHeader = prepareWrongParentHash(blocks.get(blocks.size() - 4).getHeader()); assertThatThrownBy(() -> backwardChain.prependAncestorsHeader(wrongHashHeader)) .isInstanceOf(BackwardSyncException.class) - .hasMessageContaining("Hash of header does not match our expectations"); + .hasMessageContaining("we were expecting the parent with hash"); BlockHeader firstHeader = backwardChain.getFirstAncestorHeader().orElseThrow(); assertThat(firstHeader).isEqualTo(blocks.get(blocks.size() - 3).getHeader()); } From 211015e11ae86e7cd3d8c5076fa8127c2763282c Mon Sep 17 00:00:00 2001 From: Jiri Peinlich Date: Thu, 14 Jul 2022 05:13:22 +0200 Subject: [PATCH 010/109] Finalised blocks should not prevent reorgs in BWS (#4097) Signed-off-by: Jiri Peinlich --- .../backwardsync/BackwardSyncContext.java | 59 ------------------- .../backwardsync/BackwardSyncContextTest.java | 57 ------------------ 2 files changed, 116 deletions(-) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java index 6d5a3c8a621..e69277f1400 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java @@ -23,7 +23,6 @@ import org.hyperledger.besu.ethereum.chain.BadBlockManager; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Block; -import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; @@ -253,7 +252,6 @@ public void resetBatchSize() { protected Void saveBlock(final Block block) { traceLambda(LOG, "Going to validate block {}", block::toLogString); - checkFinalizedSuccessionRuleBeforeSave(block); var optResult = this.getBlockValidatorForBlock(block) .validateAndProcessBlock( @@ -285,63 +283,6 @@ protected Void saveBlock(final Block block) { return null; } - @VisibleForTesting - protected synchronized void checkFinalizedSuccessionRuleBeforeSave(final Block block) { - final Optional finalized = findMaybeFinalized(); - if (finalized.isPresent()) { - final Optional maybeFinalizedHeader = - protocolContext - .getBlockchain() - .getBlockByHash(finalized.get()) - .map(Block::getHeader) - .or(() -> backwardChain.getHeader(finalized.get())); - if (maybeFinalizedHeader.isEmpty()) { - throw new BackwardSyncException( - "We know a block " - + finalized.get().toHexString() - + " was finalized, but we don't have it downloaded yet, cannot save new block", - true); - } - final BlockHeader finalizedHeader = maybeFinalizedHeader.get(); - if (finalizedHeader.getHash().equals(block.getHash())) { - debugLambda(LOG, "Saving new finalized block {}", block::toLogString); - return; - } - - if (finalizedHeader.getNumber() == block.getHeader().getNumber()) { - throw new BackwardSyncException( - "This block is not the target finalized block. Is " - + block.toLogString() - + " but was expecting " - + finalizedHeader.toLogString()); - } - if (!getProtocolContext().getBlockchain().contains(finalizedHeader.getHash())) { - debugLambda( - LOG, - "Saving block {} before finalized {} reached", - block::toLogString, - finalizedHeader::toLogString); // todo: some check here?? - return; - } - final Hash canonicalHash = - getProtocolContext() - .getBlockchain() - .getBlockByNumber(finalizedHeader.getNumber()) - .orElseThrow() - .getHash(); - if (finalizedHeader.getNumber() < block.getHeader().getNumber() - && !canonicalHash.equals(finalizedHeader.getHash())) { - throw new BackwardSyncException( - "Finalized block " - + finalizedHeader.toLogString() - + " is not on canonical chain. Canonical is" - + canonicalHash.toHexString() - + ". We need to reorg before saving this block."); - } - } - LOG.debug("Finalized block not known yet..."); - } - @VisibleForTesting protected void possiblyMoveHead(final Block lastSavedBlock) { final MutableBlockchain blockchain = getProtocolContext().getBlockchain(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java index dd5e76bf94d..fb001b92a9a 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java @@ -258,63 +258,6 @@ public void testUpdatingHead() { assertThat(localBlockchain.getChainHeadBlock().getHeader().getNumber()).isEqualTo(4); } - @Test - public void testSuccessionRuleAfterUpdatingFinalized() { - - backwardChain.appendTrustedBlock( - remoteBlockchain.getBlockByNumber(LOCAL_HEIGHT + 1).orElseThrow()); - // null check - context.updateHeads(null, null); - context.checkFinalizedSuccessionRuleBeforeSave(null); - // zero check - context.updateHeads(null, Hash.ZERO); - context.checkFinalizedSuccessionRuleBeforeSave(null); - - // cannot save if we don't know what is finalized - context.updateHeads( - null, remoteBlockchain.getBlockHashByNumber(LOCAL_HEIGHT + 10).orElseThrow()); - assertThatThrownBy(() -> context.checkFinalizedSuccessionRuleBeforeSave(null)) - .isInstanceOf(BackwardSyncException.class) - .hasMessageContaining( - "was finalized, but we don't have it downloaded yet, cannot save new block"); - - // updating with new finalized - context.updateHeads( - null, remoteBlockchain.getBlockHashByNumber(LOCAL_HEIGHT + 1).orElseThrow()); - context.checkFinalizedSuccessionRuleBeforeSave( - remoteBlockchain.getBlockByNumber(LOCAL_HEIGHT + 1).orElseThrow()); - - // updating when we know finalized is in futre - context.updateHeads( - null, remoteBlockchain.getBlockHashByNumber(LOCAL_HEIGHT + 4).orElseThrow()); - context.checkFinalizedSuccessionRuleBeforeSave( - remoteBlockchain.getBlockByNumber(LOCAL_HEIGHT + 1).orElseThrow()); - - // updating with block that is not finalized when we expected finalized on this height - context.updateHeads( - null, remoteBlockchain.getBlockHashByNumber(LOCAL_HEIGHT + 1).orElseThrow()); - assertThatThrownBy( - () -> - context.checkFinalizedSuccessionRuleBeforeSave( - createUncle(LOCAL_HEIGHT + 1, localBlockchain.getChainHeadHash()))) - .isInstanceOf(BackwardSyncException.class) - .hasMessageContaining("This block is not the target finalized block"); - - // updating with a block when finalized is not on canonical chain - context.updateHeads(null, uncle.getHash()); - assertThatThrownBy( - () -> - context.checkFinalizedSuccessionRuleBeforeSave( - remoteBlockchain.getBlockByNumber(LOCAL_HEIGHT + 1).orElseThrow())) - .isInstanceOf(BackwardSyncException.class) - .hasMessageContaining("is not on canonical chain. Canonical is"); - - // updating when finalized is on canonical chain - context.updateHeads(null, localBlockchain.getBlockHashByNumber(UNCLE_HEIGHT).orElseThrow()); - context.checkFinalizedSuccessionRuleBeforeSave( - remoteBlockchain.getBlockByNumber(LOCAL_HEIGHT + 1).orElseThrow()); - } - @Test public void shouldProcessExceptionsCorrectly() { assertThatThrownBy( From 823e6c819f3077f5ee2f100cbd045422932e3890 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Thu, 14 Jul 2022 10:32:25 +0200 Subject: [PATCH 011/109] delegate all the block checks and validation to the block import phase (#4098) Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 1 + .../eth/sync/backwardsync/BackwardChain.java | 20 ++++++------- .../InMemoryBackwardChainTest.java | 28 ------------------- 3 files changed, 11 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32c3bbcd0e4..03ee9244448 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Additions and Improvements - Add a block to the bad blocks if it did not descend from the terminal block [#4080](https://github.com/hyperledger/besu/pull/4080) - Backward sync exception improvements [#4092](https://github.com/hyperledger/besu/pull/4092) +- Remove block header checks during backward sync, since they will be always performed during block import phase [#4098](https://github.com/hyperledger/besu/pull/4098) ### Bug Fixes - Return the correct latest valid hash in case of bad block when calling engine methods [#4056](https://github.com/hyperledger/besu/pull/4056) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardChain.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardChain.java index eb083223b38..7a6f94e2720 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardChain.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardChain.java @@ -97,19 +97,19 @@ public synchronized void prependAncestorsHeader(final BlockHeader blockHeader) { BlockHeader firstHeader = firstStoredAncestor.get(); if (firstHeader.getNumber() != blockHeader.getNumber() + 1) { throw new BackwardSyncException( - "Block " - + firstHeader.toLogString() - + " has a wrong height, we were expecting " - + (blockHeader.getNumber() + 1)); + "Wrong height of header " + + blockHeader.getHash().toHexString() + + " is " + + blockHeader.getNumber() + + " when we were expecting " + + (firstHeader.getNumber() - 1)); } if (!firstHeader.getParentHash().equals(blockHeader.getHash())) { throw new BackwardSyncException( - "For block " - + firstHeader.toLogString() - + " we were expecting the parent with hash " - + firstHeader.getParentHash().toHexString() - + " while as parent we found " - + blockHeader.toLogString()); + "Hash of header does not match our expectations, was " + + blockHeader.toLogString() + + " when we expected " + + firstHeader.getParentHash().toHexString()); } headers.put(blockHeader.getHash(), blockHeader); chainStorage.put(blockHeader.getHash(), firstStoredAncestor.get().getHash()); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/InMemoryBackwardChainTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/InMemoryBackwardChainTest.java index c1dc0057c6b..2cbada01247 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/InMemoryBackwardChainTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/InMemoryBackwardChainTest.java @@ -15,9 +15,7 @@ package org.hyperledger.besu.ethereum.eth.sync.backwardsync; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; import static org.hyperledger.besu.ethereum.eth.sync.backwardsync.ChainForTestCreator.prepareChain; -import static org.hyperledger.besu.ethereum.eth.sync.backwardsync.ChainForTestCreator.prepareWrongParentHash; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.core.Block; @@ -95,32 +93,6 @@ public void shouldSaveHeadersWhenHeightAndHashMatches() { assertThat(firstHeader).isEqualTo(blocks.get(blocks.size() - 4).getHeader()); } - @Test - public void shouldNotSaveHeadersWhenWrongHeight() { - BackwardChain backwardChain = createChainFromBlock(blocks.get(blocks.size() - 1)); - backwardChain.prependAncestorsHeader(blocks.get(blocks.size() - 2).getHeader()); - backwardChain.prependAncestorsHeader(blocks.get(blocks.size() - 3).getHeader()); - assertThatThrownBy( - () -> backwardChain.prependAncestorsHeader(blocks.get(blocks.size() - 5).getHeader())) - .isInstanceOf(BackwardSyncException.class) - .hasMessageContaining("has a wrong height"); - BlockHeader firstHeader = backwardChain.getFirstAncestorHeader().orElseThrow(); - assertThat(firstHeader).isEqualTo(blocks.get(blocks.size() - 3).getHeader()); - } - - @Test - public void shouldNotSaveHeadersWhenWrongHash() { - BackwardChain backwardChain = createChainFromBlock(blocks.get(blocks.size() - 1)); - backwardChain.prependAncestorsHeader(blocks.get(blocks.size() - 2).getHeader()); - backwardChain.prependAncestorsHeader(blocks.get(blocks.size() - 3).getHeader()); - BlockHeader wrongHashHeader = prepareWrongParentHash(blocks.get(blocks.size() - 4).getHeader()); - assertThatThrownBy(() -> backwardChain.prependAncestorsHeader(wrongHashHeader)) - .isInstanceOf(BackwardSyncException.class) - .hasMessageContaining("we were expecting the parent with hash"); - BlockHeader firstHeader = backwardChain.getFirstAncestorHeader().orElseThrow(); - assertThat(firstHeader).isEqualTo(blocks.get(blocks.size() - 3).getHeader()); - } - @Test public void shouldDropFromTheEnd() { From 2c26259348323abb144413395f46a56e586a7e9f Mon Sep 17 00:00:00 2001 From: Daniel Lehrner Date: Thu, 14 Jul 2022 18:16:14 +0200 Subject: [PATCH 012/109] Ignore 2 tests that assume that the system language is English, if that should not be the case (#4102) * ignore 2 tests that assume that the system language is English, if that should not be the case Signed-off-by: Daniel Lehrner --- CHANGELOG.md | 1 + .../test/java/org/hyperledger/besu/cli/BesuCommandTest.java | 6 ++++++ .../p2p/network/NetworkingServiceLifecycleTest.java | 6 ++++++ 3 files changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03ee9244448..79347904c54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - Add a PoS block header rule to check that the current block is more recent than its parent [#4066](https://github.com/hyperledger/besu/pull/4066) - Fixed a trie log layer issue on bonsai during reorg [#4069](https://github.com/hyperledger/besu/pull/4069) - Fix transition protocol schedule to return the pre Merge schedule when reorg pre TTD [#4078](https://github.com/hyperledger/besu/pull/4078) +- The build process runs successfully even though the system language is not English [#4102](https://github.com/hyperledger/besu/pull/4102) ## 22.7.0-RC1 diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index e1cbe33e509..eedb1c3a562 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -17,6 +17,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.startsWith; import static org.hyperledger.besu.cli.config.NetworkName.CLASSIC; import static org.hyperledger.besu.cli.config.NetworkName.DEV; import static org.hyperledger.besu.cli.config.NetworkName.GOERLI; @@ -41,6 +42,7 @@ import static org.hyperledger.besu.ethereum.p2p.config.DefaultDiscoveryConfiguration.RINKEBY_DISCOVERY_URL; import static org.hyperledger.besu.ethereum.worldstate.DataStorageFormat.BONSAI; import static org.hyperledger.besu.nat.kubernetes.KubernetesNatManager.DEFAULT_BESU_SERVICE_NAME_FILTER; +import static org.junit.Assume.assumeThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNotNull; @@ -4755,6 +4757,10 @@ public void eeaWsApisWithPrivacyDisabledLogsWarning() { @Test public void privEnclaveKeyFileDoesNotExist() { + assumeThat( + "Ignored if system language is not English", + System.getProperty("user.language"), + startsWith("en")); parseCommand("--privacy-enabled=true", "--privacy-public-key-file", "/non/existent/file"); assertThat(commandOutput.toString(UTF_8)).isEmpty(); diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/NetworkingServiceLifecycleTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/NetworkingServiceLifecycleTest.java index 715eb431435..96340b7705a 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/NetworkingServiceLifecycleTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/NetworkingServiceLifecycleTest.java @@ -17,7 +17,9 @@ import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.hamcrest.Matchers.startsWith; import static org.hyperledger.besu.ethereum.p2p.NetworkingTestHelper.configWithRandomPorts; +import static org.junit.Assume.assumeThat; import org.hyperledger.besu.crypto.NodeKey; import org.hyperledger.besu.crypto.NodeKeyUtils; @@ -139,6 +141,10 @@ public void startDiscoveryAgentBackToBack() throws IOException { @Test public void startDiscoveryPortInUse() throws IOException { + assumeThat( + "Ignored if system language is not English", + System.getProperty("user.language"), + startsWith("en")); try (final P2PNetwork service1 = builder().config(config).build()) { service1.start(); final NetworkingConfiguration config = configWithRandomPorts(); From 94e6541ca172c11a6a1f1413d7ed79eb453f1220 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Thu, 14 Jul 2022 18:51:47 +0200 Subject: [PATCH 013/109] Fix PR 4098 (#4106) Signed-off-by: Fabio Di Fabio --- .../eth/sync/backwardsync/BackwardChain.java | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardChain.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardChain.java index 7a6f94e2720..c558ea2b763 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardChain.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardChain.java @@ -95,22 +95,6 @@ public synchronized void prependAncestorsHeader(final BlockHeader blockHeader) { return; } BlockHeader firstHeader = firstStoredAncestor.get(); - if (firstHeader.getNumber() != blockHeader.getNumber() + 1) { - throw new BackwardSyncException( - "Wrong height of header " - + blockHeader.getHash().toHexString() - + " is " - + blockHeader.getNumber() - + " when we were expecting " - + (firstHeader.getNumber() - 1)); - } - if (!firstHeader.getParentHash().equals(blockHeader.getHash())) { - throw new BackwardSyncException( - "Hash of header does not match our expectations, was " - + blockHeader.toLogString() - + " when we expected " - + firstHeader.getParentHash().toHexString()); - } headers.put(blockHeader.getHash(), blockHeader); chainStorage.put(blockHeader.getHash(), firstStoredAncestor.get().getHash()); firstStoredAncestor = Optional.of(blockHeader); From 0d1d36afc0a2679a3bb2b9daa3329bd6239a0218 Mon Sep 17 00:00:00 2001 From: Justin Florentine Date: Thu, 14 Jul 2022 13:17:25 -0400 Subject: [PATCH 014/109] log execution errors at right level, stops transition message propagation post-merge sync. (#4104) Signed-off-by: Justin Florentine Co-authored-by: garyschulte --- .../org/hyperledger/besu/consensus/merge/PostMergeContext.java | 2 +- .../jsonrpc/internal/methods/ExecutionEngineJsonRpcMethod.java | 2 +- .../besu/ethereum/eth/sync/BlockPropagationManager.java | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PostMergeContext.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PostMergeContext.java index ab9b1cde600..c3013847852 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PostMergeContext.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PostMergeContext.java @@ -84,7 +84,7 @@ public PostMergeContext setTerminalTotalDifficulty(final Difficulty newTerminalT @Override public void setIsPostMerge(final Difficulty totalDifficulty) { - if (isPostMerge.get().orElse(Boolean.FALSE) && lastFinalized.get() != null) { + if (isPostMerge.get().orElse(Boolean.FALSE)) { // if we have finalized, we never switch back to a pre-merge once we have transitioned // post-TTD. return; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecutionEngineJsonRpcMethod.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecutionEngineJsonRpcMethod.java index 85022820cdf..58a845283b1 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecutionEngineJsonRpcMethod.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecutionEngineJsonRpcMethod.java @@ -66,7 +66,7 @@ public final JsonRpcResponse response(final JsonRpcRequestContext request) { cf.complete( resp.otherwise( t -> { - LOG.debug( + LOG.error( String.format("failed to exec consensus method %s", this.getName()), t); return new JsonRpcErrorResponse( diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java index a459d2c6442..d017009ee36 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java @@ -511,7 +511,8 @@ private String toLogString(final Collection newBlockHashs) { } private void reactToTTDReachedEvent(final boolean ttdReached) { - if (ttdReached) { + if (started.get() && ttdReached) { + LOG.info("Block propagation was running, then ttd reached, stopping"); stop(); } else if (!started.get()) { start(); From 28273793d7e798078e4e0526da1cc4dfdb05ea4d Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Fri, 15 Jul 2022 14:24:14 +1000 Subject: [PATCH 015/109] Add experimental config option to enable v5 discovery (#4103) * Add experimental config option to enable v5 discovery Signed-off-by: Gabriel Trintinalia Co-authored-by: Gabriel Trintinalia Co-authored-by: Sally MacFarlane --- .../org/hyperledger/besu/RunnerBuilder.java | 2 ++ .../options/unstable/NetworkingOptions.java | 10 +++++++- .../cli/options/NetworkingOptionsTest.java | 24 +++++++++++++++++++ .../p2p/config/DiscoveryConfiguration.java | 9 +++++++ .../p2p/network/DefaultP2PNetwork.java | 4 ++++ 5 files changed, 48 insertions(+), 1 deletion(-) diff --git a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java index cae72b00225..a21408a80d1 100644 --- a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java @@ -419,6 +419,8 @@ public Runner build() { } discoveryConfiguration.setBootnodes(bootstrap); discoveryConfiguration.setDnsDiscoveryURL(ethNetworkConfig.getDnsDiscoveryUrl()); + discoveryConfiguration.setDiscoveryV5Enabled( + networkingConfiguration.getDiscovery().isDiscoveryV5Enabled()); } else { discoveryConfiguration.setActive(false); } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/NetworkingOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/NetworkingOptions.java index 2b634cf36a6..bb0045d612f 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/NetworkingOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/NetworkingOptions.java @@ -30,6 +30,7 @@ public class NetworkingOptions implements CLIOptions { private final String CHECK_MAINTAINED_CONNECTIONS_FREQUENCY_FLAG = "--Xp2p-check-maintained-connections-frequency"; private final String DNS_DISCOVERY_SERVER_OVERRIDE_FLAG = "--Xp2p-dns-discovery-server"; + private final String DISCOVERY_PROTOCOL_V5_ENABLED = "--Xv5-discovery-enabled"; @CommandLine.Option( names = INITIATE_CONNECTIONS_FREQUENCY_FLAG, @@ -58,6 +59,13 @@ public class NetworkingOptions implements CLIOptions { "DNS server host to use for doing DNS Discovery of peers, rather than the machine's configured DNS server") private Optional dnsDiscoveryServerOverride = Optional.empty(); + @CommandLine.Option( + names = DISCOVERY_PROTOCOL_V5_ENABLED, + hidden = true, + defaultValue = "false", + description = "Whether to enable P2P Discovery Protocol v5 (default: ${DEFAULT-VALUE})") + private final Boolean isPeerDiscoveryV5Enabled = false; + private NetworkingOptions() {} public static NetworkingOptions create() { @@ -81,7 +89,7 @@ public NetworkingConfiguration toDomainObject() { config.setCheckMaintainedConnectionsFrequency(checkMaintainedConnectionsFrequencySec); config.setInitiateConnectionsFrequency(initiateConnectionsFrequencySec); config.setDnsDiscoveryServerOverride(dnsDiscoveryServerOverride); - + config.getDiscovery().setDiscoveryV5Enabled(isPeerDiscoveryV5Enabled); return config; } diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/NetworkingOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/NetworkingOptionsTest.java index 4bb39f7b525..330bbc524a1 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/NetworkingOptionsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/NetworkingOptionsTest.java @@ -101,6 +101,30 @@ public void checkDnsServerOverrideFlag_isNotSet() { assertThat(commandOutput.toString(UTF_8)).isEmpty(); } + @Test + public void checkDiscoveryV5Enabled_isSet() { + final TestBesuCommand cmd = parseCommand("--Xv5-discovery-enabled"); + + final NetworkingOptions options = cmd.getNetworkingOptions(); + final NetworkingConfiguration networkingConfig = options.toDomainObject(); + assertThat(networkingConfig.getDiscovery().isDiscoveryV5Enabled()).isTrue(); + + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + } + + @Test + public void checkDiscoveryV5Enabled_isNotSet() { + final TestBesuCommand cmd = parseCommand(); + + final NetworkingOptions options = cmd.getNetworkingOptions(); + final NetworkingConfiguration networkingConfig = options.toDomainObject(); + assertThat(networkingConfig.getDiscovery().isDiscoveryV5Enabled()).isFalse(); + + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + } + @Override NetworkingConfiguration createDefaultDomainObject() { return NetworkingConfiguration.create(); diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/config/DiscoveryConfiguration.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/config/DiscoveryConfiguration.java index 9fa25637502..3b4bdb8f36d 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/config/DiscoveryConfiguration.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/config/DiscoveryConfiguration.java @@ -31,6 +31,7 @@ public class DiscoveryConfiguration { private int bucketSize = 16; private List bootnodes = new ArrayList<>(); private String dnsDiscoveryURL; + private boolean discoveryV5Enabled = false; public static DiscoveryConfiguration create() { return new DiscoveryConfiguration(); @@ -113,6 +114,14 @@ public DiscoveryConfiguration setDnsDiscoveryURL(final String dnsDiscoveryURL) { return this; } + public boolean isDiscoveryV5Enabled() { + return discoveryV5Enabled; + } + + public void setDiscoveryV5Enabled(final boolean discoveryV5Enabled) { + this.discoveryV5Enabled = discoveryV5Enabled; + } + @Override public boolean equals(final Object o) { if (o == this) { diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java index e51e3b44e8f..afbf7872837 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java @@ -204,6 +204,10 @@ public void start() { return; } + if (config.getDiscovery().isDiscoveryV5Enabled()) { + LOG.warn("Discovery Protocol v5 is not available"); + } + final String address = config.getDiscovery().getAdvertisedHost(); final int configuredDiscoveryPort = config.getDiscovery().getBindPort(); final int configuredRlpxPort = config.getRlpx().getBindPort(); From 5f69d533e3b330f1b6c7a978088c2de2805ab591 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Thu, 14 Jul 2022 22:48:41 -0600 Subject: [PATCH 016/109] Move Taccat to Emeritus (#4033) Move Taccat Isid from Active to Emeritus Maintainer. Signed-off-by: Danno Ferrin Co-authored-by: Sally MacFarlane --- MAINTAINERS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 5603cfa8e15..d4d41408e8e 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -30,7 +30,6 @@ | Stefan Pingel | pinges | pinges | | Danno Ferrin | shemnon | shemnon | | Simon Dudley | siladu | siladu | -| Taccat Isid | taccatisid | taccatisid | | Usman Saleem | usmansaleem | usmansaleem | @@ -49,6 +48,7 @@ | Rai Sur | RatanRSur | ratanraisur | | Rob Dawson | rojotek | RobDawson | | Sajida Zouarhi | sajz | SajidaZ | +| Taccat Isid | taccatisid | taccatisid | | Tim Beiko | timbeiko | timbeiko | | Vijay Michalik | vmichalik | VijayMichalik | From b25d6d8356a0bbfe1e01cc232935e16c97d3946b Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 15 Jul 2022 10:12:11 +0200 Subject: [PATCH 017/109] Remove hash to append from the queue only if the step succeeds (#4105) * Remove hash to append from the queue only if the step succeeds Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 1 + .../ethereum/eth/sync/backwardsync/BackwardChain.java | 8 +++++++- .../eth/sync/backwardsync/BackwardsSyncAlgorithm.java | 8 +++++++- .../eth/sync/backwardsync/InMemoryBackwardChainTest.java | 3 +++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79347904c54..9161dd469c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - Add a PoS block header rule to check that the current block is more recent than its parent [#4066](https://github.com/hyperledger/besu/pull/4066) - Fixed a trie log layer issue on bonsai during reorg [#4069](https://github.com/hyperledger/besu/pull/4069) - Fix transition protocol schedule to return the pre Merge schedule when reorg pre TTD [#4078](https://github.com/hyperledger/besu/pull/4078) +- Remove hash to sync from the queue only if the sync step succeeds [#4105](https://github.com/hyperledger/besu/pull/4105) - The build process runs successfully even though the system language is not English [#4102](https://github.com/hyperledger/besu/pull/4102) ## 22.7.0-RC1 diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardChain.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardChain.java index c558ea2b763..8453476e732 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardChain.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardChain.java @@ -172,7 +172,13 @@ public synchronized void addNewHash(final Hash newBlockHash) { } public synchronized Optional getFirstHashToAppend() { - return Optional.ofNullable(hashesToAppend.poll()); + return Optional.ofNullable(hashesToAppend.peek()); + } + + public synchronized void removeFromHashToAppend(final Hash hashToRemove) { + if (hashesToAppend.contains(hashToRemove)) { + hashesToAppend.remove(hashToRemove); + } } public void addBadChainToManager(final BadBlockManager badBlocksManager, final Hash hash) { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardsSyncAlgorithm.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardsSyncAlgorithm.java index 9c1551b15a3..845c117e9c0 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardsSyncAlgorithm.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardsSyncAlgorithm.java @@ -56,7 +56,13 @@ public CompletableFuture executeBackwardsSync(final Void unused) { public CompletableFuture pickNextStep() { final Optional firstHash = context.getBackwardChain().getFirstHashToAppend(); if (firstHash.isPresent()) { - return executeSyncStep(firstHash.get()); + return executeSyncStep(firstHash.get()) + .whenComplete( + (result, throwable) -> { + if (throwable == null) { + context.getBackwardChain().removeFromHashToAppend(firstHash.get()); + } + }); } if (!context.isReady()) { return waitForReady(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/InMemoryBackwardChainTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/InMemoryBackwardChainTest.java index 2cbada01247..3fabb7bad83 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/InMemoryBackwardChainTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/InMemoryBackwardChainTest.java @@ -138,12 +138,15 @@ public void shouldAddHeaderToQueue() { firstHash = backwardChain.getFirstHashToAppend(); assertThat(firstHash).isPresent(); assertThat(firstHash.orElseThrow()).isEqualTo(blocks.get(7).getHash()); + backwardChain.removeFromHashToAppend(firstHash.get()); firstHash = backwardChain.getFirstHashToAppend(); assertThat(firstHash).isPresent(); assertThat(firstHash.orElseThrow()).isEqualTo(blocks.get(9).getHash()); + backwardChain.removeFromHashToAppend(firstHash.get()); firstHash = backwardChain.getFirstHashToAppend(); assertThat(firstHash).isPresent(); assertThat(firstHash.orElseThrow()).isEqualTo(blocks.get(11).getHash()); + backwardChain.removeFromHashToAppend(firstHash.get()); } @Test From 45ce87e5b29811038ec79acc74a68f2d0764a549 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 15 Jul 2022 11:08:17 +0200 Subject: [PATCH 018/109] Create backward sync retries on demand (#4095) * Create backward sync retries on demand Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 1 + .../backwardsync/BackwardSyncContext.java | 87 +++++++++++++------ .../backwardsync/BackwardSyncContextTest.java | 25 +++++- 3 files changed, 87 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9161dd469c2..bcc4dd8ba06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Add a block to the bad blocks if it did not descend from the terminal block [#4080](https://github.com/hyperledger/besu/pull/4080) - Backward sync exception improvements [#4092](https://github.com/hyperledger/besu/pull/4092) - Remove block header checks during backward sync, since they will be always performed during block import phase [#4098](https://github.com/hyperledger/besu/pull/4098) +- Optimize the backward sync retry strategy [#4095](https://github.com/hyperledger/besu/pull/4095) ### Bug Fixes - Return the correct latest valid hash in case of bad block when calling engine methods [#4056](https://github.com/hyperledger/besu/pull/4056) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java index e69277f1400..3a9c3afe286 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.ethereum.eth.sync.backwardsync; +import static org.hyperledger.besu.util.FutureUtils.exceptionallyCompose; import static org.hyperledger.besu.util.Slf4jLambdaHelper.debugLambda; import static org.hyperledger.besu.util.Slf4jLambdaHelper.traceLambda; @@ -33,7 +34,6 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; import java.util.stream.Stream; import com.google.common.annotations.VisibleForTesting; @@ -43,7 +43,9 @@ public class BackwardSyncContext { private static final Logger LOG = LoggerFactory.getLogger(BackwardSyncContext.class); public static final int BATCH_SIZE = 200; - private static final int MAX_RETRIES = 100; + private static final int DEFAULT_MAX_RETRIES = 20; + + private static final long DEFAULT_MILLIS_BETWEEN_RETRIES = 5000; protected final ProtocolContext protocolContext; private final ProtocolSchedule protocolSchedule; @@ -58,6 +60,10 @@ public class BackwardSyncContext { private Optional maybeFinalized = Optional.empty(); private Optional maybeHead = Optional.empty(); + private final int maxRetries; + + private final long millisBetweenRetries = DEFAULT_MILLIS_BETWEEN_RETRIES; + public BackwardSyncContext( final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, @@ -65,6 +71,24 @@ public BackwardSyncContext( final EthContext ethContext, final SyncState syncState, final BackwardChain backwardChain) { + this( + protocolContext, + protocolSchedule, + metricsSystem, + ethContext, + syncState, + backwardChain, + DEFAULT_MAX_RETRIES); + } + + public BackwardSyncContext( + final ProtocolContext protocolContext, + final ProtocolSchedule protocolSchedule, + final MetricsSystem metricsSystem, + final EthContext ethContext, + final SyncState syncState, + final BackwardChain backwardChain, + final int maxRetries) { this.protocolContext = protocolContext; this.protocolSchedule = protocolSchedule; @@ -72,6 +96,7 @@ public BackwardSyncContext( this.metricsSystem = metricsSystem; this.syncState = syncState; this.backwardChain = backwardChain; + this.maxRetries = maxRetries; } public synchronized boolean isSyncing() { @@ -135,28 +160,33 @@ private boolean isTrusted(final Hash hash) { } private CompletableFuture prepareBackwardSyncFutureWithRetry() { + return prepareBackwardSyncFutureWithRetry(maxRetries) + .handle( + (unused, throwable) -> { + this.currentBackwardSyncFuture.set(null); + if (throwable != null) { + throw extractBackwardSyncException(throwable) + .orElse(new BackwardSyncException(throwable)); + } + return null; + }); + } - CompletableFuture f = prepareBackwardSyncFuture(); - for (int i = 0; i < MAX_RETRIES; i++) { - f = - f.thenApply(CompletableFuture::completedFuture) - .exceptionally( - ex -> { - processException(ex); - return ethContext - .getScheduler() - .scheduleFutureTask(this::prepareBackwardSyncFuture, Duration.ofSeconds(5)); - }) - .thenCompose(Function.identity()); + private CompletableFuture prepareBackwardSyncFutureWithRetry(final int retries) { + if (retries == 0) { + return CompletableFuture.failedFuture( + new BackwardSyncException("Max number of retries " + maxRetries + " reached")); } - return f.handle( - (unused, throwable) -> { - this.currentBackwardSyncFuture.set(null); - if (throwable != null) { - throw extractBackwardSyncException(throwable) - .orElse(new BackwardSyncException(throwable)); - } - return null; + + return exceptionallyCompose( + prepareBackwardSyncFuture(), + throwable -> { + processException(throwable); + return ethContext + .getScheduler() + .scheduleFutureTask( + () -> prepareBackwardSyncFutureWithRetry(retries - 1), + Duration.ofMillis(millisBetweenRetries)); }); } @@ -167,17 +197,23 @@ protected void processException(final Throwable throwable) { backwardSyncException -> { if (backwardSyncException.shouldRestart()) { LOG.info( - "Backward sync failed ({}). Current Peers: {}. Retrying in few seconds...", + "Backward sync failed ({}). Current Peers: {}. Retrying in " + + millisBetweenRetries + + " milliseconds...", backwardSyncException.getMessage(), ethContext.getEthPeers().peerCount()); return; } else { + debugLambda( + LOG, "Not recoverable backward sync exception {}", throwable::getMessage); throw backwardSyncException; } }, () -> LOG.warn( - "There was an uncaught exception during Backwards Sync. Retrying in few seconds...", + "There was an uncaught exception during Backwards Sync. Retrying in " + + millisBetweenRetries + + " milliseconds...", throwable)); } @@ -193,7 +229,8 @@ private Optional extractBackwardSyncException(final Throw return Optional.empty(); } - private CompletableFuture prepareBackwardSyncFuture() { + @VisibleForTesting + CompletableFuture prepareBackwardSyncFuture() { final MutableBlockchain blockchain = getProtocolContext().getBlockchain(); return new BackwardsSyncAlgorithm( this, diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java index fb001b92a9a..57bb2345a65 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java @@ -54,6 +54,7 @@ import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import javax.annotation.Nonnull; import org.junit.Before; @@ -72,6 +73,8 @@ public class BackwardSyncContextTest { public static final int LOCAL_HEIGHT = 25; public static final int UNCLE_HEIGHT = 25 - 3; + public static final int NUM_OF_RETRIES = 100; + private BackwardSyncContext context; private MutableBlockchain remoteBlockchain; @@ -157,7 +160,8 @@ public void setup() { metricsSystem, ethContext, syncState, - backwardChain)); + backwardChain, + NUM_OF_RETRIES)); doReturn(true).when(context).isReady(); doReturn(2).when(context).getBatchSize(); } @@ -288,4 +292,23 @@ public void makeSureWeRememberBadBlocks() { Mockito.verify(manager).addBadBlock(block); } + + @Test + public void shouldFailAfterMaxNumberOfRetries() { + doReturn(CompletableFuture.failedFuture(new Exception())) + .when(context) + .prepareBackwardSyncFuture(); + + final var syncFuture = context.syncBackwardsUntil(Hash.ZERO); + + try { + syncFuture.get(); + } catch (final Throwable throwable) { + if (throwable instanceof ExecutionException) { + BackwardSyncException backwardSyncException = (BackwardSyncException) throwable.getCause(); + assertThat(backwardSyncException.getMessage()) + .contains("Max number of retries " + NUM_OF_RETRIES + " reached"); + } + } + } } From f885c4671333168089a7b86ffedf985fce81954b Mon Sep 17 00:00:00 2001 From: matkt Date: Fri, 15 Jul 2022 19:16:14 +0200 Subject: [PATCH 019/109] Update checkpoint sync for merge (#4085) Signed-off-by: Karim TAAM --- config/src/main/resources/goerli.json | 6 +++--- config/src/main/resources/mainnet.json | 6 +++--- config/src/main/resources/ropsten.json | 6 +++--- config/src/main/resources/sepolia.json | 5 +++++ .../blockheaders/NewBlockHeadersSubscriptionService.java | 8 ++++---- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/config/src/main/resources/goerli.json b/config/src/main/resources/goerli.json index f819d4deb11..12e52390c24 100644 --- a/config/src/main/resources/goerli.json +++ b/config/src/main/resources/goerli.json @@ -22,9 +22,9 @@ ] }, "checkpoint": { - "hash": "0x2ae30061bdfc7f6dad5b07361dce436502eb0fde68645de12bae4929be619188", - "number": 6720000, - "totalDifficulty": "0x967F81", + "hash": "0x50e55c39a725f062af438c5332a5c5bec9a36d02c829ee6ac2cc27d1db719446", + "number": 4350000, + "totalDifficulty": "0x61DBBF", "_comment": "must be the beginning of an epoch" } }, diff --git a/config/src/main/resources/mainnet.json b/config/src/main/resources/mainnet.json index 1ae9964a92a..805a668c762 100644 --- a/config/src/main/resources/mainnet.json +++ b/config/src/main/resources/mainnet.json @@ -35,9 +35,9 @@ ] }, "checkpoint": { - "hash": "0x844d581cb00058d19f0584fb582fa2de208876ee56bbae27446a679baf4633f4", - "number": 14700000, - "totalDifficulty": "0xA2539264C62BF98CFC6" + "hash": "0x44bca881b07a6a09f83b130798072441705d9a665c5ac8bdf2f39a3cdf3bee29", + "number": 11052984, + "totalDifficulty": "0x3D103014E5C74E5E196" } }, "nonce": "0x42", diff --git a/config/src/main/resources/ropsten.json b/config/src/main/resources/ropsten.json index 3912705c18e..ffd10f68fd3 100644 --- a/config/src/main/resources/ropsten.json +++ b/config/src/main/resources/ropsten.json @@ -23,9 +23,9 @@ ] }, "checkpoint": { - "hash": "0x43de216f876d897e59b9757dd24186e5b53be28bc425ca6a966335b48daaa50c", - "number": 12200000, - "totalDifficulty": "0x928D05243C1CF4" + "hash": "0xeefb1f70bf7bed6394ed7d6f812f422aa37bf7680e1b75fa551d40e849f10a87", + "number": 12269949, + "totalDifficulty": "0x94730AAE0106DC" } }, "nonce": "0x0000000000000042", diff --git a/config/src/main/resources/sepolia.json b/config/src/main/resources/sepolia.json index e91896ef740..d560a5e415e 100644 --- a/config/src/main/resources/sepolia.json +++ b/config/src/main/resources/sepolia.json @@ -19,6 +19,11 @@ "enode://9246d00bc8fd1742e5ad2428b80fc4dc45d786283e05ef6edbd9002cbc335d40998444732fbe921cb88e1d2c73d1b1de53bae6a2237996e9bfe14f871baf7066@18.168.182.86:30303", "enode://ec66ddcf1a974950bd4c782789a7e04f8aa7110a72569b6e65fcd51e937e74eed303b1ea734e4d19cfaec9fbff9b6ee65bf31dcb50ba79acce9dd63a6aca61c7@52.14.151.177:30303" ] + }, + "checkpoint": { + "hash": "0x491ebac1b7f9c0eb426047a495dc577140cb3e09036cd3f7266eda86b635d9fa", + "number": 1273020, + "totalDifficulty": "0x13DE1653E7D280" } }, "alloc":{ diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/blockheaders/NewBlockHeadersSubscriptionService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/blockheaders/NewBlockHeadersSubscriptionService.java index d97bae0bd7c..780caef5043 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/blockheaders/NewBlockHeadersSubscriptionService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/blockheaders/NewBlockHeadersSubscriptionService.java @@ -22,7 +22,7 @@ import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; import org.hyperledger.besu.ethereum.chain.BlockAddedObserver; -import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockHeader; import java.util.ArrayList; import java.util.Collections; @@ -46,8 +46,8 @@ public NewBlockHeadersSubscriptionService( @Override public void onBlockAdded(final BlockAddedEvent event) { if (event.isNewCanonicalHead()) { - final List blocks = new ArrayList<>(); - Block blockPtr = event.getBlock(); + final List blocks = new ArrayList<>(); + BlockHeader blockPtr = event.getBlock().getHeader(); while (!blockPtr.getHash().equals(event.getCommonAncestorHash())) { blocks.add(blockPtr); @@ -55,7 +55,7 @@ public void onBlockAdded(final BlockAddedEvent event) { blockPtr = blockchainQueries .getBlockchain() - .getBlockByHash(blockPtr.getHeader().getParentHash()) + .getBlockHeader(blockPtr.getParentHash()) .orElseThrow(() -> new IllegalStateException("The block was on a orphaned chain.")); } From e48b73bb70280e76beac97847fdedb310acb8eb8 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Mon, 18 Jul 2022 07:49:07 -0700 Subject: [PATCH 020/109] post-merge sync and peering fix (#4116) * add a merge-specific definiton of bestPeer and the supporting plumbing Signed-off-by: garyschulte * set reached TTD when finishing a fast sync if appropriate Signed-off-by: garyschulte * spdx header Signed-off-by: garyschulte * fix BetterSyncTargetEvaluatorTest tests Signed-off-by: garyschulte --- .../MergeBesuControllerBuilder.java | 22 ++++-- .../TransitionBesuControllerBuilder.java | 31 +++++++++ .../merge/TransitionBestPeerComparator.java | 69 +++++++++++++++++++ .../TransitionBestPeerComparatorTest.java | 66 ++++++++++++++++++ .../besu/ethereum/eth/manager/EthPeers.java | 25 +++++-- .../eth/sync/DefaultSynchronizer.java | 10 ++- .../backwardsync/BackwardSyncContext.java | 4 ++ .../eth/sync/fastsync/FastSyncActions.java | 5 ++ .../sync/fastsync/FastSyncTargetManager.java | 6 +- .../fullsync/BetterSyncTargetEvaluator.java | 2 +- .../ethereum/eth/manager/EthPeersTest.java | 16 ++--- .../BetterSyncTargetEvaluatorTest.java | 6 ++ 12 files changed, 238 insertions(+), 24 deletions(-) create mode 100644 consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionBestPeerComparator.java create mode 100644 consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/TransitionBestPeerComparatorTest.java diff --git a/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java index 1876de302ee..bb140b87edd 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java @@ -17,6 +17,7 @@ import org.hyperledger.besu.consensus.merge.MergeContext; import org.hyperledger.besu.consensus.merge.MergeProtocolSchedule; import org.hyperledger.besu.consensus.merge.PostMergeContext; +import org.hyperledger.besu.consensus.merge.TransitionBestPeerComparator; import org.hyperledger.besu.consensus.merge.blockcreation.MergeCoordinator; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.ProtocolContext; @@ -91,13 +92,22 @@ protected EthProtocolManager createEthProtocolManager( final List peerValidators, final Optional mergePeerFilter) { + var mergeContext = protocolContext.getConsensusContext(MergeContext.class); + + var mergeBestPeerComparator = + new TransitionBestPeerComparator( + configOptionsSupplier + .get() + .getTerminalTotalDifficulty() + .map(Difficulty::of) + .orElseThrow()); + ethPeers.setBestChainComparator(mergeBestPeerComparator); + mergeContext.observeNewIsPostMergeState(mergeBestPeerComparator); + if (mergePeerFilter.isPresent()) { - protocolContext - .getConsensusContext(MergeContext.class) - .observeNewIsPostMergeState(mergePeerFilter.get()); - protocolContext - .getConsensusContext(MergeContext.class) - .addNewForkchoiceMessageListener(mergePeerFilter.get()); + + mergeContext.observeNewIsPostMergeState(mergePeerFilter.get()); + mergeContext.addNewForkchoiceMessageListener(mergePeerFilter.get()); } EthProtocolManager ethProtocolManager = diff --git a/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java index a859ee65e89..83f2d4e658d 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java @@ -31,7 +31,13 @@ import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; +import org.hyperledger.besu.ethereum.eth.manager.EthContext; +import org.hyperledger.besu.ethereum.eth.manager.EthMessages; +import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; +import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; +import org.hyperledger.besu.ethereum.eth.manager.MergePeerFilter; +import org.hyperledger.besu.ethereum.eth.peervalidation.PeerValidator; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.backwardsync.BackwardSyncContext; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; @@ -119,6 +125,31 @@ protected MiningCoordinator createMiningCoordinator( return composedCoordinator; } + @Override + protected EthProtocolManager createEthProtocolManager( + final ProtocolContext protocolContext, + final boolean fastSyncEnabled, + final TransactionPool transactionPool, + final EthProtocolConfiguration ethereumWireProtocolConfiguration, + final EthPeers ethPeers, + final EthContext ethContext, + final EthMessages ethMessages, + final EthScheduler scheduler, + final List peerValidators, + final Optional mergePeerFilter) { + return mergeBesuControllerBuilder.createEthProtocolManager( + protocolContext, + fastSyncEnabled, + transactionPool, + ethereumWireProtocolConfiguration, + ethPeers, + ethContext, + ethMessages, + scheduler, + peerValidators, + mergePeerFilter); + } + @Override protected ProtocolSchedule createProtocolSchedule() { return new TransitionProtocolSchedule( diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionBestPeerComparator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionBestPeerComparator.java new file mode 100644 index 00000000000..b0df8d279b1 --- /dev/null +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionBestPeerComparator.java @@ -0,0 +1,69 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.consensus.merge; + +import static org.hyperledger.besu.ethereum.eth.manager.EthPeers.CHAIN_HEIGHT; + +import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.eth.manager.EthPeer; + +import java.math.BigInteger; +import java.util.Comparator; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiFunction; + +public class TransitionBestPeerComparator implements Comparator, MergeStateHandler { + + private static final AtomicReference terminalTotalDifficulty = + new AtomicReference<>(); + + static final BiFunction distanceFromTTD = + (a, ttd) -> + a.chainState() + .getEstimatedTotalDifficulty() + .getAsBigInteger() + .subtract(ttd.getAsBigInteger()) + .abs() + .negate(); + + public static final Comparator EXACT_DIFFICULTY = + (a, b) -> { + var ttd = terminalTotalDifficulty.get(); + var aDelta = distanceFromTTD.apply(a, ttd); + var bDelta = distanceFromTTD.apply(b, ttd); + return aDelta.compareTo(bDelta); + }; + + public static final Comparator BEST_MERGE_CHAIN = + EXACT_DIFFICULTY.thenComparing(CHAIN_HEIGHT); + + public TransitionBestPeerComparator(final Difficulty configuredTerminalTotalDifficulty) { + terminalTotalDifficulty.set(configuredTerminalTotalDifficulty); + } + + @Override + public void mergeStateChanged( + final boolean isPoS, final Optional difficultyStoppedAt) { + if (isPoS && difficultyStoppedAt.isPresent()) { + terminalTotalDifficulty.set(difficultyStoppedAt.get()); + } + } + + @Override + public int compare(final EthPeer o1, final EthPeer o2) { + return BEST_MERGE_CHAIN.compare(o1, o2); + } +} diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/TransitionBestPeerComparatorTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/TransitionBestPeerComparatorTest.java new file mode 100644 index 00000000000..8c0d2cb9aa6 --- /dev/null +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/TransitionBestPeerComparatorTest.java @@ -0,0 +1,66 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.consensus.merge; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.eth.manager.EthPeer; + +import java.util.Optional; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class TransitionBestPeerComparatorTest { + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + EthPeer a; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + EthPeer b; + + @Test + public void assertDistanceFromTTDPrecedence() { + var comparator = new TransitionBestPeerComparator(Difficulty.of(5000)); + when(a.chainState().getEstimatedTotalDifficulty()).thenReturn(Difficulty.of(5002)); + when(b.chainState().getEstimatedTotalDifficulty()).thenReturn(Difficulty.of(4995)); + // a has less distance from TTD: + assertThat(comparator.compare(a, b)).isEqualTo(1); + when(b.chainState().getEstimatedTotalDifficulty()).thenReturn(Difficulty.of(5001)); + // b has less distance from TTD: + assertThat(comparator.compare(a, b)).isEqualTo(-1); + when(b.chainState().getEstimatedTotalDifficulty()).thenReturn(Difficulty.of(5002)); + // a and b are equi-distant + assertThat(comparator.compare(a, b)).isEqualTo(0); + } + + @Test + public void assertHandlesNewTTD() { + var comparator = new TransitionBestPeerComparator(Difficulty.of(5000)); + when(a.chainState().getEstimatedTotalDifficulty()).thenReturn(Difficulty.of(5002)); + when(b.chainState().getEstimatedTotalDifficulty()).thenReturn(Difficulty.of(4999)); + assertThat(comparator.compare(a, b)).isEqualTo(-1); + + // update TTD with actual value + comparator.mergeStateChanged(true, Optional.of(Difficulty.of(5002))); + assertThat(comparator.compare(a, b)).isEqualTo(1); + } +} diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java index 812608adfa5..9c6c0d16bc1 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java @@ -36,14 +36,19 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class EthPeers { + private static final Logger LOG = LoggerFactory.getLogger(EthPeers.class); public static final Comparator TOTAL_DIFFICULTY = Comparator.comparing(((final EthPeer p) -> p.chainState().getEstimatedTotalDifficulty())); public static final Comparator CHAIN_HEIGHT = Comparator.comparing(((final EthPeer p) -> p.chainState().getEstimatedHeight())); - public static final Comparator BEST_CHAIN = TOTAL_DIFFICULTY.thenComparing(CHAIN_HEIGHT); + public static final Comparator HEAVIEST_CHAIN = + TOTAL_DIFFICULTY.thenComparing(CHAIN_HEIGHT); public static final Comparator LEAST_TO_MOST_BUSY = Comparator.comparing(EthPeer::outstandingRequests) @@ -59,6 +64,8 @@ public class EthPeers { private final Subscribers disconnectCallbacks = Subscribers.create(); private final Collection pendingRequests = new CopyOnWriteArrayList<>(); + private Comparator bestPeerComparator; + public EthPeers( final String protocolName, final Clock clock, @@ -80,6 +87,7 @@ public EthPeers( this.permissioningProviders = permissioningProviders; this.maxPeers = maxPeers; this.maxMessageSize = maxMessageSize; + this.bestPeerComparator = HEAVIEST_CHAIN; metricsSystem.createIntegerGauge( BesuMetricCategory.PEERS, "pending_peer_requests_current", @@ -186,11 +194,11 @@ public Stream streamAvailablePeers() { } public Stream streamBestPeers() { - return streamAvailablePeers().sorted(BEST_CHAIN.reversed()); + return streamAvailablePeers().sorted(getBestChainComparator().reversed()); } public Optional bestPeer() { - return streamAvailablePeers().max(BEST_CHAIN); + return streamAvailablePeers().max(getBestChainComparator()); } public Optional bestPeerWithHeightEstimate() { @@ -199,7 +207,16 @@ public Optional bestPeerWithHeightEstimate() { } public Optional bestPeerMatchingCriteria(final Predicate matchesCriteria) { - return streamAvailablePeers().filter(matchesCriteria).max(BEST_CHAIN); + return streamAvailablePeers().filter(matchesCriteria).max(getBestChainComparator()); + } + + public void setBestChainComparator(final Comparator comparator) { + LOG.info("Updating the default best peer comparator"); + bestPeerComparator = comparator; + } + + public Comparator getBestChainComparator() { + return bestPeerComparator; } @FunctionalInterface diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java index dd1e19e2c70..23241cf3e15 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java @@ -228,9 +228,13 @@ private CompletableFuture handleSyncResult(final FastSyncState result) { result.getPivotBlockNumber().getAsLong()); pivotBlockSelector.close(); syncState.markInitialSyncPhaseAsDone(); - return terminationCondition.shouldContinueDownload() - ? startFullSync() - : CompletableFuture.completedFuture(null); + + if (terminationCondition.shouldContinueDownload()) { + return startFullSync(); + } else { + syncState.setReachedTerminalDifficulty(true); + return CompletableFuture.completedFuture(null); + } } private CompletableFuture startFullSync() { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java index 3a9c3afe286..8ce71fe0423 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java @@ -265,6 +265,10 @@ public BlockValidator getBlockValidatorForBlock(final Block block) { } public boolean isReady() { + LOG.debug( + "checking if BWS is ready: ttd reached {}, initial sync done {}", + syncState.hasReachedTerminalDifficulty().orElse(Boolean.FALSE), + syncState.isInitialSyncPhaseDone()); return syncState.hasReachedTerminalDifficulty().orElse(Boolean.FALSE) && syncState.isInitialSyncPhaseDone(); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActions.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActions.java index a1cb0371635..bda9c4a74ac 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActions.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActions.java @@ -176,6 +176,11 @@ private long countPeersThatCanDeterminePivotBlock() { } private boolean canPeerDeterminePivotBlock(final EthPeer peer) { + LOG.debug( + "peer {} hasEstimatedHeight {} isFullyValidated? {}", + peer.getShortNodeId(), + peer.chainState().hasEstimatedHeight(), + peer.isFullyValidated()); return peer.chainState().hasEstimatedHeight() && peer.isFullyValidated(); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncTargetManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncTargetManager.java index 79c3ce0ccb7..73fab1f3cb5 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncTargetManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncTargetManager.java @@ -76,8 +76,10 @@ protected CompletableFuture> selectBestAvailableSyncTarget() { final EthPeer bestPeer = maybeBestPeer.get(); if (bestPeer.chainState().getEstimatedHeight() < pivotBlockHeader.getNumber()) { LOG.info( - "No sync target with sufficient chain height, waiting for peers: {}", - ethContext.getEthPeers().peerCount()); + "Best peer {} has chain height {} below pivotBlock height {}", + maybeBestPeer.map(EthPeer::getShortNodeId).orElse("none"), + maybeBestPeer.map(p -> p.chainState().getEstimatedHeight()).orElse(-1L), + pivotBlockHeader.getNumber()); return completedFuture(Optional.empty()); } else { return confirmPivotBlockHeader(bestPeer); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/BetterSyncTargetEvaluator.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/BetterSyncTargetEvaluator.java index d7c8f6e9332..68aa5ec95f8 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/BetterSyncTargetEvaluator.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/BetterSyncTargetEvaluator.java @@ -40,7 +40,7 @@ public boolean shouldSwitchSyncTarget(final EthPeer currentSyncTarget) { return maybeBestPeer .map( bestPeer -> { - if (EthPeers.BEST_CHAIN.compare(bestPeer, currentSyncTarget) <= 0) { + if (ethPeers.getBestChainComparator().compare(bestPeer, currentSyncTarget) <= 0) { // Our current target is better or equal to the best peer return false; } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeersTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeersTest.java index e696f78d8cb..4ae23a01169 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeersTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeersTest.java @@ -69,10 +69,10 @@ public void comparesPeersWithHeightAndTd() { assertThat(EthPeers.CHAIN_HEIGHT.compare(peerA, peerB)).isGreaterThan(0); assertThat(EthPeers.TOTAL_DIFFICULTY.compare(peerA, peerB)).isLessThan(0); - assertThat(EthPeers.BEST_CHAIN.compare(peerA, peerB)).isLessThan(0); - assertThat(EthPeers.BEST_CHAIN.compare(peerB, peerA)).isGreaterThan(0); - assertThat(EthPeers.BEST_CHAIN.compare(peerA, peerA)).isEqualTo(0); - assertThat(EthPeers.BEST_CHAIN.compare(peerB, peerB)).isEqualTo(0); + assertThat(EthPeers.HEAVIEST_CHAIN.compare(peerA, peerB)).isLessThan(0); + assertThat(EthPeers.HEAVIEST_CHAIN.compare(peerB, peerA)).isGreaterThan(0); + assertThat(EthPeers.HEAVIEST_CHAIN.compare(peerA, peerA)).isEqualTo(0); + assertThat(EthPeers.HEAVIEST_CHAIN.compare(peerB, peerB)).isEqualTo(0); assertThat(ethProtocolManager.ethContext().getEthPeers().bestPeer()).contains(peerB); assertThat(ethProtocolManager.ethContext().getEthPeers().bestPeerWithHeightEstimate()) @@ -97,10 +97,10 @@ public void comparesPeersWithTdAndNoHeight() { assertThat(EthPeers.CHAIN_HEIGHT.compare(peerA, peerB)).isEqualTo(0); assertThat(EthPeers.TOTAL_DIFFICULTY.compare(peerA, peerB)).isGreaterThan(0); - assertThat(EthPeers.BEST_CHAIN.compare(peerA, peerB)).isGreaterThan(0); - assertThat(EthPeers.BEST_CHAIN.compare(peerB, peerA)).isLessThan(0); - assertThat(EthPeers.BEST_CHAIN.compare(peerA, peerA)).isEqualTo(0); - assertThat(EthPeers.BEST_CHAIN.compare(peerB, peerB)).isEqualTo(0); + assertThat(EthPeers.HEAVIEST_CHAIN.compare(peerA, peerB)).isGreaterThan(0); + assertThat(EthPeers.HEAVIEST_CHAIN.compare(peerB, peerA)).isLessThan(0); + assertThat(EthPeers.HEAVIEST_CHAIN.compare(peerA, peerA)).isEqualTo(0); + assertThat(EthPeers.HEAVIEST_CHAIN.compare(peerB, peerB)).isEqualTo(0); assertThat(ethProtocolManager.ethContext().getEthPeers().bestPeer()).contains(peerA); assertThat(ethProtocolManager.ethContext().getEthPeers().bestPeerWithHeightEstimate()) diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/BetterSyncTargetEvaluatorTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/BetterSyncTargetEvaluatorTest.java index 602a2d12cb6..c552f1033ae 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/BetterSyncTargetEvaluatorTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fullsync/BetterSyncTargetEvaluatorTest.java @@ -28,6 +28,7 @@ import java.util.Optional; import org.apache.tuweni.units.bigints.UInt256; +import org.junit.Before; import org.junit.Test; public class BetterSyncTargetEvaluatorTest { @@ -46,6 +47,11 @@ public class BetterSyncTargetEvaluatorTest { .build(), ethPeers); + @Before + public void setupMocks() { + when(ethPeers.getBestChainComparator()).thenReturn(EthPeers.HEAVIEST_CHAIN); + } + @Test public void shouldNotSwitchTargetsIfNoBestPeerIsAvailable() { when(ethPeers.bestPeer()).thenReturn(Optional.empty()); From ac3e075ab3474ba1535d7a00501d7cb65943e329 Mon Sep 17 00:00:00 2001 From: Daniel Lehrner Date: Mon, 18 Jul 2022 17:56:35 +0200 Subject: [PATCH 021/109] Check status of block propagation manager before starting or stopping (#4122) * check status of block propagation manager before starting or stopping Signed-off-by: Daniel Lehrner --- CHANGELOG.md | 3 ++- .../ethereum/eth/sync/DefaultSynchronizer.java | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bcc4dd8ba06..9d6ca2eb358 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,8 @@ - Fixed a trie log layer issue on bonsai during reorg [#4069](https://github.com/hyperledger/besu/pull/4069) - Fix transition protocol schedule to return the pre Merge schedule when reorg pre TTD [#4078](https://github.com/hyperledger/besu/pull/4078) - Remove hash to sync from the queue only if the sync step succeeds [#4105](https://github.com/hyperledger/besu/pull/4105) -- The build process runs successfully even though the system language is not English [#4102](https://github.com/hyperledger/besu/pull/4102) +- The build process runs successfully even though the system language is not English [#4102](https://github.com/hyperledger/besu/pull/4102) +- Avoid starting or stopping the BlockPropagationManager more than once [#4122](https://github.com/hyperledger/besu/pull/4122) ## 22.7.0-RC1 diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java index 23241cf3e15..34d31764bc4 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java @@ -179,7 +179,12 @@ private TrailingPeerRequirements calculateTrailingPeerRequirements() { public CompletableFuture start() { if (running.compareAndSet(false, true)) { LOG.info("Starting synchronizer."); - blockPropagationManager.ifPresent(BlockPropagationManager::start); + blockPropagationManager.ifPresent( + manager -> { + if (!manager.isRunning()) { + manager.start(); + } + }); CompletableFuture future; if (fastSyncDownloader.isPresent()) { future = fastSyncDownloader.get().start().thenCompose(this::handleSyncResult); @@ -201,7 +206,12 @@ public void stop() { fastSyncDownloader.ifPresent(FastSyncDownloader::stop); fullSyncDownloader.ifPresent(FullSyncDownloader::stop); maybePruner.ifPresent(Pruner::stop); - blockPropagationManager.ifPresent(BlockPropagationManager::stop); + blockPropagationManager.ifPresent( + manager -> { + if (manager.isRunning()) { + manager.stop(); + } + }); } } From 3ce7f0ff7a53e098776df93f6b4c3df76c996dc9 Mon Sep 17 00:00:00 2001 From: matkt Date: Mon, 18 Jul 2022 20:59:05 +0200 Subject: [PATCH 022/109] candidate fix for missing parent worldstate (#4094) * candidate fix for missing parent worldstate * add rollback if failure * fix persist trie log issue * add trielog manager * fix inmemory issue for bonsai Signed-off-by: Karim TAAM Co-authored-by: garyschulte Co-authored-by: Justin Florentine --- .../controller/BesuControllerBuilder.java | 9 +- .../controller/BesuControllerBuilderTest.java | 11 +- .../bonsai/BonsaiInMemoryWorldState.java | 26 ++- .../bonsai/BonsaiPersistedWorldState.java | 61 +----- .../bonsai/BonsaiWorldStateArchive.java | 109 +++-------- .../besu/ethereum/bonsai/TrieLogManager.java | 182 ++++++++++++++++++ .../core/InMemoryKeyValueStorageProvider.java | 10 +- .../bonsai/BonsaiWorldStateArchiveTest.java | 59 +++++- .../besu/ethereum/bonsai/LogRollingTests.java | 12 +- .../besu/ethereum/bonsai/RollingImport.java | 6 +- 10 files changed, 332 insertions(+), 153 deletions(-) create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/TrieLogManager.java diff --git a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java index 612fb3fdfbd..f791b269ee8 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java @@ -32,6 +32,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethods; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; import org.hyperledger.besu.ethereum.bonsai.BonsaiWorldStateArchive; +import org.hyperledger.besu.ethereum.bonsai.BonsaiWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.bonsai.TrieLogManager; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.BlockchainStorage; import org.hyperledger.besu.ethereum.chain.DefaultBlockchain; @@ -602,7 +604,12 @@ private WorldStateArchive createWorldStateArchive( switch (dataStorageConfiguration.getDataStorageFormat()) { case BONSAI: return new BonsaiWorldStateArchive( - storageProvider, blockchain, dataStorageConfiguration.getBonsaiMaxLayersToLoad()); + new TrieLogManager( + blockchain, + (BonsaiWorldStateKeyValueStorage) worldStateStorage, + dataStorageConfiguration.getBonsaiMaxLayersToLoad()), + storageProvider, + blockchain); case FOREST: default: final WorldStatePreimageStorage preimageStorage = diff --git a/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java index a6c1ce0947f..331256df210 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java @@ -29,6 +29,7 @@ import org.hyperledger.besu.crypto.NodeKey; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.GasLimitCalculator; +import org.hyperledger.besu.ethereum.bonsai.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; @@ -46,6 +47,7 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.ObservableMetricsSystem; +import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import java.math.BigInteger; @@ -83,6 +85,7 @@ public class BesuControllerBuilderTest { @Mock StorageProvider storageProvider; @Mock GasLimitCalculator gasLimitCalculator; @Mock WorldStateStorage worldStateStorage; + @Mock BonsaiWorldStateKeyValueStorage bonsaiWorldStateStorage; @Mock WorldStatePreimageStorage worldStatePreimageStorage; BigInteger networkId = BigInteger.ONE; @@ -128,7 +131,11 @@ public void setup() { when(worldStatePreimageStorage.updater()) .thenReturn(mock(WorldStatePreimageStorage.Updater.class)); when(worldStateStorage.updater()).thenReturn(mock(WorldStateStorage.Updater.class)); - + BonsaiWorldStateKeyValueStorage.Updater bonsaiUpdater = + mock(BonsaiWorldStateKeyValueStorage.Updater.class); + when(bonsaiUpdater.getTrieLogStorageTransaction()) + .thenReturn(mock(KeyValueStorageTransaction.class)); + when(bonsaiWorldStateStorage.updater()).thenReturn(bonsaiUpdater); besuControllerBuilder = visitWithMockConfigs(new MainnetBesuControllerBuilder()); } @@ -152,6 +159,8 @@ BesuControllerBuilder visitWithMockConfigs(final BesuControllerBuilder builder) @Test public void shouldDisablePruningIfBonsaiIsEnabled() { + when(storageProvider.createWorldStateStorage(DataStorageFormat.BONSAI)) + .thenReturn(bonsaiWorldStateStorage); besuControllerBuilder .isPruningEnabled(true) .dataStorageConfiguration( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiInMemoryWorldState.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiInMemoryWorldState.java index 43e36e00810..f24238867f0 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiInMemoryWorldState.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiInMemoryWorldState.java @@ -21,6 +21,8 @@ public class BonsaiInMemoryWorldState extends BonsaiPersistedWorldState { + private boolean isPersisted = false; + public BonsaiInMemoryWorldState( final BonsaiWorldStateArchive archive, final BonsaiWorldStateKeyValueStorage worldStateStorage) { @@ -29,9 +31,16 @@ public BonsaiInMemoryWorldState( @Override public Hash rootHash() { + if (isPersisted) { + return worldStateRootHash; + } + return rootHash(updater.copy()); + } + + public Hash rootHash(final BonsaiWorldStateUpdater localUpdater) { final BonsaiWorldStateKeyValueStorage.Updater updater = worldStateStorage.updater(); try { - final Hash calculatedRootHash = calculateRootHash(updater); + final Hash calculatedRootHash = calculateRootHash(updater, localUpdater); return Hash.wrap(calculatedRootHash); } finally { updater.rollback(); @@ -41,13 +50,12 @@ public Hash rootHash() { @Override public void persist(final BlockHeader blockHeader) { final BonsaiWorldStateUpdater localUpdater = updater.copy(); - try { - final Hash newWorldStateRootHash = rootHash(); - prepareTrieLog(blockHeader, localUpdater, newWorldStateRootHash); - worldStateBlockHash = blockHeader.getHash(); - worldStateRootHash = newWorldStateRootHash; - } finally { - localUpdater.reset(); - } + final Hash newWorldStateRootHash = rootHash(localUpdater); + archive + .getTrieLogManager() + .saveTrieLog(archive, localUpdater, newWorldStateRootHash, blockHeader); + worldStateRootHash = newWorldStateRootHash; + worldStateBlockHash = blockHeader.getBlockHash(); + isPersisted = true; } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiPersistedWorldState.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiPersistedWorldState.java index 9fd7b479b07..cafe2f48fba 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiPersistedWorldState.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiPersistedWorldState.java @@ -25,7 +25,6 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.MutableWorldState; -import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.ethereum.trie.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.evm.account.Account; @@ -100,10 +99,6 @@ public BonsaiWorldStateKeyValueStorage getWorldStateStorage() { return worldStateStorage; } - protected Hash calculateRootHash(final BonsaiWorldStateKeyValueStorage.Updater stateUpdater) { - return calculateRootHash(stateUpdater, updater.copy()); - } - protected Hash calculateRootHash( final BonsaiWorldStateKeyValueStorage.Updater stateUpdater, final BonsaiWorldStateUpdater worldStateUpdater) { @@ -252,14 +247,16 @@ public void persist(final BlockHeader blockHeader) { // then persist the TrieLog for that transition. // If specified but not a direct descendant simply store the new block hash. if (blockHeader != null) { - // do not overwrite a trielog layer that already exists in the database. - // if it's only in memory we need to save it - // for example, like that in case of reorg we don't replace a trielog layer - if (worldStateStorage.getTrieLog(blockHeader.getHash()).isEmpty()) { - final TrieLogLayer trieLog = - prepareTrieLog(blockHeader, localUpdater, newWorldStateRootHash); - persistTrieLog(blockHeader, newWorldStateRootHash, trieLog, stateUpdater); + if (!newWorldStateRootHash.equals(blockHeader.getStateRoot())) { + throw new RuntimeException( + "World State Root does not match expected value, header " + + blockHeader.getStateRoot().toHexString() + + " calculated " + + newWorldStateRootHash.toHexString()); } + archive + .getTrieLogManager() + .saveTrieLog(archive, localUpdater, newWorldStateRootHash, blockHeader); stateUpdater .getTrieBranchStorageTransaction() .put(WORLD_BLOCK_HASH_KEY, blockHeader.getHash().toArrayUnsafe()); @@ -283,46 +280,6 @@ public void persist(final BlockHeader blockHeader) { updater.reset(); } } - if (blockHeader != null) { - archive.scrubLayeredCache(blockHeader.getNumber()); - } - } - - protected TrieLogLayer prepareTrieLog( - final BlockHeader blockHeader, - final BonsaiWorldStateUpdater localUpdater, - final Hash currentWorldStateRootHash) { - - if (!currentWorldStateRootHash.equals(blockHeader.getStateRoot())) { - throw new RuntimeException( - "World State Root does not match expected value, header " - + blockHeader.getStateRoot().toHexString() - + " calculated " - + currentWorldStateRootHash.toHexString()); - } - - debugLambda(LOG, "Adding layered world state for {}", blockHeader::toLogString); - final TrieLogLayer trieLog = localUpdater.generateTrieLog(blockHeader.getBlockHash()); - trieLog.freeze(); - archive.addLayeredWorldState(this, blockHeader, currentWorldStateRootHash, trieLog); - return trieLog; - } - - private void persistTrieLog( - final BlockHeader blockHeader, - final Hash worldStateRootHash, - final TrieLogLayer trieLog, - final BonsaiWorldStateKeyValueStorage.Updater stateUpdater) { - debugLambda( - LOG, - "Persisting trie log for block hash {} and world state root {}", - blockHeader::toLogString, - worldStateRootHash::toHexString); - final BytesValueRLPOutput rlpLog = new BytesValueRLPOutput(); - trieLog.writeTo(rlpLog); - stateUpdater - .getTrieLogStorageTransaction() - .put(blockHeader.getHash().toArrayUnsafe(), rlpLog.encoded().toArrayUnsafe()); } @Override diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchive.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchive.java index ed69ab02f3e..853ab83492a 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchive.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchive.java @@ -17,7 +17,6 @@ package org.hyperledger.besu.ethereum.bonsai; import static org.hyperledger.besu.datatypes.Hash.fromPlugin; -import static org.hyperledger.besu.util.Slf4jLambdaHelper.debugLambda; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; @@ -31,13 +30,10 @@ import org.hyperledger.besu.evm.worldstate.WorldState; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -46,35 +42,20 @@ public class BonsaiWorldStateArchive implements WorldStateArchive { private static final Logger LOG = LoggerFactory.getLogger(BonsaiWorldStateArchive.class); - private static final long RETAINED_LAYERS = 512; // at least 256 + typical rollbacks - private final Blockchain blockchain; + private final TrieLogManager trieLogManager; private final BonsaiPersistedWorldState persistedState; - private final Map layeredWorldStatesByHash; private final BonsaiWorldStateKeyValueStorage worldStateStorage; - private final long maxLayersToLoad; - - public BonsaiWorldStateArchive(final StorageProvider provider, final Blockchain blockchain) { - this(provider, blockchain, RETAINED_LAYERS, new HashMap<>()); - } - - public BonsaiWorldStateArchive( - final StorageProvider provider, final Blockchain blockchain, final long maxLayersToLoad) { - this(provider, blockchain, maxLayersToLoad, new HashMap<>()); - } public BonsaiWorldStateArchive( + final TrieLogManager trieLogManager, final StorageProvider provider, - final Blockchain blockchain, - final long maxLayersToLoad, - final Map layeredWorldStatesByHash) { + final Blockchain blockchain) { + this.trieLogManager = trieLogManager; this.blockchain = blockchain; - this.worldStateStorage = new BonsaiWorldStateKeyValueStorage(provider); this.persistedState = new BonsaiPersistedWorldState(this, worldStateStorage); - this.layeredWorldStatesByHash = layeredWorldStatesByHash; - this.maxLayersToLoad = maxLayersToLoad; blockchain.observeBlockAdded(this::blockAddedHandler); } @@ -82,22 +63,17 @@ private void blockAddedHandler(final BlockAddedEvent event) { LOG.debug("New block add event {}", event); if (event.isNewCanonicalHead()) { final BlockHeader eventBlockHeader = event.getBlock().getHeader(); - layeredWorldStatesByHash.computeIfPresent( - eventBlockHeader.getParentHash(), - (parentHash, bonsaiLayeredWorldState) -> { - if (layeredWorldStatesByHash.containsKey(eventBlockHeader.getHash())) { - bonsaiLayeredWorldState.setNextWorldView( - Optional.of(layeredWorldStatesByHash.get(eventBlockHeader.getHash()))); - } - return bonsaiLayeredWorldState; - }); + trieLogManager.updateLayeredWorldState( + eventBlockHeader.getParentHash(), eventBlockHeader.getHash()); } } @Override public Optional get(final Hash rootHash, final Hash blockHash) { - if (layeredWorldStatesByHash.containsKey(blockHash)) { - return Optional.of(layeredWorldStatesByHash.get(blockHash)); + final Optional layeredWorldState = + trieLogManager.getBonsaiLayeredWorldState(blockHash); + if (layeredWorldState.isPresent()) { + return Optional.of(layeredWorldState.get()); } else if (rootHash.equals(persistedState.blockHash())) { return Optional.of(persistedState); } else { @@ -105,38 +81,9 @@ public Optional get(final Hash rootHash, final Hash blockHash) { } } - public void addLayeredWorldState( - final BonsaiWorldView persistedWorldState, - final BlockHeader blockHeader, - final Hash worldStateRootHash, - final TrieLogLayer trieLog) { - final BonsaiLayeredWorldState bonsaiLayeredWorldState = - new BonsaiLayeredWorldState( - blockchain, - this, - Optional.of(persistedWorldState), - blockHeader.getNumber(), - worldStateRootHash, - trieLog); - debugLambda( - LOG, - "adding layered world state for block {}, state root hash {}", - blockHeader::toLogString, - worldStateRootHash::toHexString); - layeredWorldStatesByHash.put(blockHeader.getHash(), bonsaiLayeredWorldState); - } - - public Optional getTrieLogLayer(final Hash blockHash) { - if (layeredWorldStatesByHash.containsKey(blockHash)) { - return Optional.of(layeredWorldStatesByHash.get(blockHash).getTrieLog()); - } else { - return worldStateStorage.getTrieLog(blockHash).map(TrieLogLayer::fromBytes); - } - } - @Override public boolean isWorldStateAvailable(final Hash rootHash, final Hash blockHash) { - return layeredWorldStatesByHash.containsKey(blockHash) + return trieLogManager.getBonsaiLayeredWorldState(blockHash).isPresent() || persistedState.blockHash().equals(blockHash) || worldStateStorage.isWorldStateAvailable(rootHash, blockHash); } @@ -155,16 +102,21 @@ public Optional getMutable( public Optional getMutable( final Hash rootHash, final Hash blockHash, final boolean isPersistingState) { if (!isPersistingState) { - if (layeredWorldStatesByHash.containsKey(blockHash)) { - return Optional.of(layeredWorldStatesByHash.get(blockHash)); + final Optional layeredWorldState = + trieLogManager.getBonsaiLayeredWorldState(blockHash); + if (layeredWorldState.isPresent()) { + return layeredWorldState; } else { final BlockHeader header = blockchain.getBlockHeader(blockHash).get(); final BlockHeader currentHeader = blockchain.getChainHeadHeader(); - if ((currentHeader.getNumber() - header.getNumber()) >= maxLayersToLoad) { - LOG.warn("Exceeded the limit of back layers that can be loaded ({})", maxLayersToLoad); + if ((currentHeader.getNumber() - header.getNumber()) + >= trieLogManager.getMaxLayersToLoad()) { + LOG.warn( + "Exceeded the limit of back layers that can be loaded ({})", + trieLogManager.getMaxLayersToLoad()); return Optional.empty(); } - final Optional trieLogLayer = getTrieLogLayer(blockHash); + final Optional trieLogLayer = trieLogManager.getTrieLogLayer(blockHash); if (trieLogLayer.isPresent()) { return Optional.of( new BonsaiLayeredWorldState( @@ -195,7 +147,7 @@ public Optional getMutable(final Hash rootHash, final Hash bl final List rollBacks = new ArrayList<>(); final List rollForwards = new ArrayList<>(); if (maybePersistedHeader.isEmpty()) { - getTrieLogLayer(persistedState.blockHash()).ifPresent(rollBacks::add); + trieLogManager.getTrieLogLayer(persistedState.blockHash()).ifPresent(rollBacks::add); } else { BlockHeader targetHeader = blockchain.getBlockHeader(blockHash).get(); BlockHeader persistedHeader = maybePersistedHeader.get(); @@ -203,7 +155,7 @@ public Optional getMutable(final Hash rootHash, final Hash bl Hash persistedBlockHash = persistedHeader.getBlockHash(); while (persistedHeader.getNumber() > targetHeader.getNumber()) { LOG.debug("Rollback {}", persistedBlockHash); - rollBacks.add(getTrieLogLayer(persistedBlockHash).get()); + rollBacks.add(trieLogManager.getTrieLogLayer(persistedBlockHash).get()); persistedHeader = blockchain.getBlockHeader(persistedHeader.getParentHash()).get(); persistedBlockHash = persistedHeader.getBlockHash(); } @@ -211,7 +163,7 @@ public Optional getMutable(final Hash rootHash, final Hash bl Hash targetBlockHash = targetHeader.getBlockHash(); while (persistedHeader.getNumber() < targetHeader.getNumber()) { LOG.debug("Rollforward {}", targetBlockHash); - rollForwards.add(getTrieLogLayer(targetBlockHash).get()); + rollForwards.add(trieLogManager.getTrieLogLayer(targetBlockHash).get()); targetHeader = blockchain.getBlockHeader(targetHeader.getParentHash()).get(); targetBlockHash = targetHeader.getBlockHash(); } @@ -220,10 +172,10 @@ public Optional getMutable(final Hash rootHash, final Hash bl while (!persistedBlockHash.equals(targetBlockHash)) { LOG.debug("Paired Rollback {}", persistedBlockHash); LOG.debug("Paired Rollforward {}", targetBlockHash); - rollForwards.add(getTrieLogLayer(targetBlockHash).get()); + rollForwards.add(trieLogManager.getTrieLogLayer(targetBlockHash).get()); targetHeader = blockchain.getBlockHeader(targetHeader.getParentHash()).get(); - rollBacks.add(getTrieLogLayer(persistedBlockHash).get()); + rollBacks.add(trieLogManager.getTrieLogLayer(persistedBlockHash).get()); persistedHeader = blockchain.getBlockHeader(persistedHeader.getParentHash()).get(); targetBlockHash = targetHeader.getBlockHash(); @@ -269,6 +221,10 @@ public MutableWorldState getMutable() { return persistedState; } + public TrieLogManager getTrieLogManager() { + return trieLogManager; + } + @Override public void setArchiveStateUnSafe(final BlockHeader blockHeader) { persistedState.setArchiveStateUnSafe(blockHeader); @@ -287,9 +243,4 @@ public Optional getAccountProof( // FIXME we can do proofs for layered tries and the persisted trie return Optional.empty(); } - - void scrubLayeredCache(final long newMaxHeight) { - final long waterline = newMaxHeight - RETAINED_LAYERS; - layeredWorldStatesByHash.entrySet().removeIf(entry -> entry.getValue().getHeight() < waterline); - } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/TrieLogManager.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/TrieLogManager.java new file mode 100644 index 00000000000..d8752e5e2fa --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/TrieLogManager.java @@ -0,0 +1,182 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.bonsai; + +import static org.hyperledger.besu.util.Slf4jLambdaHelper.debugLambda; + +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.MutableWorldState; +import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import org.apache.tuweni.bytes.Bytes32; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TrieLogManager { + + private static final long RETAINED_LAYERS = 512; // at least 256 + typical rollbacks + + private static final Logger LOG = LoggerFactory.getLogger(TrieLogManager.class); + + private final Blockchain blockchain; + private final BonsaiWorldStateKeyValueStorage worldStateStorage; + + private final Map layeredWorldStatesByHash; + private final long maxLayersToLoad; + + public TrieLogManager( + final Blockchain blockchain, + final BonsaiWorldStateKeyValueStorage worldStateStorage, + final long maxLayersToLoad, + final Map layeredWorldStatesByHash) { + this.blockchain = blockchain; + this.worldStateStorage = worldStateStorage; + this.layeredWorldStatesByHash = layeredWorldStatesByHash; + this.maxLayersToLoad = maxLayersToLoad; + } + + public TrieLogManager( + final Blockchain blockchain, + final BonsaiWorldStateKeyValueStorage worldStateStorage, + final long maxLayersToLoad) { + this(blockchain, worldStateStorage, maxLayersToLoad, new HashMap<>()); + } + + public TrieLogManager( + final Blockchain blockchain, final BonsaiWorldStateKeyValueStorage worldStateStorage) { + this(blockchain, worldStateStorage, RETAINED_LAYERS, new HashMap<>()); + } + + public synchronized void saveTrieLog( + final BonsaiWorldStateArchive worldStateArchive, + final BonsaiWorldStateUpdater localUpdater, + final Hash worldStateRootHash, + final BlockHeader blockHeader) { + // do not overwrite a trielog layer that already exists in the database. + // if it's only in memory we need to save it + // for example, like that in case of reorg we don't replace a trielog layer + if (worldStateStorage.getTrieLog(blockHeader.getHash()).isEmpty()) { + final BonsaiWorldStateKeyValueStorage.Updater stateUpdater = worldStateStorage.updater(); + boolean success = false; + try { + final TrieLogLayer trieLog = + prepareTrieLog(blockHeader, worldStateRootHash, localUpdater, worldStateArchive); + persistTrieLog(blockHeader, worldStateRootHash, trieLog, stateUpdater); + success = true; + } finally { + if (success) { + stateUpdater.commit(); + } else { + stateUpdater.rollback(); + } + } + } + } + + public synchronized void addLayeredWorldState( + final BlockHeader blockHeader, + final Hash worldStateRootHash, + final TrieLogLayer trieLog, + final BonsaiWorldStateArchive worldStateArchive) { + + final BonsaiLayeredWorldState bonsaiLayeredWorldState = + new BonsaiLayeredWorldState( + blockchain, + worldStateArchive, + Optional.of((BonsaiPersistedWorldState) worldStateArchive.getMutable()), + blockHeader.getNumber(), + worldStateRootHash, + trieLog); + debugLambda( + LOG, + "adding layered world state for block {}, state root hash {}", + blockHeader::toLogString, + worldStateRootHash::toHexString); + layeredWorldStatesByHash.put(blockHeader.getHash(), bonsaiLayeredWorldState); + scrubLayeredCache(blockHeader.getNumber()); + } + + public synchronized void updateLayeredWorldState( + final Hash blockParentHash, final Hash blockHash) { + layeredWorldStatesByHash.computeIfPresent( + blockParentHash, + (parentHash, bonsaiLayeredWorldState) -> { + if (layeredWorldStatesByHash.containsKey(blockHash)) { + bonsaiLayeredWorldState.setNextWorldView( + Optional.of(layeredWorldStatesByHash.get(blockHash))); + } + return bonsaiLayeredWorldState; + }); + } + + public synchronized void scrubLayeredCache(final long newMaxHeight) { + final long waterline = newMaxHeight - RETAINED_LAYERS; + layeredWorldStatesByHash.entrySet().removeIf(entry -> entry.getValue().getHeight() < waterline); + } + + public long getMaxLayersToLoad() { + return maxLayersToLoad; + } + + public Optional getTrieLogLayer(final Hash blockHash) { + if (layeredWorldStatesByHash.containsKey(blockHash)) { + return Optional.of(layeredWorldStatesByHash.get(blockHash).getTrieLog()); + } else { + return worldStateStorage.getTrieLog(blockHash).map(TrieLogLayer::fromBytes); + } + } + + public Optional getBonsaiLayeredWorldState(final Hash blockHash) { + if (layeredWorldStatesByHash.containsKey(blockHash)) { + return Optional.of(layeredWorldStatesByHash.get(blockHash)); + } + return Optional.empty(); + } + + private TrieLogLayer prepareTrieLog( + final BlockHeader blockHeader, + final Hash currentWorldStateRootHash, + final BonsaiWorldStateUpdater localUpdater, + final BonsaiWorldStateArchive worldStateArchive) { + debugLambda(LOG, "Adding layered world state for {}", blockHeader::toLogString); + final TrieLogLayer trieLog = localUpdater.generateTrieLog(blockHeader.getBlockHash()); + trieLog.freeze(); + addLayeredWorldState(blockHeader, currentWorldStateRootHash, trieLog, worldStateArchive); + return trieLog; + } + + private void persistTrieLog( + final BlockHeader blockHeader, + final Hash worldStateRootHash, + final TrieLogLayer trieLog, + final BonsaiWorldStateKeyValueStorage.Updater stateUpdater) { + debugLambda( + LOG, + "Persisting trie log for block hash {} and world state root {}", + blockHeader::toLogString, + worldStateRootHash::toHexString); + final BytesValueRLPOutput rlpLog = new BytesValueRLPOutput(); + trieLog.writeTo(rlpLog); + stateUpdater + .getTrieLogStorageTransaction() + .put(blockHeader.getHash().toArrayUnsafe(), rlpLog.encoded().toArrayUnsafe()); + } +} diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/InMemoryKeyValueStorageProvider.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/InMemoryKeyValueStorageProvider.java index 8ce4a09e3c4..18de012ed30 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/InMemoryKeyValueStorageProvider.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/InMemoryKeyValueStorageProvider.java @@ -15,6 +15,8 @@ package org.hyperledger.besu.ethereum.core; import org.hyperledger.besu.ethereum.bonsai.BonsaiWorldStateArchive; +import org.hyperledger.besu.ethereum.bonsai.BonsaiWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.bonsai.TrieLogManager; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.DefaultBlockchain; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; @@ -63,7 +65,13 @@ public static DefaultWorldStateArchive createInMemoryWorldStateArchive() { public static BonsaiWorldStateArchive createBonsaiInMemoryWorldStateArchive( final Blockchain blockchain) { - return new BonsaiWorldStateArchive(new InMemoryKeyValueStorageProvider(), blockchain); + final InMemoryKeyValueStorageProvider inMemoryKeyValueStorageProvider = + new InMemoryKeyValueStorageProvider(); + return new BonsaiWorldStateArchive( + new TrieLogManager( + blockchain, new BonsaiWorldStateKeyValueStorage(inMemoryKeyValueStorageProvider)), + inMemoryKeyValueStorageProvider, + blockchain); } public static MutableWorldState createInMemoryWorldState() { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchiveTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchiveTest.java index 925b0e548cd..7947df01554 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchiveTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchiveTest.java @@ -80,7 +80,11 @@ public void testGetMutableReturnPersistedStateWhenNeeded() { .thenReturn(Optional.of(chainHead.getStateRoot().toArrayUnsafe())); when(keyValueStorage.get(WORLD_BLOCK_HASH_KEY)) .thenReturn(Optional.of(chainHead.getHash().toArrayUnsafe())); - bonsaiWorldStateArchive = new BonsaiWorldStateArchive(storageProvider, blockchain, 1); + bonsaiWorldStateArchive = + new BonsaiWorldStateArchive( + new TrieLogManager(blockchain, new BonsaiWorldStateKeyValueStorage(storageProvider), 1), + storageProvider, + blockchain); assertThat(bonsaiWorldStateArchive.getMutable(null, chainHead.getHash(), true)) .containsInstanceOf(BonsaiPersistedWorldState.class); @@ -88,7 +92,12 @@ public void testGetMutableReturnPersistedStateWhenNeeded() { @Test public void testGetMutableReturnEmptyWhenLoadMoreThanLimitLayersBack() { - bonsaiWorldStateArchive = new BonsaiWorldStateArchive(storageProvider, blockchain, 512); + bonsaiWorldStateArchive = + new BonsaiWorldStateArchive( + new TrieLogManager( + blockchain, new BonsaiWorldStateKeyValueStorage(storageProvider), 512), + storageProvider, + blockchain); final BlockHeader blockHeader = blockBuilder.number(0).buildHeader(); final BlockHeader chainHead = blockBuilder.number(512).buildHeader(); when(blockchain.getBlockHeader(eq(blockHeader.getHash()))).thenReturn(Optional.of(blockHeader)); @@ -98,7 +107,12 @@ public void testGetMutableReturnEmptyWhenLoadMoreThanLimitLayersBack() { @Test public void testGetMutableWhenLoadLessThanLimitLayersBack() { - bonsaiWorldStateArchive = new BonsaiWorldStateArchive(storageProvider, blockchain, 512); + bonsaiWorldStateArchive = + new BonsaiWorldStateArchive( + new TrieLogManager( + blockchain, new BonsaiWorldStateKeyValueStorage(storageProvider), 512), + storageProvider, + blockchain); final BlockHeader blockHeader = blockBuilder.number(0).buildHeader(); final BlockHeader chainHead = blockBuilder.number(511).buildHeader(); @@ -123,7 +137,14 @@ public void testGetMutableWithStorageInconsistencyRollbackTheState() { final Map layeredWorldStatesByHash = mock(HashMap.class); bonsaiWorldStateArchive = - new BonsaiWorldStateArchive(storageProvider, blockchain, 12, layeredWorldStatesByHash); + new BonsaiWorldStateArchive( + new TrieLogManager( + blockchain, + new BonsaiWorldStateKeyValueStorage(storageProvider), + 12, + layeredWorldStatesByHash), + storageProvider, + blockchain); final BlockHeader blockHeader = blockBuilder.number(0).buildHeader(); when(blockchain.getBlockHeader(eq(blockHeader.getHash()))).thenReturn(Optional.of(blockHeader)); @@ -143,7 +164,15 @@ public void testGetMutableWithStorageConsistencyNotRollbackTheState() { final Map layeredWorldStatesByHash = mock(HashMap.class); bonsaiWorldStateArchive = - spy(new BonsaiWorldStateArchive(storageProvider, blockchain, 12, layeredWorldStatesByHash)); + spy( + new BonsaiWorldStateArchive( + new TrieLogManager( + blockchain, + new BonsaiWorldStateKeyValueStorage(storageProvider), + 12, + layeredWorldStatesByHash), + storageProvider, + blockchain)); var updater = spy(bonsaiWorldStateArchive.getUpdater()); when(bonsaiWorldStateArchive.getUpdater()).thenReturn(updater); @@ -179,7 +208,15 @@ public void testGetMutableWithStorageConsistencyToRollbackAndRollForwardTheState .thenReturn(mock(BonsaiLayeredWorldState.class, Answers.RETURNS_MOCKS)); bonsaiWorldStateArchive = - spy(new BonsaiWorldStateArchive(storageProvider, blockchain, 12, layeredWorldStatesByHash)); + spy( + new BonsaiWorldStateArchive( + new TrieLogManager( + blockchain, + new BonsaiWorldStateKeyValueStorage(storageProvider), + 12, + layeredWorldStatesByHash), + storageProvider, + blockchain)); var updater = spy(bonsaiWorldStateArchive.getUpdater()); when(bonsaiWorldStateArchive.getUpdater()).thenReturn(updater); @@ -222,7 +259,15 @@ public void testGetMutableWithRollbackNotOverrideTrieLogLayer() { .thenReturn(mock(BonsaiLayeredWorldState.class, Answers.RETURNS_MOCKS)); bonsaiWorldStateArchive = - spy(new BonsaiWorldStateArchive(storageProvider, blockchain, 12, layeredWorldStatesByHash)); + spy( + new BonsaiWorldStateArchive( + new TrieLogManager( + blockchain, + new BonsaiWorldStateKeyValueStorage(storageProvider), + 12, + layeredWorldStatesByHash), + storageProvider, + blockchain)); var updater = spy(bonsaiWorldStateArchive.getUpdater()); when(bonsaiWorldStateArchive.getUpdater()).thenReturn(updater); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/LogRollingTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/LogRollingTests.java index bee11318552..f6f7ea5decc 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/LogRollingTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/LogRollingTests.java @@ -109,7 +109,11 @@ public class LogRollingTests { @Before public void createStorage() { final InMemoryKeyValueStorageProvider provider = new InMemoryKeyValueStorageProvider(); - archive = new BonsaiWorldStateArchive(provider, blockchain); + archive = + new BonsaiWorldStateArchive( + new TrieLogManager(blockchain, new BonsaiWorldStateKeyValueStorage(provider)), + provider, + blockchain); accountStorage = (InMemoryKeyValueStorage) provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE); @@ -128,7 +132,11 @@ public void createStorage() { provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.TRIE_LOG_STORAGE); final InMemoryKeyValueStorageProvider secondProvider = new InMemoryKeyValueStorageProvider(); - secondArchive = new BonsaiWorldStateArchive(secondProvider, blockchain); + secondArchive = + new BonsaiWorldStateArchive( + new TrieLogManager(blockchain, new BonsaiWorldStateKeyValueStorage(secondProvider)), + secondProvider, + blockchain); secondAccountStorage = (InMemoryKeyValueStorage) secondProvider.getStorageBySegmentIdentifier( diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/RollingImport.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/RollingImport.java index a1cf2948d6a..3c45cc16e7f 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/RollingImport.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/RollingImport.java @@ -38,7 +38,11 @@ public static void main(final String[] arg) throws IOException { new RollingFileReader((i, c) -> Path.of(String.format(arg[0] + "-%04d.rdat", i)), false); final InMemoryKeyValueStorageProvider provider = new InMemoryKeyValueStorageProvider(); - final BonsaiWorldStateArchive archive = new BonsaiWorldStateArchive(provider, null); + final BonsaiWorldStateArchive archive = + new BonsaiWorldStateArchive( + new TrieLogManager(null, new BonsaiWorldStateKeyValueStorage(provider)), + provider, + null); final InMemoryKeyValueStorage accountStorage = (InMemoryKeyValueStorage) provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE); From a08ee362ac31fff5ba5fcbc4e85851ca6bab61ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diego=20L=C3=B3pez=20Le=C3=B3n?= Date: Mon, 18 Jul 2022 16:50:51 -0300 Subject: [PATCH 023/109] Make JsonRpcHttpService to not attend requests in order (#4099) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Diego López León --- .../besu/ethereum/api/jsonrpc/JsonRpcHttpService.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java index 35147802292..02333398fd9 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java @@ -339,7 +339,8 @@ private Router buildRouter() { authenticationService.get(), config.getNoAuthRpcApis()), rpcMethods), - tracer)); + tracer), + false); } else { mainRoute.blockingHandler( HandlerFactory.jsonRpcExecutor( @@ -347,7 +348,8 @@ private Router buildRouter() { new TimedJsonRpcProcessor( new TracedJsonRpcProcessor(new BaseJsonRpcProcessor()), requestTimer), rpcMethods), - tracer)); + tracer), + false); } if (authenticationService.isPresent()) { From 915854cfe1541a3dd02579ac7efa84f41ab5c0e2 Mon Sep 17 00:00:00 2001 From: ahamlat Date: Tue, 19 Jul 2022 17:37:53 +0200 Subject: [PATCH 024/109] Update RocksDB default block cache size (#4132) * Update RocksDB default block cache size. Signed-off-by: Ameziane H --- .../storage/rocksdb/configuration/RocksDBCLIOptions.java | 4 ++-- .../rocksdb/segmented/RocksDBColumnarKeyValueStorage.java | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/RocksDBCLIOptions.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/RocksDBCLIOptions.java index 68c37ca473f..a919330b022 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/RocksDBCLIOptions.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/configuration/RocksDBCLIOptions.java @@ -20,7 +20,7 @@ public class RocksDBCLIOptions { public static final int DEFAULT_MAX_OPEN_FILES = 1024; - public static final long DEFAULT_CACHE_CAPACITY = 8388608; + public static final long DEFAULT_CACHE_CAPACITY = 134217728; public static final int DEFAULT_MAX_BACKGROUND_COMPACTIONS = 4; public static final int DEFAULT_BACKGROUND_THREAD_COUNT = 4; @@ -42,7 +42,7 @@ public class RocksDBCLIOptions { @CommandLine.Option( names = {CACHE_CAPACITY_FLAG}, hidden = true, - defaultValue = "8388608", + defaultValue = "134217728", paramLabel = "", description = "Cache capacity of RocksDB (default: ${DEFAULT-VALUE})") long cacheCapacity; diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java index 3991d799214..f8d7852dcdb 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java @@ -66,6 +66,8 @@ public class RocksDBColumnarKeyValueStorage private static final Logger LOG = LoggerFactory.getLogger(RocksDBColumnarKeyValueStorage.class); private static final String DEFAULT_COLUMN = "default"; private static final String NO_SPACE_LEFT_ON_DEVICE = "No space left on device"; + private static final int ROCKSDB_FORMAT_VERSION = 5; + private static final long ROCKSDB_BLOCK_SIZE = 32768; static { RocksDbUtil.loadNativeLibrary(); @@ -151,10 +153,10 @@ private BlockBasedTableConfig createBlockBasedTableConfig(final RocksDBConfigura final LRUCache cache = new LRUCache(config.getCacheCapacity()); return new BlockBasedTableConfig() .setBlockCache(cache) - .setFormatVersion(5) + .setFormatVersion(ROCKSDB_FORMAT_VERSION) .setOptimizeFiltersForMemory(true) .setCacheIndexAndFilterBlocks(true) - .setBlockSize(32768); + .setBlockSize(ROCKSDB_BLOCK_SIZE); } @Override From 0ca45f34b91fc92eae7e3d3d96a835171863f474 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Tue, 19 Jul 2022 15:01:18 -0700 Subject: [PATCH 025/109] alternative malloc implementation - jemalloc (#4126) * add malloc arena params to besu startup * add jemalloc preload to besu startup * add jemalloc lib download to docker jvm images * use 5.* for jemalloc-dev version * add jemalloc to circleci containers for acceptance tests Signed-off-by: garyschulte --- .circleci/config.yml | 2 +- CHANGELOG.md | 1 + besu/src/main/scripts/unixStartScript.txt | 4 ++++ docker/openjdk-11-debug/Dockerfile | 2 +- docker/openjdk-11/Dockerfile | 2 +- docker/openjdk-latest/Dockerfile | 2 +- 6 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 63a38fb3dd9..4192595610f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -66,7 +66,7 @@ commands: name: Install Packages - LibSodium, nssdb command: | sudo apt-get update - sudo apt-get install -y libsodium23 libsodium-dev apt-transport-https haveged libnss3-tools + sudo apt-get install -y libsodium23 libsodium-dev libjemalloc-dev apt-transport-https haveged libnss3-tools sudo service haveged restart - restore_gradle_cache restore_gradle_cache: diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d6ca2eb358..9ea40102a81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Backward sync exception improvements [#4092](https://github.com/hyperledger/besu/pull/4092) - Remove block header checks during backward sync, since they will be always performed during block import phase [#4098](https://github.com/hyperledger/besu/pull/4098) - Optimize the backward sync retry strategy [#4095](https://github.com/hyperledger/besu/pull/4095) +- Add support for jemalloc library to better handle rocksdb memory consumption [#4126](https://github.com/hyperledger/besu/pull/4126) ### Bug Fixes - Return the correct latest valid hash in case of bad block when calling engine methods [#4056](https://github.com/hyperledger/besu/pull/4056) diff --git a/besu/src/main/scripts/unixStartScript.txt b/besu/src/main/scripts/unixStartScript.txt index cfcd93532a0..50585f07660 100644 --- a/besu/src/main/scripts/unixStartScript.txt +++ b/besu/src/main/scripts/unixStartScript.txt @@ -182,4 +182,8 @@ APP_ARGS=`save "\$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- \$DEFAULT_JVM_OPTS \$JAVA_OPTS \$${optsEnvironmentVar} <% if ( appNameSystemProperty ) { %>"\"-D${appNameSystemProperty}=\$APP_BASE_NAME\"" <% } %>-classpath "\"\$CLASSPATH\"" <% if ( mainClassName.startsWith('--module ') ) { %>--module-path "\"\$MODULE_PATH\"" <% } %>${mainClassName} "\$APP_ARGS" +# limit malloc to 2 arenas, and use jemalloc if available +export MALLOC_ARENA_MAX=2 +export LD_PRELOAD=libjemalloc.so + exec "\$JAVACMD" "\$@" diff --git a/docker/openjdk-11-debug/Dockerfile b/docker/openjdk-11-debug/Dockerfile index c51dc3285d8..1f03d60465f 100644 --- a/docker/openjdk-11-debug/Dockerfile +++ b/docker/openjdk-11-debug/Dockerfile @@ -3,7 +3,7 @@ FROM ubuntu:20.04 ARG VERSION="dev" RUN apt-get update && \ - apt-get install --no-install-recommends -q --assume-yes curl=7* wget=1.20* jq=1.6* net-tools=1.60* openjdk-11-jdk-headless=11* && \ + apt-get install --no-install-recommends -q --assume-yes curl=7* wget=1.20* jq=1.6* net-tools=1.60* openjdk-11-jdk-headless=11* libjemalloc-dev=5.* && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* && \ adduser --disabled-password --gecos "" --home /opt/besu besu && \ diff --git a/docker/openjdk-11/Dockerfile b/docker/openjdk-11/Dockerfile index 949fdf726f0..e6b71319ccf 100644 --- a/docker/openjdk-11/Dockerfile +++ b/docker/openjdk-11/Dockerfile @@ -3,7 +3,7 @@ FROM ubuntu:20.04 ARG VERSION="dev" RUN apt-get update && \ - apt-get install --no-install-recommends -q --assume-yes openjdk-11-jre-headless=11* && \ + apt-get install --no-install-recommends -q --assume-yes openjdk-11-jre-headless=11* libjemalloc-dev=5.* && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* && \ adduser --disabled-password --gecos "" --home /opt/besu besu && \ diff --git a/docker/openjdk-latest/Dockerfile b/docker/openjdk-latest/Dockerfile index e3590695697..1eeac94cd8a 100644 --- a/docker/openjdk-latest/Dockerfile +++ b/docker/openjdk-latest/Dockerfile @@ -3,7 +3,7 @@ FROM ubuntu:20.04 ARG VERSION="dev" RUN apt-get update && \ - apt-get install --no-install-recommends -q --assume-yes openjdk-17-jre-headless=17* && \ + apt-get install --no-install-recommends -q --assume-yes openjdk-17-jre-headless=17* libjemalloc-dev=5.* && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* && \ adduser --disabled-password --gecos "" --home /opt/besu besu && \ From b7877befdf7c5c8917752a88ea1ea30c3c3258b8 Mon Sep 17 00:00:00 2001 From: Stefan Pingel <16143240+pinges@users.noreply.github.com> Date: Wed, 20 Jul 2022 12:40:34 +1000 Subject: [PATCH 026/109] Useful response improves reputation (#4130) * useful response improves reputation Signed-off-by: Stefan --- .../hyperledger/besu/ethereum/eth/manager/EthPeer.java | 4 ++++ .../hyperledger/besu/ethereum/eth/manager/EthPeers.java | 7 +++++++ .../besu/ethereum/eth/manager/PeerReputation.java | 8 ++++++-- .../eth/manager/task/AbstractPeerRequestTask.java | 6 +++++- .../besu/ethereum/eth/manager/EthPeerTest.java | 8 ++++++++ .../besu/ethereum/eth/manager/PeerReputationTest.java | 6 ++++++ 6 files changed, 36 insertions(+), 3 deletions(-) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeer.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeer.java index 9df946a7ef4..260aec318cc 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeer.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeer.java @@ -215,6 +215,10 @@ public void recordUselessResponse(final String requestType) { reputation.recordUselessResponse(System.currentTimeMillis()).ifPresent(this::disconnect); } + public void recordUsefulResponse() { + reputation.recordUsefulResposne(); + } + public void disconnect(final DisconnectReason reason) { connection.disconnect(reason); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java index 9c6c0d16bc1..442471aadf7 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java @@ -17,6 +17,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthPeer.DisconnectCallback; import org.hyperledger.besu.ethereum.eth.peervalidation.PeerValidator; import org.hyperledger.besu.ethereum.p2p.rlpx.connections.PeerConnection; +import org.hyperledger.besu.ethereum.p2p.rlpx.wire.PeerInfo; import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.permissioning.NodeMessagePermissioningProvider; @@ -115,6 +116,12 @@ public void registerDisconnect(final PeerConnection connection) { disconnectCallbacks.forEach(callback -> callback.onDisconnect(peer)); peer.handleDisconnect(); abortPendingRequestsAssignedToDisconnectedPeers(); + final PeerInfo peerInfo = peer.getConnection().getPeerInfo(); + LOG.debug( + "Disconnected EthPeer {}, client ID: {}, {}", + peerInfo.getNodeId(), + peerInfo.getClientId(), + peer.getReputation()); } reattemptPendingPeerRequests(); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputation.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputation.java index 8293f0dfa09..aa1c37f3218 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputation.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputation.java @@ -44,7 +44,7 @@ public class PeerReputation implements Comparable { private static final int SMALL_ADJUSTMENT = 1; private static final int LARGE_ADJUSTMENT = 10; - private int score = DEFAULT_SCORE; + private long score = DEFAULT_SCORE; public Optional recordRequestTimeout(final int requestCode) { final int newTimeoutCount = getOrCreateTimeoutCount(requestCode).incrementAndGet(); @@ -85,6 +85,10 @@ public Optional recordUselessResponse(final long timestamp) { } } + public void recordUsefulResposne() { + score += SMALL_ADJUSTMENT; + } + private boolean shouldRemove(final Long timestamp, final long currentTimestamp) { return timestamp != null && timestamp + USELESS_RESPONSE_WINDOW_IN_MILLIS < currentTimestamp; } @@ -96,6 +100,6 @@ public String toString() { @Override public int compareTo(final @Nonnull PeerReputation otherReputation) { - return Integer.compare(this.score, otherReputation.score); + return Long.compare(this.score, otherReputation.score); } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractPeerRequestTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractPeerRequestTask.java index 39d4be28ad6..6dd87ae3b7a 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractPeerRequestTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractPeerRequestTask.java @@ -105,7 +105,11 @@ private void handleMessage( } try { final Optional result = processResponse(streamClosed, message, peer); - result.ifPresent(promise::complete); + result.ifPresent( + r -> { + promise.complete(r); + peer.recordUsefulResponse(); + }); } catch (final RLPException e) { // Peer sent us malformed data - disconnect LOG.debug("Disconnecting with BREACH_OF_PROTOCOL due to malformed message: {}", peer, e); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeerTest.java index c9899ba0674..1da115f6920 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeerTest.java @@ -362,6 +362,14 @@ public void compareTo_withDifferentNodeId() { assertThat(peer2.compareTo(peer1)).isEqualTo(-1); } + @Test + public void recordUsefullResponse() { + final EthPeer peer = createPeer(); + final EthPeer peer2 = createPeer(); + peer.recordUsefulResponse(); + assertThat(peer.getReputation().compareTo(peer2.getReputation())).isGreaterThan(0); + } + private void messageStream( final ResponseStreamSupplier getStream, final MessageData targetMessage, diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputationTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputationTest.java index 1371f64c34a..e8a8c6d9a7d 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputationTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputationTest.java @@ -80,4 +80,10 @@ public void shouldDiscardEmptyResponseRecordsAfterTimeWindowElapses() { 1001 + PeerReputation.USELESS_RESPONSE_WINDOW_IN_MILLIS + 1)) .isEmpty(); } + + @Test + public void shouldIncreaseScore() { + reputation.recordUsefulResposne(); + assertThat(reputation.compareTo(new PeerReputation())).isGreaterThan(0); + } } From 86197c449d3661cef57be05c99c31320f71f075f Mon Sep 17 00:00:00 2001 From: Stefan Pingel <16143240+pinges@users.noreply.github.com> Date: Wed, 20 Jul 2022 14:50:58 +1000 Subject: [PATCH 027/109] increase the default max message size for p2p messages (#4120) * remove the limit for the incoming message size. The size is limited on the RLPx layer (16.7MB) Signed-off-by: Stefan --- .../eth/manager/EthProtocolManager.java | 18 ++------------- .../eth/manager/EthProtocolManagerTest.java | 23 ++----------------- 2 files changed, 4 insertions(+), 37 deletions(-) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java index c6a3d54f475..3ce95da4389 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java @@ -71,8 +71,6 @@ public class EthProtocolManager implements ProtocolManager, MinedBlockObserver { private final Blockchain blockchain; private final BlockBroadcaster blockBroadcaster; private final List peerValidators; - // The max size of messages (in bytes) - private final int maxMessageSize; private final Optional mergePeerFilter; public EthProtocolManager( @@ -93,7 +91,6 @@ public EthProtocolManager( this.peerValidators = peerValidators; this.scheduler = scheduler; this.blockchain = blockchain; - this.maxMessageSize = ethereumWireProtocolConfiguration.getMaxMessageSize(); this.mergePeerFilter = mergePeerFilter; this.shutdown = new CountDownLatch(1); this.genesisHash = blockchain.getBlockHashByNumber(0L).orElse(Hash.ZERO); @@ -250,17 +247,6 @@ public void processMessage(final Capability cap, final Message message) { return; } - if (messageData.getSize() > maxMessageSize) { - LOG.warn( - "Received message (code: {}) exceeding size limit of {} bytes: {} bytes. Disconnecting from {}", - Integer.toString(code, 16), - maxMessageSize, - messageData.getSize(), - ethPeer); - ethPeer.disconnect(DisconnectReason.SUBPROTOCOL_TRIGGERED); - return; - } - // Handle STATUS processing if (code == EthPV62.STATUS) { handleStatusMessage(ethPeer, messageData); @@ -391,7 +377,7 @@ private void handleStatusMessage(final EthPeer peer, final MessageData data) { status.genesisHash()); peer.disconnect(DisconnectReason.SUBPROTOCOL_TRIGGERED); } else if (mergePeerFilter.isPresent()) { - boolean disconnected = mergePeerFilter.get().disconnectIfPoW(status, peer); + final boolean disconnected = mergePeerFilter.get().disconnectIfPoW(status, peer); if (disconnected) { handleDisconnect(peer.getConnection(), DisconnectReason.SUBPROTOCOL_TRIGGERED, false); } @@ -422,7 +408,7 @@ public void blockMined(final Block block) { } public List getForkIdAsBytesList() { - ForkId chainHeadForkId = forkIdManager.getForkIdForChainHead(); + final ForkId chainHeadForkId = forkIdManager.getForkIdForChainHead(); return chainHeadForkId == null ? Collections.emptyList() : chainHeadForkId.getForkIdAsBytesList(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java index 1f4eaaef172..4fee5d05e63 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java @@ -202,28 +202,9 @@ public void disconnectOnWrongChainId() { } } - @Test - public void disconnectOnVeryLargeMessage() { - try (final EthProtocolManager ethManager = - EthProtocolManagerTestUtil.create( - blockchain, - () -> false, - protocolContext.getWorldStateArchive(), - transactionPool, - EthProtocolConfiguration.defaultConfig())) { - final MessageData messageData = mock(MessageData.class); - when(messageData.getSize()).thenReturn(EthProtocolConfiguration.DEFAULT_MAX_MESSAGE_SIZE + 1); - when(messageData.getCode()).thenReturn(EthPV62.TRANSACTIONS); - final MockPeerConnection peer = setupPeer(ethManager, (cap, msg, conn) -> {}); - - ethManager.processMessage(EthProtocol.ETH63, new DefaultMessage(peer, messageData)); - assertThat(peer.isDisconnected()).isTrue(); - } - } - @Test public void disconnectNewPoWPeers() { - MergePeerFilter mergePeerFilter = new MergePeerFilter(); + final MergePeerFilter mergePeerFilter = new MergePeerFilter(); try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( blockchain, @@ -1119,7 +1100,7 @@ public void transactionMessagesGoToTheCorrectExecutor() { @Test public void forkIdForChainHeadMayBeNull() { - EthScheduler ethScheduler = mock(EthScheduler.class); + final EthScheduler ethScheduler = mock(EthScheduler.class); try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( blockchain, From e139860549b0b1589c4aa64a29b0005b75b38487 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Wed, 20 Jul 2022 11:18:33 -0700 Subject: [PATCH 028/109] logging additions for better engine visibility (#4136) Signed-off-by: garyschulte --- .../engine/EngineForkchoiceUpdated.java | 29 +++++++++++++------ .../methods/engine/EngineNewPayload.java | 6 ++++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdated.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdated.java index e5906ae53ce..6ec375dc8ca 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdated.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdated.java @@ -77,10 +77,11 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) forkChoice.getHeadBlockHash(), maybeFinalizedHash, forkChoice.getSafeBlockHash()); if (mergeContext.isSyncing()) { - return syncingResponse(requestId); + return syncingResponse(requestId, forkChoice); } if (mergeCoordinator.isBadBlock(forkChoice.getHeadBlockHash())) { + logForkchoiceUpdatedCall(INVALID, forkChoice); return new JsonRpcSuccessResponse( requestId, new EngineUpdateForkchoiceResult( @@ -96,25 +97,21 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) mergeCoordinator.getOrSyncHeaderByHash(forkChoice.getHeadBlockHash()); if (newHead.isEmpty()) { - return syncingResponse(requestId); + return syncingResponse(requestId, forkChoice); } - LOG.info( - "Consensus fork-choice-update: head: {}, finalized: {}, safeBlockHash: {}", - forkChoice.getHeadBlockHash(), - forkChoice.getFinalizedBlockHash(), - forkChoice.getSafeBlockHash()); - maybePayloadAttributes.ifPresentOrElse( this::logPayload, () -> LOG.debug("Payload attributes are null")); if (!isValidForkchoiceState( forkChoice.getSafeBlockHash(), forkChoice.getFinalizedBlockHash(), newHead.get())) { + logForkchoiceUpdatedCall(INVALID, forkChoice); return new JsonRpcErrorResponse(requestId, JsonRpcError.INVALID_FORKCHOICE_STATE); } // TODO: post-merge cleanup, this should be unnecessary after merge if (!mergeCoordinator.latestValidAncestorDescendsFromTerminal(newHead.get())) { + logForkchoiceUpdatedCall(INVALID, forkChoice); return new JsonRpcSuccessResponse( requestId, new EngineUpdateForkchoiceResult( @@ -137,6 +134,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) payloadAttributes.getSuggestedFeeRecipient()))); if (!result.isValid()) { + logForkchoiceUpdatedCall(INVALID, forkChoice); return handleNonValidForkchoiceUpdate(requestId, result); } @@ -158,6 +156,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) pid::toHexString, () -> maybePayloadAttributes.map(EnginePayloadAttributesParameter::serialize))); + logForkchoiceUpdatedCall(VALID, forkChoice); return new JsonRpcSuccessResponse( requestId, new EngineUpdateForkchoiceResult( @@ -256,8 +255,20 @@ private boolean isValidForkchoiceState( return mergeCoordinator.isDescendantOf(maybeSafeBlock.get(), newBlock); } - private JsonRpcResponse syncingResponse(final Object requestId) { + private JsonRpcResponse syncingResponse( + final Object requestId, final EngineForkchoiceUpdatedParameter forkChoice) { + logForkchoiceUpdatedCall(SYNCING, forkChoice); return new JsonRpcSuccessResponse( requestId, new EngineUpdateForkchoiceResult(SYNCING, null, null, Optional.empty())); } + + private void logForkchoiceUpdatedCall( + final EngineStatus status, final EngineForkchoiceUpdatedParameter forkChoice) { + LOG.info( + "{} for fork-choice-update: head: {}, finalized: {}, safeBlockHash: {}", + status.name(), + forkChoice.getHeadBlockHash(), + forkChoice.getFinalizedBlockHash(), + forkChoice.getSafeBlockHash()); + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java index dc1002a769e..0a6e4b0f2b2 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java @@ -165,6 +165,11 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) new Block(newBlockHeader, new BlockBody(transactions, Collections.emptyList())); if (mergeContext.isSyncing() || parentHeader.isEmpty()) { + LOG.info( + "isSyncing: {} parentHeaderMissing: {}, adding {} to backwardsync", + mergeContext.isSyncing(), + parentHeader.isEmpty(), + block.getHash()); mergeCoordinator .appendNewPayloadToSync(block) .exceptionally( @@ -177,6 +182,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) // TODO: post-merge cleanup if (!mergeCoordinator.latestValidAncestorDescendsFromTerminal(newBlockHeader)) { + LOG.warn("payload did not descend from terminal: {}", newBlockHeader.toLogString()); mergeCoordinator.addBadBlock(block); return respondWithInvalid( reqId, From 359c6f2da0a3bc9adb92058b9845e9555077058d Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 20 Jul 2022 13:36:07 -0600 Subject: [PATCH 029/109] 22.7.0 CHANGELOG.md (#4137) update changelog for release Signed-off-by: Danno Ferrin --- CHANGELOG.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ea40102a81..f0077276626 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,9 +8,18 @@ - Remove block header checks during backward sync, since they will be always performed during block import phase [#4098](https://github.com/hyperledger/besu/pull/4098) - Optimize the backward sync retry strategy [#4095](https://github.com/hyperledger/besu/pull/4095) - Add support for jemalloc library to better handle rocksdb memory consumption [#4126](https://github.com/hyperledger/besu/pull/4126) +- RocksDB configuration changes to improve performance. [#4132](https://github.com/hyperledger/besu/pull/4132) ### Bug Fixes -- Return the correct latest valid hash in case of bad block when calling engine methods [#4056](https://github.com/hyperledger/besu/pull/4056) +- Changed max message size in the p2p layer to 16.7MB from 10MB to improve peering performance [#4120](https://github.com/hyperledger/besu/pull/4120) +- Fixes for parent stateroot mismatch when using Bonsai storage mode (please report if you encounter this bug on this version) [#4094](https://github.com/hyperledger/besu/pull/4094) +- Above Bonsai related fixes have addressed situations where the event log was not indexed properly [#3921](https://github.com/hyperledger/besu/pull/3921) +- Fixes related to backward sync and reorgs [#4097](https://github.com/hyperledger/besu/pull/4097) +- Checkpoint sync with more merge friendly checkpoint blocks [#4085](https://github.com/hyperledger/besu/pull/4085) +- Fixes around RocksDB performance and memory usage [#4128](https://github.com/hyperledger/besu/pull/4128) +- Fix for RPC performance parallelization to improve RPC performance under heavy load [#3959](https://github.com/hyperledger/besu/pull/3959) +- Fix for post-Merge peering after PoW is removed in our logic for weighting peers [#4116](https://github.com/hyperledger/besu/pull/4116) +- Various logging changes to improve UX- Return the correct latest valid hash in case of bad block when calling engine methods [#4056](https://github.com/hyperledger/besu/pull/4056) - Add a PoS block header rule to check that the current block is more recent than its parent [#4066](https://github.com/hyperledger/besu/pull/4066) - Fixed a trie log layer issue on bonsai during reorg [#4069](https://github.com/hyperledger/besu/pull/4069) - Fix transition protocol schedule to return the pre Merge schedule when reorg pre TTD [#4078](https://github.com/hyperledger/besu/pull/4078) From 02d834518cf3e911a84cab47459a123eee7b71fd Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 20 Jul 2022 14:01:20 -0600 Subject: [PATCH 030/109] 22.7.0-RC2 release (#4138) Release 22.7.0-RC2 of Hyperledger Besu Signed-off-by: Danno Ferrin --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 3bcc64412ba..c4fce401999 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=22.7.0-RC2-SNAPSHOT +version=22.7.0-RC2 # Workaround for Java 16 and spotless bug 834 https://github.com/diffplug/spotless/issues/834 org.gradle.jvmargs=--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ From 8eb22bbaa166a0e06fd2fc305007c9541573b65a Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 20 Jul 2022 14:52:52 -0600 Subject: [PATCH 031/109] Prep 22.7.0 release (#4139) Prep snapshot of 22.7.0 Signed-off-by: Danno Ferrin --- CHANGELOG.md | 10 ++++++++++ gradle.properties | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0077276626..4961450c427 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 22.7.0 + +### Additions and Improvements + +### Bug Fixes + ## 22.7.0-RC2 ### Additions and Improvements @@ -27,6 +33,10 @@ - The build process runs successfully even though the system language is not English [#4102](https://github.com/hyperledger/besu/pull/4102) - Avoid starting or stopping the BlockPropagationManager more than once [#4122](https://github.com/hyperledger/besu/pull/4122) +### Download links +- https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/22.7.0-RC2/besu-22.7.0-RC2.tar.gz / sha256: `//FIXME` +- https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/22.7.0-RC2/besu-22.7.0-RC2.zip / sha256: `//FIXME` + ## 22.7.0-RC1 ### Additions and Improvements diff --git a/gradle.properties b/gradle.properties index c4fce401999..77ba4f70c9e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=22.7.0-RC2 +version=22.7.0-SNAPSHOT # Workaround for Java 16 and spotless bug 834 https://github.com/diffplug/spotless/issues/834 org.gradle.jvmargs=--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ From 1dd7357257b540b616cb4691e9eaa240fc52c0c2 Mon Sep 17 00:00:00 2001 From: Jiri Peinlich Date: Thu, 21 Jul 2022 14:55:29 +0200 Subject: [PATCH 032/109] Allow creating the Trie Log Layer objects outside of its package (#4096) * Allow creating Trie Log Layer objects outside of its package Signed-off-by: Jiri Peinlich * Make access public so that I can use the class outside of besu Signed-off-by: Jiri Peinlich --- .../besu/ethereum/bonsai/TrieLogLayer.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/TrieLogLayer.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/TrieLogLayer.java index 52fca5e89bb..f37e7e2cb05 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/TrieLogLayer.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/TrieLogLayer.java @@ -99,11 +99,11 @@ void addStorageChange( .put(slotHash, new BonsaiValue<>(oldValue, newValue)); } - static TrieLogLayer fromBytes(final byte[] bytes) { + public static TrieLogLayer fromBytes(final byte[] bytes) { return readFrom(new BytesValueRLPInput(Bytes.wrap(bytes), false)); } - static TrieLogLayer readFrom(final RLPInput input) { + public static TrieLogLayer readFrom(final RLPInput input) { final TrieLogLayer newLayer = new TrieLogLayer(); input.enterList(); @@ -161,7 +161,7 @@ static TrieLogLayer readFrom(final RLPInput input) { return newLayer; } - void writeTo(final RLPOutput output) { + public void writeTo(final RLPOutput output) { freeze(); final Set
addresses = new TreeSet<>(); @@ -212,23 +212,23 @@ void writeTo(final RLPOutput output) { output.endList(); // container } - Stream>> streamAccountChanges() { + public Stream>> streamAccountChanges() { return accounts.entrySet().stream(); } - Stream>> streamCodeChanges() { + public Stream>> streamCodeChanges() { return code.entrySet().stream(); } - Stream>>> streamStorageChanges() { + public Stream>>> streamStorageChanges() { return storage.entrySet().stream(); } - boolean hasStorageChanges(final Address address) { + public boolean hasStorageChanges(final Address address) { return storage.containsKey(address); } - Stream>> streamStorageChanges(final Address address) { + public Stream>> streamStorageChanges(final Address address) { return storage.getOrDefault(address, Map.of()).entrySet().stream(); } From d0c71c3bdcc1869b88781ec6bc6835a370be9c8c Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Thu, 21 Jul 2022 16:28:20 -0600 Subject: [PATCH 033/109] Remove Sonar Integration (#4135) Sonar has been removed from the build workflow. This PR removes all configuration and code markings that were used to facilitate it. Signed-off-by: Danno Ferrin --- .circleci/config.yml | 9 +--- .github/workflows/sonarcloud.yml | 41 ------------------- .../org/hyperledger/besu/cli/BesuCommand.java | 6 +-- build.gradle | 13 ------ .../besu/util/Slf4jLambdaHelper.java | 1 - 5 files changed, 4 insertions(+), 66 deletions(-) delete mode 100644 .github/workflows/sonarcloud.yml diff --git a/.circleci/config.yml b/.circleci/config.yml index 4192595610f..7c4830b45c1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -212,11 +212,6 @@ jobs: command: | ./gradlew --no-daemon build - capture_test_results -# Temporarily disabled -# - run: -# name: SonarQube -# no_output_timeout: 30m -# command: ./gradlew --no-daemon jacocoRootReport sonarqube -Dsonar.login=$SONAR_TOKEN integrationTests: executor: xl_machine_executor @@ -411,9 +406,7 @@ workflows: - dco - spotless - unitTests: -# Temporarily disabled -# context: SonarCloud - requires: + requires: - assemble - testWindows: requires: diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml deleted file mode 100644 index 8665eab6656..00000000000 --- a/.github/workflows/sonarcloud.yml +++ /dev/null @@ -1,41 +0,0 @@ - -name: SonarCloud analysis - -on: - push: - branches: [ "main", release* ] -# pull_request: -# branches: [ "main" ] - workflow_dispatch: - -permissions: - pull-requests: read # allows SonarCloud to decorate PRs with analysis results - -jobs: - Analysis: - runs-on: ubuntu-latest - - steps: - - name: Analyze with SonarCloud - - # You can pin the exact commit or the version. - # uses: SonarSource/sonarcloud-github-action@de2e56b42aa84d0b1c5b622644ac17e505c9a049 - uses: SonarSource/sonarcloud-github-action@de2e56b42aa84d0b1c5b622644ac17e505c9a049 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} # Generate a token on Sonarcloud.io, add it to the secrets of this repo with the name SONAR_TOKEN (Settings > Secrets > Actions > add new repository secret) - with: - # Additional arguments for the sonarcloud scanner - args: - # Unique keys of your project and organization. You can find them in SonarCloud > Information (bottom-left menu) - # mandatory - -Dsonar.projectKey=hyperledger_besu - -Dsonar.organization=hyperledger - # Comma-separated paths to directories containing main source files. - #-Dsonar.sources= # optional, default is project base directory - # When you need the analysis to take place in a directory other than the one from which it was launched - #-Dsonar.projectBaseDir= # optional, default is . - # Comma-separated paths to directories containing test source files. - #-Dsonar.tests= # optional. For more info about Code Coverage, please refer to https://docs.sonarcloud.io/enriching/test-coverage/overview/ - # Adds more detail to both client and server-side analysis logs, activating DEBUG mode for the scanner, and adding client-side environment variables and system properties to the server-side log of analysis report processing. - #-Dsonar.verbose= # optional, default is false diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index 4c66897c595..ce53d8cdb43 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -1190,7 +1190,7 @@ static class TxPoolOptionGroup { "Maximum number of pending transaction hashes that will be kept in the transaction pool (default: ${DEFAULT-VALUE})", arity = "1") @SuppressWarnings("unused") - private final Integer pooledTransactionHashesSize = null; // NOSONAR + private final Integer pooledTransactionHashesSize = null; @Option( names = {"--tx-pool-retention-hours"}, @@ -1906,7 +1906,7 @@ private void issueOptionWarnings() { "--privacy-flexible-groups-enabled"); } - if (txPoolOptionGroup.pooledTransactionHashesSize != null) { // NOSONAR + if (txPoolOptionGroup.pooledTransactionHashesSize != null) { logger.warn(DEPRECATED_AND_USELESS_WARNING_MSG, "--tx-pool-hashes-max-size"); } } @@ -2136,7 +2136,7 @@ private JsonRpcConfiguration createEngineJsonRpcConfiguration( engineConfig.setAuthenticationEnabled(true); engineConfig.setAuthenticationAlgorithm(JwtAlgorithm.HS256); if (Objects.nonNull(engineRPCOptionGroup.engineJwtKeyFile) - && java.nio.file.Files.exists(engineRPCOptionGroup.engineJwtKeyFile)) { // NOSONAR + && java.nio.file.Files.exists(engineRPCOptionGroup.engineJwtKeyFile)) { engineConfig.setAuthenticationPublicKeyFile(engineRPCOptionGroup.engineJwtKeyFile.toFile()); } else { logger.info( diff --git a/build.gradle b/build.gradle index 3debb574b43..71425653c21 100644 --- a/build.gradle +++ b/build.gradle @@ -28,21 +28,8 @@ plugins { id 'me.champeau.jmh' version '0.6.6' apply false id 'net.ltgt.errorprone' version '2.0.2' id 'maven-publish' - id 'org.sonarqube' version '3.4.0.2513' } -sonarqube { - properties { - property "sonar.projectKey", "hyperledger_besu" - property "sonar.organization", "hyperledger" - property "sonar.host.url", "https://sonarcloud.io" - property "sonar.coverage.jacoco.xmlReportPaths", "${buildDir}/reports/jacoco/jacocoRootReport/jacocoRootReport.xml" - property "sonar.coverage.exclusions", "acceptance-tests/**/*" - } -} - -project.tasks["sonarqube"].dependsOn "jacocoRootReport" - if (!JavaVersion.current().java11Compatible) { throw new GradleException("Java 11 or later is required to build Besu.\n" + " Detected version ${JavaVersion.current()}") diff --git a/util/src/main/java/org/hyperledger/besu/util/Slf4jLambdaHelper.java b/util/src/main/java/org/hyperledger/besu/util/Slf4jLambdaHelper.java index f0c4c907106..88481bce929 100644 --- a/util/src/main/java/org/hyperledger/besu/util/Slf4jLambdaHelper.java +++ b/util/src/main/java/org/hyperledger/besu/util/Slf4jLambdaHelper.java @@ -25,7 +25,6 @@ */ public class Slf4jLambdaHelper { - // sonar code smell private Slf4jLambdaHelper() {} public static void warnLambda( From 60895a81665486e9db1b1b6e9597dadfed4f2a3d Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Fri, 22 Jul 2022 08:55:27 +1000 Subject: [PATCH 034/109] Peering logging (#4142) * log connected/disconnected state of RemotelyInitiatedConnections * separate class for logging process message Signed-off-by: Sally MacFarlane --- .../eth/manager/EthProtocolLogger.java | 28 +++++++++++++++++++ .../eth/manager/EthProtocolManager.java | 2 +- .../internal/DiscoveryProtocolLogger.java | 2 +- .../p2p/rlpx/connections/RlpxConnection.java | 4 ++- 4 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolLogger.java diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolLogger.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolLogger.java new file mode 100644 index 00000000000..0b57488b193 --- /dev/null +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolLogger.java @@ -0,0 +1,28 @@ +/* + * Copyright Contributors to Hyperledger Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.eth.manager; + +import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EthProtocolLogger { + private static final Logger LOG = LoggerFactory.getLogger(EthProtocolLogger.class); + + public static void logProcessMessage(final Capability cap, final int code) { + LOG.trace("Process message {}, {}", cap, code); + } +} diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java index 3ce95da4389..1bee6a0205b 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java @@ -239,7 +239,7 @@ public void processMessage(final Capability cap, final Message message) { "Unsupported capability passed to processMessage(): " + cap); final MessageData messageData = message.getData(); final int code = messageData.getCode(); - LOG.trace("Process message {}, {}", cap, code); + EthProtocolLogger.logProcessMessage(cap, code); final EthPeer ethPeer = ethPeers.peer(message.getConnection()); if (ethPeer == null) { LOG.debug( diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/DiscoveryProtocolLogger.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/DiscoveryProtocolLogger.java index 5510354a5df..30f2c21945f 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/DiscoveryProtocolLogger.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/DiscoveryProtocolLogger.java @@ -47,7 +47,7 @@ public DiscoveryProtocolLogger(final MetricsSystem metricsSystem) { void logSendingPacket(final Peer peer, final Packet packet) { outgoingMessageCounter.labels(packet.getType().name()).inc(); LOG.trace( - "<<< Sending {} packet to peer {} ({}): {}", + "<<< Sending {} packet to peer {} ({}): {}", shortenPacketType(packet), peer.getId().slice(0, 16), peer.getEnodeURL(), diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/RlpxConnection.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/RlpxConnection.java index ae0ba7f4b4a..bd05f0709cf 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/RlpxConnection.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/RlpxConnection.java @@ -149,7 +149,9 @@ public String toString() { return "RemotelyInitiatedRlpxConnection initiatedAt:" + getInitiatedAt() + " to " - + peerConnection.getPeer().getId(); + + peerConnection.getPeer().getId() + + " disconnected? " + + isFailedOrDisconnected(); } } From de91d3122b218077e5df6c361c42f69d31a0a01c Mon Sep 17 00:00:00 2001 From: Stefan Pingel <16143240+pinges@users.noreply.github.com> Date: Fri, 22 Jul 2022 10:08:23 +1000 Subject: [PATCH 035/109] logging changes for peering (#4145) * logging changes for peering Signed-off-by: Stefan --- .../besu/ethereum/eth/manager/EthPeer.java | 33 ++++++++++--------- .../besu/ethereum/eth/manager/EthPeers.java | 11 ++----- .../eth/manager/EthProtocolManager.java | 6 ++-- .../connections/AbstractPeerConnection.java | 2 ++ .../p2p/rlpx/connections/netty/DeFramer.java | 2 +- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeer.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeer.java index 260aec318cc..ff7c992d713 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeer.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeer.java @@ -15,7 +15,6 @@ package org.hyperledger.besu.ethereum.eth.manager; import static com.google.common.base.Preconditions.checkArgument; -import static org.hyperledger.besu.util.Slf4jLambdaHelper.traceLambda; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -211,7 +210,7 @@ public void recordRequestTimeout(final int requestCode) { } public void recordUselessResponse(final String requestType) { - LOG.debug("Received useless response for {} from peer {}", requestType, this); + LOG.debug("Received useless response for request type {} from peer {}", requestType, this); reputation.recordUselessResponse(System.currentTimeMillis()).ifPresent(this::disconnect); } @@ -231,15 +230,13 @@ public RequestManager.ResponseStream send( final MessageData messageData, final String protocolName) throws PeerNotConnected { if (connection.getAgreedCapabilities().stream() .noneMatch(capability -> capability.getName().equalsIgnoreCase(protocolName))) { - LOG.debug("Protocol {} unavailable for this peer ", protocolName); + LOG.debug("Protocol {} unavailable for this peer {}", protocolName, this); return null; } if (permissioningProviders.stream() .anyMatch(p -> !p.isMessagePermitted(connection.getRemoteEnode(), messageData.getCode()))) { LOG.info( - "Permissioning blocked sending of message code {} to {}", - messageData.getCode(), - connection.getRemoteEnode()); + "Permissioning blocked sending of message code {} to {}", messageData.getCode(), this); if (LOG.isDebugEnabled()) { LOG.debug( "Permissioning blocked by providers {}", @@ -256,7 +253,7 @@ public RequestManager.ResponseStream send( LOG.error( "Sending {} message to peer ({}) which exceeds local message size limit of {} bytes. Message code: {}, Message Size: {}", protocolName, - connection.getRemoteEnode(), + this, maxMessageSize, messageData.getCode(), messageData.getSize()); @@ -389,9 +386,10 @@ void dispatch(final EthMessage ethMessage, final String protocolName) { requestManager -> requestManager.dispatchResponse(ethMessage), () -> { LOG.trace( - "Message {} not expected has just been received for {} ", + "Message {} not expected has just been received for protocol {}, peer {} ", messageCode, - protocolName); + protocolName, + this); }); } @@ -424,8 +422,7 @@ public PeerReputation getReputation() { } void handleDisconnect() { - traceLambda( - LOG, "handleDisconnect - peer... {}, {}", this::getShortNodeId, this::getReputation); + LOG.debug("handleDisconnect - EthPeer {}", this); requestManagers.forEach( (protocolName, map) -> map.forEach((code, requestManager) -> requestManager.close())); @@ -554,8 +551,14 @@ public boolean hasSupportForMessage(final int messageCode) { @Override public String toString() { return String.format( - "Peer %s... %s, validated? %s, disconnected? %s", - getShortNodeId(), reputation, isFullyValidated(), isDisconnected()); + "PeerId %s, reputation %s, validated? %s, disconnected? %s, client: %s, connection %s, enode %s", + nodeId(), + reputation, + isFullyValidated(), + isDisconnected(), + connection.getPeerInfo().getClientId(), + System.identityHashCode(connection), + connection.getPeer().getEnodeURLString()); } @Nonnull @@ -565,10 +568,10 @@ public String getShortNodeId() { @Override public int compareTo(final @Nonnull EthPeer ethPeer) { - int repCompare = this.reputation.compareTo(ethPeer.reputation); + final int repCompare = this.reputation.compareTo(ethPeer.reputation); if (repCompare != 0) return repCompare; - int headStateCompare = + final int headStateCompare = Long.compare( this.chainHeadState.getBestBlock().getNumber(), ethPeer.chainHeadState.getBestBlock().getNumber()); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java index 442471aadf7..c5074a2f909 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java @@ -17,7 +17,6 @@ import org.hyperledger.besu.ethereum.eth.manager.EthPeer.DisconnectCallback; import org.hyperledger.besu.ethereum.eth.peervalidation.PeerValidator; import org.hyperledger.besu.ethereum.p2p.rlpx.connections.PeerConnection; -import org.hyperledger.besu.ethereum.p2p.rlpx.wire.PeerInfo; import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.permissioning.NodeMessagePermissioningProvider; @@ -107,7 +106,8 @@ public void registerConnection( maxMessageSize, clock, permissioningProviders); - connections.putIfAbsent(peerConnection, peer); + final EthPeer ethPeer = connections.putIfAbsent(peerConnection, peer); + LOG.debug("Adding new EthPeer {}", ethPeer); } public void registerDisconnect(final PeerConnection connection) { @@ -116,12 +116,7 @@ public void registerDisconnect(final PeerConnection connection) { disconnectCallbacks.forEach(callback -> callback.onDisconnect(peer)); peer.handleDisconnect(); abortPendingRequestsAssignedToDisconnectedPeers(); - final PeerInfo peerInfo = peer.getConnection().getPeerInfo(); - LOG.debug( - "Disconnected EthPeer {}, client ID: {}, {}", - peerInfo.getNodeId(), - peerInfo.getClientId(), - peer.getReputation()); + LOG.debug("Disconnected EthPeer {}", peer); } reattemptPendingPeerRequests(); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java index 1bee6a0205b..5edcb3236d8 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java @@ -273,7 +273,7 @@ public void processMessage(final Capability cap, final Message message) { final EthMessage ethMessage = new EthMessage(ethPeer, messageData); if (!ethPeer.validateReceivedMessage(ethMessage, getSupportedProtocol())) { - LOG.debug("Unsolicited message received from, disconnecting: {}", ethPeer); + LOG.debug("Unsolicited message received, disconnecting from EthPeer: {}", ethPeer); ethPeer.disconnect(DisconnectReason.BREACH_OF_PROTOCOL); return; } @@ -360,7 +360,7 @@ private void handleStatusMessage(final EthPeer peer, final MessageData data) { final StatusMessage status = StatusMessage.readFrom(data); try { if (!status.networkId().equals(networkId)) { - LOG.debug("{} has mismatched network id: {}", peer, status.networkId()); + LOG.debug("Mismatched network id: {}, EthPeer {}", status.networkId(), peer); peer.disconnect(DisconnectReason.SUBPROTOCOL_TRIGGERED); } else if (!forkIdManager.peerCheck(status.forkId()) && status.protocolVersion() > 63) { LOG.debug( @@ -387,7 +387,7 @@ private void handleStatusMessage(final EthPeer peer, final MessageData data) { status.bestHash(), status.totalDifficulty(), status.protocolVersion()); } } catch (final RLPException e) { - LOG.debug("Unable to parse status message.", e); + LOG.debug("Unable to parse status message from peer {}.", peer, e); // Parsing errors can happen when clients broadcast network ids outside the int range, // So just disconnect with "subprotocol" error rather than "breach of protocol". peer.disconnect(DisconnectReason.SUBPROTOCOL_TRIGGERED); diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/AbstractPeerConnection.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/AbstractPeerConnection.java index 96545c474fa..e21e1800c64 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/AbstractPeerConnection.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/AbstractPeerConnection.java @@ -147,6 +147,7 @@ public void terminateConnection(final DisconnectReason reason, final boolean pee // Always ensure the context gets closed immediately even if we previously sent a disconnect // message and are waiting to close. closeConnectionImmediately(); + LOG.debug("Terminating connection {}, reason {}", System.identityHashCode(this), reason); } protected abstract void closeConnectionImmediately(); @@ -158,6 +159,7 @@ public void disconnect(final DisconnectReason reason) { if (disconnected.compareAndSet(false, true)) { connectionEventDispatcher.dispatchDisconnect(this, reason, false); doSend(null, DisconnectMessage.create(reason)); + LOG.debug("Disconnecting connection {}, reason {}", System.identityHashCode(this), reason); closeConnection(); } } diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramer.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramer.java index 11e8fc21d35..597784f9133 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramer.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramer.java @@ -241,7 +241,7 @@ public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable thr if (connectFuture.isDone() && !connectFuture.isCompletedExceptionally()) { connectFuture .get() - .terminateConnection(DisconnectMessage.DisconnectReason.TCP_SUBSYSTEM_ERROR, true); + .terminateConnection(DisconnectMessage.DisconnectReason.TCP_SUBSYSTEM_ERROR, false); } else { connectFuture.completeExceptionally(throwable); ctx.close(); From be133b8d348111ab383934e836b763df5ceb98f7 Mon Sep 17 00:00:00 2001 From: Stefan Pingel <16143240+pinges@users.noreply.github.com> Date: Fri, 22 Jul 2022 19:43:23 +1000 Subject: [PATCH 036/109] fix 1 byte long disconnect reason (#4150) Signed-off-by: Stefan --- .../ethereum/p2p/rlpx/connections/netty/DeFramer.java | 2 +- .../p2p/rlpx/wire/messages/DisconnectMessage.java | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramer.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramer.java index 597784f9133..44d325d7329 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramer.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramer.java @@ -205,7 +205,7 @@ private Optional createPeer(final PeerInfo peerInfo, final ChannelHandlerC if (remoteAddress == null) { return Optional.empty(); } - int port = peerInfo.getPort(); + final int port = peerInfo.getPort(); return Optional.of( DefaultPeer.fromEnodeURL( EnodeURLImpl.builder() diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/wire/messages/DisconnectMessage.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/wire/messages/DisconnectMessage.java index 71ffe018941..3871939ea3a 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/wire/messages/DisconnectMessage.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/wire/messages/DisconnectMessage.java @@ -80,9 +80,14 @@ public void writeTo(final RLPOutput out) { } public static Data readFrom(final RLPInput in) { - in.enterList(); - Bytes reasonData = in.readBytes(); - in.leaveList(); + Bytes reasonData = Bytes.EMPTY; + if (in.nextIsList()) { + in.enterList(); + reasonData = in.readBytes(); + in.leaveList(); + } else if (in.nextSize() == 1) { + reasonData = in.readBytes(); + } // Disconnect reason should be at most 1 byte, otherwise, just return UNKNOWN final DisconnectReason reason = From 059af013bd141bb50de7dc19328768d0433be125 Mon Sep 17 00:00:00 2001 From: Daniel Lehrner Date: Fri, 22 Jul 2022 23:01:02 +0200 Subject: [PATCH 037/109] filter out the periodic log message "Refreshing DNS records with ..." (#4155) Signed-off-by: Daniel Lehrner --- besu/src/main/resources/log4j2.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/besu/src/main/resources/log4j2.xml b/besu/src/main/resources/log4j2.xml index 166b8efa389..b43e1acfd4f 100644 --- a/besu/src/main/resources/log4j2.xml +++ b/besu/src/main/resources/log4j2.xml @@ -39,6 +39,9 @@ + + + From b7cea68d65ca058615545049e3cc981e537ed4d2 Mon Sep 17 00:00:00 2001 From: Antoine Toulme Date: Mon, 25 Jul 2022 07:00:39 +0200 Subject: [PATCH 038/109] move some easy build jobs (DCO, Spotless) over to github (#4161) Signed-off-by: Antoine Toulme --- .circleci/config.yml | 25 +------------------------ .github/workflows/checks.yml | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 24 deletions(-) create mode 100644 .github/workflows/checks.yml diff --git a/.circleci/config.yml b/.circleci/config.yml index 7c4830b45c1..106d7667324 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -137,24 +137,6 @@ jobs: destination: distributions when: always - dco: - executor: besu_executor_small - steps: - - checkout - - restore_gradle_cache - - run: - name: DCO check - command: | - ./scripts/dco_check.sh - spotless: - executor: besu_executor_small - steps: - - checkout - - restore_gradle_cache - - run: - name: Spotless - command: | - ./gradlew --no-daemon --parallel clean spotlessCheck testWindows: executor: win/default steps: @@ -399,12 +381,7 @@ workflows: version: 2 default: jobs: - - dco - - spotless - - assemble: - requires: - - dco - - spotless + - assemble - unitTests: requires: - assemble diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml new file mode 100644 index 00000000000..8fc4b98f560 --- /dev/null +++ b/.github/workflows/checks.yml @@ -0,0 +1,34 @@ +name: checks +on: + push: + branches: [ main ] + pull_request: + +jobs: + spotless: + runs-on: ubuntu-latest + if: ${{ github.actor != 'dependabot[bot]' }} + steps: + - name: Checkout Repo + uses: actions/checkout@v3 + - name: Set up Java + uses: actions/setup-java@v2 + with: + distribution: adopt + java-version: 11 + cache: gradle + - name: spotless + run: ./gradlew --no-daemon --parallel clean spotlessCheck + dco: + runs-on: ubuntu-latest + if: ${{ github.actor != 'dependabot[bot]' }} + steps: + - name: Get PR Commits + id: 'get-pr-commits' + uses: tim-actions/get-pr-commits@v1.2.0 + with: + token: ${{ secrets.GITHUB_TOKEN }} + - name: DCO Check + uses: tim-actions/dco@v1.1.0 + with: + commits: ${{ steps.get-pr-commits.outputs.commits }} \ No newline at end of file From 979988707baa7ba43e3ccd420f016637096109c6 Mon Sep 17 00:00:00 2001 From: Daniel Lehrner Date: Tue, 26 Jul 2022 11:26:28 +0200 Subject: [PATCH 039/109] Fix post merge chain reog with invalid block (#4131) * fix infinite loop if a reorg contain a bad block * add cache for latest valid ancestors for bad blocks Signed-off-by: Daniel Lehrner --- .../merge/blockcreation/MergeCoordinator.java | 64 +++++++++++++++++-- .../blockcreation/MergeMiningCoordinator.java | 2 + .../blockcreation/TransitionCoordinator.java | 5 ++ .../engine/EngineForkchoiceUpdated.java | 2 +- .../methods/engine/EngineNewPayload.java | 9 ++- .../engine/EngineForkchoiceUpdatedTest.java | 2 +- .../methods/engine/EngineNewPayloadTest.java | 6 +- .../besu/ethereum/chain/BadBlockManager.java | 10 +++ .../eth/sync/backwardsync/BackwardChain.java | 22 +++---- .../backwardsync/BackwardSyncContext.java | 39 +++++++++-- .../sync/backwardsync/BadChainListener.java | 27 ++++++++ .../backwardsync/BackwardSyncContextTest.java | 30 ++++++--- 12 files changed, 177 insertions(+), 41 deletions(-) create mode 100644 ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BadChainListener.java diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java index cd4643a0a3d..98b3728ea75 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java @@ -34,6 +34,7 @@ import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.sync.backwardsync.BackwardSyncContext; +import org.hyperledger.besu.ethereum.eth.sync.backwardsync.BadChainListener; import org.hyperledger.besu.ethereum.eth.transactions.sorter.AbstractPendingTransactionsSorter; import org.hyperledger.besu.ethereum.mainnet.AbstractGasLimitSpecification; import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; @@ -52,7 +53,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class MergeCoordinator implements MergeMiningCoordinator { +public class MergeCoordinator implements MergeMiningCoordinator, BadChainListener { private static final Logger LOG = LoggerFactory.getLogger(MergeCoordinator.class); final AtomicLong targetGasLimit; @@ -95,6 +96,8 @@ public MergeCoordinator( address.or(miningParameters::getCoinbase).orElse(Address.ZERO), this.miningParameters.getMinBlockOccupancyRatio(), parentHeader); + + this.backwardSyncContext.subscribeBadChainListener(this); } @Override @@ -243,7 +246,7 @@ public Optional getOrSyncHeaderByHash( } private Void logSyncException(final Hash blockHash, final Throwable exception) { - LOG.warn("Sync to block hash " + blockHash.toHexString() + " failed", exception); + LOG.warn("Sync to block hash " + blockHash.toHexString() + " failed", exception.getMessage()); return null; } @@ -545,6 +548,42 @@ private boolean isPayloadAttributesValid( return payloadAttributes.getTimestamp() > headBlockHeader.getTimestamp(); } + @Override + public void onBadChain( + final Block badBlock, + final List badBlockDescendants, + final List badBlockHeaderDescendants) { + LOG.trace("Adding bad block {} and all its descendants", badBlock.getHash()); + final BadBlockManager badBlockManager = getBadBlockManager(); + + final Optional parentHeader = + protocolContext.getBlockchain().getBlockHeader(badBlock.getHeader().getParentHash()); + final Optional maybeLatestValidHash = + parentHeader.isPresent() && isPoSHeader(parentHeader.get()) + ? Optional.of(parentHeader.get().getHash()) + : Optional.empty(); + + badBlockManager.addBadBlock(badBlock); + + badBlockDescendants.forEach( + block -> { + LOG.trace("Add descendant block {} to bad blocks", block.getHash()); + badBlockManager.addBadBlock(block); + maybeLatestValidHash.ifPresent( + latestValidHash -> + badBlockManager.addLatestValidHash(block.getHash(), latestValidHash)); + }); + + badBlockHeaderDescendants.forEach( + header -> { + LOG.trace("Add descendant header {} to bad blocks", header.getHash()); + badBlockManager.addBadHeader(header); + maybeLatestValidHash.ifPresent( + latestValidHash -> + badBlockManager.addLatestValidHash(header.getHash(), latestValidHash)); + }); + } + @FunctionalInterface interface MergeBlockCreatorFactory { MergeBlockCreator forParams(BlockHeader header, Optional
feeRecipient); @@ -560,11 +599,28 @@ public void addBadBlock(final Block block) { @Override public boolean isBadBlock(final Hash blockHash) { + final BadBlockManager badBlocksManager = getBadBlockManager(); + return badBlocksManager.getBadBlock(blockHash).isPresent() + || badBlocksManager.getBadHash(blockHash).isPresent(); + } + + private BadBlockManager getBadBlockManager() { final BadBlockManager badBlocksManager = protocolSchedule .getByBlockNumber(protocolContext.getBlockchain().getChainHeadBlockNumber()) .getBadBlocksManager(); - return badBlocksManager.getBadBlock(blockHash).isPresent() - || badBlocksManager.getBadHash(blockHash).isPresent(); + return badBlocksManager; + } + + @Override + public Optional getLatestValidHashOfBadBlock(Hash blockHash) { + return protocolSchedule + .getByBlockNumber(protocolContext.getBlockchain().getChainHeadBlockNumber()) + .getBadBlocksManager() + .getLatestValidHash(blockHash); + } + + private boolean isPoSHeader(final BlockHeader header) { + return header.getDifficulty().equals(Difficulty.ZERO); } } diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeMiningCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeMiningCoordinator.java index 836aa74fb90..b5f616520a7 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeMiningCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeMiningCoordinator.java @@ -68,6 +68,8 @@ ForkchoiceResult updateForkChoice( boolean isBadBlock(Hash blockHash); + Optional getLatestValidHashOfBadBlock(final Hash blockHash); + class ForkchoiceResult { public enum Status { VALID, diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java index 01ee8c4afc2..e8d968e17ea 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java @@ -208,4 +208,9 @@ public void addBadBlock(final Block block) { public boolean isBadBlock(final Hash blockHash) { return mergeCoordinator.isBadBlock(blockHash); } + + @Override + public Optional getLatestValidHashOfBadBlock(final Hash blockHash) { + return mergeCoordinator.getLatestValidHashOfBadBlock(blockHash); + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdated.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdated.java index 6ec375dc8ca..d1773fa759e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdated.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdated.java @@ -87,7 +87,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) new EngineUpdateForkchoiceResult( INVALID, mergeCoordinator - .getLatestValidAncestor(forkChoice.getHeadBlockHash()) + .getLatestValidHashOfBadBlock(forkChoice.getHeadBlockHash()) .orElse(Hash.ZERO), null, Optional.of(forkChoice.getHeadBlockHash() + " is an invalid block"))); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java index 0a6e4b0f2b2..f71d049fc1a 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java @@ -141,11 +141,13 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) LOG.debug("block already present"); return respondWith(reqId, blockParam, blockParam.getBlockHash(), VALID); } - if (mergeCoordinator.isBadBlock(blockParam.getParentHash())) { + if (mergeCoordinator.isBadBlock(blockParam.getBlockHash())) { return respondWith( reqId, blockParam, - mergeCoordinator.getLatestValidAncestor(blockParam.getParentHash()).orElse(Hash.ZERO), + mergeCoordinator + .getLatestValidHashOfBadBlock(blockParam.getBlockHash()) + .orElse(Hash.ZERO), INVALID); } @@ -174,7 +176,8 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) .appendNewPayloadToSync(block) .exceptionally( exception -> { - LOG.warn("Sync to block " + block.toLogString() + " failed", exception); + LOG.warn( + "Sync to block " + block.toLogString() + " failed", exception.getMessage()); return null; }); return respondWith(reqId, blockParam, null, SYNCING); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedTest.java index 6f0537a72d3..b95724218be 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedTest.java @@ -123,7 +123,7 @@ public void shouldReturnInvalidWithLatestValidHashOnBadBlock() { BlockHeader mockHeader = new BlockHeaderTestFixture().baseFeePerGas(Wei.ONE).buildHeader(); Hash latestValidHash = Hash.hash(Bytes32.fromHexStringLenient("0xcafebabe")); when(mergeCoordinator.isBadBlock(mockHeader.getHash())).thenReturn(true); - when(mergeCoordinator.getLatestValidAncestor(mockHeader.getHash())) + when(mergeCoordinator.getLatestValidHashOfBadBlock(mockHeader.getHash())) .thenReturn(Optional.of(latestValidHash)); assertSuccessWithPayloadForForkchoiceResult( diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java index e17cc083854..c98a42e5187 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java @@ -184,13 +184,13 @@ public void shouldReturnInvalidOnBadTerminalBlock() { } @Test - public void shouldReturnInvalidWithLatestValidHashIfDescendingFromBadBlock() { + public void shouldReturnInvalidWithLatestValidHashIsABadBlock() { BlockHeader mockHeader = createBlockHeader(); Hash latestValidHash = Hash.hash(Bytes32.fromHexStringLenient("0xcafebabe")); when(blockchain.getBlockByHash(mockHeader.getHash())).thenReturn(Optional.empty()); - when(mergeCoordinator.isBadBlock(mockHeader.getParentHash())).thenReturn(true); - when(mergeCoordinator.getLatestValidAncestor(mockHeader.getParentHash())) + when(mergeCoordinator.isBadBlock(mockHeader.getHash())).thenReturn(true); + when(mergeCoordinator.getLatestValidHashOfBadBlock(mockHeader.getHash())) .thenReturn(Optional.of(latestValidHash)); var resp = resp(mockPayload(mockHeader, Collections.emptyList())); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BadBlockManager.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BadBlockManager.java index acc412c681c..b60bbed6f27 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BadBlockManager.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BadBlockManager.java @@ -30,6 +30,8 @@ public class BadBlockManager { CacheBuilder.newBuilder().maximumSize(100).concurrencyLevel(1).build(); private final Cache badHeaders = CacheBuilder.newBuilder().maximumSize(100).concurrencyLevel(1).build(); + private final Cache latestValidHashes = + CacheBuilder.newBuilder().maximumSize(100).concurrencyLevel(1).build(); /** * Add a new invalid block. @@ -68,4 +70,12 @@ public void addBadHeader(final BlockHeader header) { public Optional getBadHash(final Hash blockHash) { return Optional.ofNullable(badHeaders.getIfPresent(blockHash)); } + + public void addLatestValidHash(final Hash blockHash, final Hash latestValidHash) { + this.latestValidHashes.put(blockHash, latestValidHash); + } + + public Optional getLatestValidHash(final Hash blockHash) { + return Optional.ofNullable(latestValidHashes.getIfPresent(blockHash)); + } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardChain.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardChain.java index 8453476e732..94dfa89ef66 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardChain.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardChain.java @@ -19,7 +19,6 @@ import static org.slf4j.LoggerFactory.getLogger; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.ethereum.chain.BadBlockManager; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; @@ -160,6 +159,14 @@ public synchronized void clear() { hashesToAppend.clear(); } + public synchronized Optional getDescendant(final Hash blockHash) { + return chainStorage.get(blockHash); + } + + public synchronized Optional getBlock(final Hash hash) { + return blocks.get(hash); + } + public synchronized Optional getHeader(final Hash hash) { return headers.get(hash); } @@ -180,17 +187,4 @@ public synchronized void removeFromHashToAppend(final Hash hashToRemove) { hashesToAppend.remove(hashToRemove); } } - - public void addBadChainToManager(final BadBlockManager badBlocksManager, final Hash hash) { - final Optional ancestor = chainStorage.get(hash); - while (ancestor.isPresent()) { - final Optional block = blocks.get(ancestor.get()); - if (block.isPresent()) { - badBlocksManager.addBadBlock(block.get()); - } else { - final Optional blockHeader = headers.get(ancestor.get()); - blockHeader.ifPresent(badBlocksManager::addBadHeader); - } - } - } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java index 8ce71fe0423..25a6a9582b9 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java @@ -21,16 +21,19 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.BlockValidator; import org.hyperledger.besu.ethereum.ProtocolContext; -import org.hyperledger.besu.ethereum.chain.BadBlockManager; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.plugin.services.MetricsSystem; +import org.hyperledger.besu.util.Subscribers; import java.time.Duration; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; @@ -64,6 +67,8 @@ public class BackwardSyncContext { private final long millisBetweenRetries = DEFAULT_MILLIS_BETWEEN_RETRIES; + private final Subscribers badChainListeners = Subscribers.create(); + public BackwardSyncContext( final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, @@ -277,6 +282,10 @@ public CompletableFuture stop() { return currentBackwardSyncFuture.get(); } + public void subscribeBadChainListener(final BadChainListener badChainListener) { + badChainListeners.subscribe(badChainListener); + } + // In rare case when we request too many headers/blocks we get response that does not contain all // data and we might want to retry with smaller batch size public int getBatchSize() { @@ -308,12 +317,7 @@ protected Void saveBlock(final Block block) { .appendBlock(block, optResult.blockProcessingOutputs.get().receipts); possiblyMoveHead(block); } else { - final BadBlockManager badBlocksManager = - protocolSchedule - .getByBlockNumber(getProtocolContext().getBlockchain().getChainHeadBlockNumber()) - .getBadBlocksManager(); - badBlocksManager.addBadBlock(block); - getBackwardChain().addBadChainToManager(badBlocksManager, block.getHash()); + emitBadChainEvent(block); throw new BackwardSyncException( "Cannot save block " + block.toLogString() @@ -360,4 +364,25 @@ public Optional findMaybeFinalized() { .map(Optional::get) .findFirst(); } + + private void emitBadChainEvent(final Block badBlock) { + final List badBlockDescendants = new ArrayList<>(); + final List badBlockHeaderDescendants = new ArrayList<>(); + + Optional descendant = backwardChain.getDescendant(badBlock.getHash()); + + while (descendant.isPresent()) { + final Optional block = backwardChain.getBlock(descendant.get()); + if (block.isPresent()) { + badBlockDescendants.add(block.get()); + } else { + backwardChain.getHeader(descendant.get()).ifPresent(badBlockHeaderDescendants::add); + } + + descendant = backwardChain.getDescendant(descendant.get()); + } + + badChainListeners.forEach( + listener -> listener.onBadChain(badBlock, badBlockDescendants, badBlockHeaderDescendants)); + } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BadChainListener.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BadChainListener.java new file mode 100644 index 00000000000..1e88f6d659c --- /dev/null +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BadChainListener.java @@ -0,0 +1,27 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.eth.sync.backwardsync; + +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockHeader; + +import java.util.List; + +public interface BadChainListener { + void onBadChain( + final Block badBlock, + final List badBlockDescendants, + final List badBlockHeaderDescendants); +} diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java index 57bb2345a65..d09d2927f11 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java @@ -23,7 +23,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -32,7 +31,6 @@ import org.hyperledger.besu.ethereum.BlockValidator; import org.hyperledger.besu.ethereum.BlockValidator.Result; import org.hyperledger.besu.ethereum.ProtocolContext; -import org.hyperledger.besu.ethereum.chain.BadBlockManager; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; @@ -52,6 +50,7 @@ import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; +import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -276,21 +275,36 @@ public void shouldProcessExceptionsCorrectly() { } @Test - public void makeSureWeRememberBadBlocks() { + public void shouldEmitBadChainEvent() { Block block = Mockito.mock(Block.class); - when(block.getHash()).thenReturn(Hash.ZERO); + BlockHeader blockHeader = Mockito.mock(BlockHeader.class); + when(block.getHash()).thenReturn(Hash.fromHexStringLenient("0x42")); + when(block.getHeader()).thenReturn(blockHeader); + when(blockHeader.getHash()).thenReturn(Hash.fromHexStringLenient("0x42")); + BadChainListener badChainListener = Mockito.mock(BadChainListener.class); + context.subscribeBadChainListener(badChainListener); + + BlockHeader childBlockHeader = + remoteBlockchain.getBlockByNumber(LOCAL_HEIGHT + 2).get().getHeader(); + BlockHeader grandChildBlockHeader = + remoteBlockchain.getBlockByNumber(LOCAL_HEIGHT + 1).get().getHeader(); + + backwardChain.clear(); + backwardChain.prependAncestorsHeader(grandChildBlockHeader); + backwardChain.prependAncestorsHeader(childBlockHeader); + backwardChain.prependAncestorsHeader(block.getHeader()); + doReturn(blockValidator).when(context).getBlockValidatorForBlock(any()); Result result = new Result("custom error"); doReturn(result).when(blockValidator).validateAndProcessBlock(any(), any(), any(), any()); - final BadBlockManager manager = mock(BadBlockManager.class); - doReturn(manager).when(mockProtocolSpec).getBadBlocksManager(); - assertThatThrownBy(() -> context.saveBlock(block)) .isInstanceOf(BackwardSyncException.class) .hasMessageContaining("custom error"); - Mockito.verify(manager).addBadBlock(block); + Mockito.verify(badChainListener) + .onBadChain( + block, Collections.emptyList(), List.of(childBlockHeader, grandChildBlockHeader)); } @Test From 0a2d80518fe59aec1177051d4eeb418bfb745bbb Mon Sep 17 00:00:00 2001 From: Daniel Lehrner Date: Tue, 26 Jul 2022 17:11:24 +0200 Subject: [PATCH 040/109] Change expiration for JWT authentification of engine port to 60 seconds (#4168) * change expiration for JWT authentification of engine port to 60 seconds Signed-off-by: Daniel Lehrner --- CHANGELOG.md | 1 + .../api/jsonrpc/authentication/EngineAuthService.java | 4 +++- .../jsonrpc/authentication/EngineAuthServiceTest.java | 11 +++-------- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4961450c427..24de4623e56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 22.7.0 ### Additions and Improvements +- Engine API: Change expiration time for JWT tokens to 60s [#4168](https://github.com/hyperledger/besu/pull/4168) ### Bug Fixes diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/EngineAuthService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/EngineAuthService.java index 12a5f67ac49..e6120ac29e1 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/EngineAuthService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/EngineAuthService.java @@ -44,6 +44,8 @@ public class EngineAuthService implements AuthenticationService { private static final Logger LOG = LoggerFactory.getLogger(EngineAuthService.class); + private static final int JWT_EXPIRATION_TIME = 60; + private final JWTAuth jwtAuthProvider; public EngineAuthService(final Vertx vertx, final Optional signingKey, final Path datadir) { @@ -167,6 +169,6 @@ public boolean isPermitted( private boolean issuedRecently(final long iat) { long iatSecondsSinceEpoch = iat; long nowSecondsSinceEpoch = System.currentTimeMillis() / 1000; - return (Math.abs((nowSecondsSinceEpoch - iatSecondsSinceEpoch)) <= 5); + return (Math.abs((nowSecondsSinceEpoch - iatSecondsSinceEpoch)) <= JWT_EXPIRATION_TIME); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/EngineAuthServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/EngineAuthServiceTest.java index 9cf3e00c890..d8fb363385a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/EngineAuthServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/authentication/EngineAuthServiceTest.java @@ -110,15 +110,10 @@ public void denyExpired() throws IOException, URISyntaxException { assertThat(auth).isNotNull(); JWTAuth jwtAuth = auth.getJwtAuthProvider(); String token = - jwtAuth.generateToken(new JsonObject().put("iat", (System.currentTimeMillis() / 1000) - 6)); + jwtAuth.generateToken( + new JsonObject().put("iat", (System.currentTimeMillis() / 1000) - 61)); - Handler> authHandler = - new Handler>() { - @Override - public void handle(final Optional event) { - assertThat(event).isEmpty(); - } - }; + Handler> authHandler = event -> assertThat(event).isEmpty(); auth.authenticate(token, authHandler); } } From e0b4d88786c0610b5c9d5399934da10547406789 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Tue, 26 Jul 2022 09:18:08 -0700 Subject: [PATCH 041/109] add goerli ttd (#4160) Signed-off-by: garyschulte --- config/src/main/resources/goerli.json | 1 + .../hyperledger/besu/config/GenesisConfigFileTest.java | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/config/src/main/resources/goerli.json b/config/src/main/resources/goerli.json index 12e52390c24..41283aa7d67 100644 --- a/config/src/main/resources/goerli.json +++ b/config/src/main/resources/goerli.json @@ -5,6 +5,7 @@ "istanbulBlock":1561651, "berlinBlock":4460644, "londonBlock":5062605, + "terminalTotalDifficulty": 10790000, "clique":{ "blockperiodseconds":15, "epochlength":30000 diff --git a/config/src/test/java/org/hyperledger/besu/config/GenesisConfigFileTest.java b/config/src/test/java/org/hyperledger/besu/config/GenesisConfigFileTest.java index 3992a0c99f9..677d0e5152b 100644 --- a/config/src/test/java/org/hyperledger/besu/config/GenesisConfigFileTest.java +++ b/config/src/test/java/org/hyperledger/besu/config/GenesisConfigFileTest.java @@ -208,6 +208,16 @@ public void assertRopstenTerminalTotalDifficulty() { .isEqualTo(UInt256.valueOf(new BigInteger("50000000000000000"))); } + @Test + public void assertGoerliTerminalTotalDifficulty() { + GenesisConfigOptions goerliOptions = + GenesisConfigFile.genesisFileFromResources("/goerli.json").getConfigOptions(); + + assertThat(goerliOptions.getTerminalTotalDifficulty()).isPresent(); + assertThat(goerliOptions.getTerminalTotalDifficulty().get()) + .isEqualTo(UInt256.valueOf(new BigInteger("10790000"))); + } + @Test public void assertTerminalTotalDifficultyOverride() { GenesisConfigOptions ropstenOverrideOptions = From 01d077bd65d69228a9056b5740572397712edb85 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Tue, 26 Jul 2022 10:25:05 -0700 Subject: [PATCH 042/109] add sepolia mergeNetSplit block (#4158) * add sepolia paris / mergeNetSplit block * fix test looking for old premerge fork alias, add sepolia terminal conditions test * rename to mergeNetSplit, ditch the terminalBlockHash and terminalBlockNumber configs for sepolia Signed-off-by: garyschulte --- .../org/hyperledger/besu/ForkIdsTest.java | 7 ++++ .../besu/config/GenesisConfigOptions.java | 2 +- .../besu/config/JsonGenesisConfigOptions.java | 16 ++------ .../besu/config/StubGenesisConfigOptions.java | 12 +++--- config/src/main/resources/kiln.json | 2 +- config/src/main/resources/sepolia.json | 1 + .../besu/config/GenesisConfigFileTest.java | 40 +++++++++---------- config/src/test/resources/all_forks.json | 2 +- .../mainnet/ProtocolScheduleBuilder.java | 2 +- .../besu/ethereum/eth/ForkIdTestUtil.java | 9 +++++ .../ethereum/eth/manager/EIP2124Test.java | 17 ++++++++ .../ReferenceTestProtocolSchedules.java | 2 + .../retesteth/methods/TestSetChainParams.java | 1 + 13 files changed, 69 insertions(+), 44 deletions(-) diff --git a/besu/src/test/java/org/hyperledger/besu/ForkIdsTest.java b/besu/src/test/java/org/hyperledger/besu/ForkIdsTest.java index 98940b4981d..78dacb83daf 100644 --- a/besu/src/test/java/org/hyperledger/besu/ForkIdsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/ForkIdsTest.java @@ -56,6 +56,13 @@ public class ForkIdsTest { @Parameterized.Parameters(name = "{0}") public static Collection parameters() { return List.of( + new Object[] { + NetworkName.SEPOLIA, + List.of( + new ForkId(Bytes.ofUnsignedInt(0xfe3366e7L), 1735371L), + new ForkId(Bytes.ofUnsignedInt(0xb96cbd13L), 0L), + new ForkId(Bytes.ofUnsignedInt(0xb96cbd13L), 0L)) + }, new Object[] { NetworkName.ROPSTEN, List.of( diff --git a/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java index f1eef229d8c..341bb638692 100644 --- a/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java @@ -88,7 +88,7 @@ default boolean isConsensusMigration() { OptionalLong getGrayGlacierBlockNumber(); - OptionalLong getParisBlockNumber(); + OptionalLong getMergeNetSplitBlockNumber(); Optional getBaseFeePerGas(); diff --git a/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java index 1158f33bef7..66b81c2b81e 100644 --- a/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java @@ -33,7 +33,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Streams; import org.apache.tuweni.units.bigints.UInt256; public class JsonGenesisConfigOptions implements GenesisConfigOptions { @@ -281,14 +280,8 @@ public OptionalLong getGrayGlacierBlockNumber() { } @Override - public OptionalLong getParisBlockNumber() { - var parisBlock = getOptionalLong("parisblock"); - var preMergeAlias = getOptionalLong("premergeforkblock"); - if (parisBlock.isPresent() && preMergeAlias.isPresent()) { - throw new RuntimeException( - "Found both paris and preMergeFork blocks. Should have one or the other"); - } - return Streams.concat(parisBlock.stream(), preMergeAlias.stream()).findFirst(); + public OptionalLong getMergeNetSplitBlockNumber() { + return getOptionalLong("mergenetsplitblock"); } @Override @@ -447,7 +440,7 @@ public Map asMap() { getLondonBlockNumber().ifPresent(l -> builder.put("londonBlock", l)); getArrowGlacierBlockNumber().ifPresent(l -> builder.put("arrowGlacierBlock", l)); getGrayGlacierBlockNumber().ifPresent(l -> builder.put("grayGlacierBlock", l)); - getParisBlockNumber().ifPresent(l -> builder.put("parisBlock", l)); + getMergeNetSplitBlockNumber().ifPresent(l -> builder.put("mergeNetSplitBlock", l)); getTerminalBlockNumber().ifPresent(l -> builder.put("terminalBlockNumber", l)); getTerminalBlockHash().ifPresent(h -> builder.put("terminalBlockHash", h.toHexString())); @@ -566,8 +559,7 @@ public List getForks() { getLondonBlockNumber(), getArrowGlacierBlockNumber(), getGrayGlacierBlockNumber(), - getParisBlockNumber(), - getTerminalBlockNumber(), + getMergeNetSplitBlockNumber(), getEcip1015BlockNumber(), getDieHardBlockNumber(), getGothamBlockNumber(), diff --git a/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java index 882eac9d64d..3aa5b04a8e4 100644 --- a/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java @@ -43,7 +43,7 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions { private OptionalLong londonBlockNumber = OptionalLong.empty(); private OptionalLong arrowGlacierBlockNumber = OptionalLong.empty(); private OptionalLong grayGlacierBlockNumber = OptionalLong.empty(); - private OptionalLong parisBlockNumber = OptionalLong.empty(); + private OptionalLong mergeNetSplitBlockNumber = OptionalLong.empty(); private OptionalLong terminalBlockNumber = OptionalLong.empty(); private Optional terminalBlockHash = Optional.empty(); private Optional terminalTotalDifficulty = Optional.empty(); @@ -212,8 +212,8 @@ public OptionalLong getGrayGlacierBlockNumber() { } @Override - public OptionalLong getParisBlockNumber() { - return parisBlockNumber; + public OptionalLong getMergeNetSplitBlockNumber() { + return mergeNetSplitBlockNumber; } @Override @@ -343,7 +343,7 @@ public Map asMap() { getLondonBlockNumber().ifPresent(l -> builder.put("londonBlock", l)); getArrowGlacierBlockNumber().ifPresent(l -> builder.put("arrowGlacierBlock", l)); getGrayGlacierBlockNumber().ifPresent(l -> builder.put("grayGlacierBlock", l)); - getParisBlockNumber().ifPresent(l -> builder.put("parisBlock", l)); + getMergeNetSplitBlockNumber().ifPresent(l -> builder.put("mergeNetSplitBlock", l)); getTerminalBlockNumber().ifPresent(l -> builder.put("terminalBlockNumber", l)); getTerminalBlockHash().ifPresent(h -> builder.put("terminalBlockHash", h)); // classic fork blocks @@ -477,8 +477,8 @@ public StubGenesisConfigOptions grayGlacierBlock(final long blockNumber) { return this; } - public StubGenesisConfigOptions parisBlock(final long blockNumber) { - parisBlockNumber = OptionalLong.of(blockNumber); + public StubGenesisConfigOptions mergeNetSplitBlock(final long blockNumber) { + mergeNetSplitBlockNumber = OptionalLong.of(blockNumber); return this; } diff --git a/config/src/main/resources/kiln.json b/config/src/main/resources/kiln.json index e2b93d8cf9c..9808a3b2de8 100644 --- a/config/src/main/resources/kiln.json +++ b/config/src/main/resources/kiln.json @@ -12,7 +12,7 @@ "istanbulBlock": 0, "berlinBlock": 0, "londonBlock": 0, - "parisBlock": 1000, + "mergeNetSplitBlock": 1000, "terminalTotalDifficulty": 20000000000000, "discovery": { "bootnodes": [ diff --git a/config/src/main/resources/sepolia.json b/config/src/main/resources/sepolia.json index d560a5e415e..b1751b86e9d 100644 --- a/config/src/main/resources/sepolia.json +++ b/config/src/main/resources/sepolia.json @@ -11,6 +11,7 @@ "istanbulBlock":0, "berlinBlock":0, "londonBlock":0, + "mergeNetSplitBlock": 1735371, "terminalTotalDifficulty": 17000000000000000, "ethash":{}, "discovery": { diff --git a/config/src/test/java/org/hyperledger/besu/config/GenesisConfigFileTest.java b/config/src/test/java/org/hyperledger/besu/config/GenesisConfigFileTest.java index 677d0e5152b..3112f908377 100644 --- a/config/src/test/java/org/hyperledger/besu/config/GenesisConfigFileTest.java +++ b/config/src/test/java/org/hyperledger/besu/config/GenesisConfigFileTest.java @@ -208,6 +208,16 @@ public void assertRopstenTerminalTotalDifficulty() { .isEqualTo(UInt256.valueOf(new BigInteger("50000000000000000"))); } + @Test + public void assertSepoliaTerminalTotalDifficulty() { + GenesisConfigOptions sepoliaOptions = + GenesisConfigFile.genesisFileFromResources("/sepolia.json").getConfigOptions(); + + assertThat(sepoliaOptions.getTerminalTotalDifficulty()).isPresent(); + assertThat(sepoliaOptions.getTerminalTotalDifficulty().get()) + .isEqualTo(UInt256.valueOf(new BigInteger("17000000000000000"))); + } + @Test public void assertGoerliTerminalTotalDifficulty() { GenesisConfigOptions goerliOptions = @@ -230,34 +240,20 @@ public void assertTerminalTotalDifficultyOverride() { } @Test - public void shouldFindParisForkAndAlias() { - GenesisConfigFile parisGenesis = - GenesisConfigFile.fromConfig("{\"config\":{\"parisBlock\":10},\"baseFeePerGas\":\"0xa\"}"); - assertThat(parisGenesis.getForks()).hasSize(1); - assertThat(parisGenesis.getConfigOptions().getParisBlockNumber()).isPresent(); - assertThat(parisGenesis.getConfigOptions().getParisBlockNumber().getAsLong()).isEqualTo(10L); - - GenesisConfigFile premergeForkGenesis = + public void shouldFindMergeNetSplitForkAndAlias() { + GenesisConfigFile mergeNetSplitGenesis = GenesisConfigFile.fromConfig( - "{\"config\":{\"preMergeForkBlock\":11},\"baseFeePerGas\":\"0xa\"}"); - assertThat(premergeForkGenesis.getForks()).hasSize(1); - assertThat(premergeForkGenesis.getConfigOptions().getParisBlockNumber()).isPresent(); - assertThat(premergeForkGenesis.getConfigOptions().getParisBlockNumber().getAsLong()) + "{\"config\":{\"mergeNetsplitBlock\":11},\"baseFeePerGas\":\"0xa\"}"); + assertThat(mergeNetSplitGenesis.getForks()).hasSize(1); + assertThat(mergeNetSplitGenesis.getConfigOptions().getMergeNetSplitBlockNumber()).isPresent(); + assertThat(mergeNetSplitGenesis.getConfigOptions().getMergeNetSplitBlockNumber().getAsLong()) .isEqualTo(11L); - // assert fail if both paris and alias are present - var dupeOptions = - GenesisConfigFile.fromConfig( - "{\"config\":{\"parisBlock\":10,\"preMergeForkBlock\":11},\"baseFeePerGas\":\"0xa\"}") - .getConfigOptions(); - assertThatThrownBy(() -> dupeOptions.getParisBlockNumber()) - .isInstanceOf(RuntimeException.class); - - // assert empty if neither are present: + // assert empty if not present: GenesisConfigFile londonGenesis = GenesisConfigFile.fromConfig("{\"config\":{\"londonBlock\":11},\"baseFeePerGas\":\"0xa\"}"); assertThat(londonGenesis.getForks()).hasSize(1); - assertThat(londonGenesis.getConfigOptions().getParisBlockNumber()).isEmpty(); + assertThat(londonGenesis.getConfigOptions().getMergeNetSplitBlockNumber()).isEmpty(); } @Test diff --git a/config/src/test/resources/all_forks.json b/config/src/test/resources/all_forks.json index 567d6aeac0d..fee4fa4bda5 100644 --- a/config/src/test/resources/all_forks.json +++ b/config/src/test/resources/all_forks.json @@ -13,7 +13,7 @@ "londonBlock": 11, "arrowGlacierBlock": 12, "grayGlacierBlock": 13, - "parisBlock": 14, + "mergeNetSplitBlock": 14, "ecip1015Block": 102, "dieHardBlock": 103, "gothamBlock": 104, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java index 3fccd7b6f43..40d5f08a54a 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java @@ -233,7 +233,7 @@ private TreeMap buildMilestoneMap( specFactory.arrowGlacierDefinition(config)), create( config.getGrayGlacierBlockNumber(), specFactory.grayGlacierDefinition(config)), - create(config.getParisBlockNumber(), specFactory.parisDefinition(config)), + create(config.getMergeNetSplitBlockNumber(), specFactory.parisDefinition(config)), // Classic Milestones create(config.getEcip1015BlockNumber(), specFactory.tangerineWhistleDefinition()), create(config.getDieHardBlockNumber(), specFactory.dieHardDefinition()), diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/ForkIdTestUtil.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/ForkIdTestUtil.java index 0905aafe495..e9c8b8dfb4f 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/ForkIdTestUtil.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/ForkIdTestUtil.java @@ -52,6 +52,8 @@ public static class GenesisHash { "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"; public static final String ROPSTEN = "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"; + public static final String SEPOLIA = + "0x25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9"; public static final String RINKEBY = "0x6341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177"; public static final String GOERLI = @@ -67,6 +69,8 @@ public static class Forks { 9069000L, 9200000L, 12244000L, 12965000L, 13773000L, 15050000L); public static final List ROPSTEN = Arrays.asList(0L, 0L, 10L, 1700000L, 4230000L, 4939394L, 6485846L, 7117117L); + public static final List SEPOLIA = + Arrays.asList(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1735371L); public static final List RINKEBY = Arrays.asList(1L, 2L, 3L, 3L, 1035301L, 3660663L, 4321234L, 5435345L); public static final List GOERLI = Arrays.asList(0L, 0L, 0L, 0L, 0L, 0L, 0L, 1561651L); @@ -99,6 +103,10 @@ public static class ForkIds { new ForkId(Bytes.fromHexString("0xd6e2149b"), 6485846L), new ForkId(Bytes.fromHexString("0x4bc66396"), 7117117L), new ForkId(Bytes.fromHexString("0x6727ef90"), 0L)); + public static final List SEPOLIA = + Arrays.asList( + new ForkId(Bytes.fromHexString("0xfe3366e7"), 1735371L), + new ForkId(Bytes.fromHexString("0xb96cbd13"), 0L)); public static final List RINKEBY = Arrays.asList( new ForkId(Bytes.fromHexString("0x3b8e0691"), 1L), @@ -118,6 +126,7 @@ public static class ForkIds { public static class Network { public static final Network MAINNET = network(GenesisHash.MAINNET, Forks.MAINNET); public static final Network ROPSTEN = network(GenesisHash.ROPSTEN, Forks.ROPSTEN); + public static final Network SEPOLIA = network(GenesisHash.SEPOLIA, Forks.SEPOLIA); public static final Network RINKEBY = network(GenesisHash.RINKEBY, Forks.RINKEBY); public static final Network GOERLI = network(GenesisHash.GOERLI, Forks.GOERLI); public static final Network PRIVATE = network(GenesisHash.PRIVATE, Forks.PRIVATE); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EIP2124Test.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EIP2124Test.java index 8b1df3f12a9..90bff710043 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EIP2124Test.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EIP2124Test.java @@ -353,6 +353,23 @@ public static Collection data() { Optional.of(ForkIds.ROPSTEN), empty() }, + // Sepolia test cases + { + "Sepolia // mergenetsplit block", + Network.SEPOLIA, + 0L, + ForkIdTestUtil.wantForkId("0xfe3366e7", 1735371L), + Optional.of(ForkIds.SEPOLIA), + empty() + }, + { + "Sepolia // Future", + Network.SEPOLIA, + 1735371L, + ForkIdTestUtil.wantForkId("0xb96cbd13", 0L), + Optional.of(ForkIds.SEPOLIA), + empty() + }, // Rinkeby test cases { "Rinkeby // Unsynced, last Frontier block", diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java index c277f28e1e7..38cc3af14ef 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java @@ -68,6 +68,8 @@ public static ReferenceTestProtocolSchedules create() { builder.put( "ArrowGlacier", createSchedule(new StubGenesisConfigOptions().arrowGlacierBlock(0))); builder.put("GrayGlacier", createSchedule(new StubGenesisConfigOptions().grayGlacierBlock(0))); + builder.put( + "MergeNetSplit", createSchedule(new StubGenesisConfigOptions().mergeNetSplitBlock(0))); return new ReferenceTestProtocolSchedules(builder.build()); } diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestSetChainParams.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestSetChainParams.java index 30de53effc1..e5c80595af2 100644 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestSetChainParams.java +++ b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestSetChainParams.java @@ -125,6 +125,7 @@ private static String modifyGenesisFile(final String initialGenesis) { maybeMoveToNumber(params, "londonForkBlock", config, "londonBlock"); maybeMoveToNumber(params, "arrowGlacierForkBlock", config, "arrowGlacierBlock"); maybeMoveToNumber(params, "grayGlacierForkBlock", config, "grayGlacierBlock"); + maybeMoveToNumber(params, "mergeNetSplitForkBlock", config, "mergeNetSplitBlock"); maybeMoveToNumber(params, "chainID", config, "chainId", 1); maybeMove(genesis, "author", chainParamsJson, "coinbase"); From eabbea604d02683560a51a671f9e89299e68f861 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Tue, 26 Jul 2022 10:47:56 -0700 Subject: [PATCH 043/109] limit engine-api info logging (#4156) * limit engine-api info logging * use a common constant for engine api logging threshold Signed-off-by: garyschulte --- .../methods/ExecutionEngineJsonRpcMethod.java | 1 + .../engine/EngineForkchoiceUpdated.java | 20 +++++++---- .../methods/engine/EngineNewPayload.java | 33 +++++++++++-------- 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecutionEngineJsonRpcMethod.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecutionEngineJsonRpcMethod.java index 58a845283b1..0e031cae3c7 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecutionEngineJsonRpcMethod.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecutionEngineJsonRpcMethod.java @@ -37,6 +37,7 @@ public enum EngineStatus { INVALID_BLOCK_HASH; } + public static final long ENGINE_API_LOGGING_THRESHOLD = 60000L; private final Vertx syncVertx; private static final Logger LOG = LoggerFactory.getLogger(ExecutionEngineJsonRpcMethod.class); protected final MergeContext mergeContext; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdated.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdated.java index d1773fa759e..bd8c7f70a15 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdated.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdated.java @@ -257,18 +257,26 @@ private boolean isValidForkchoiceState( private JsonRpcResponse syncingResponse( final Object requestId, final EngineForkchoiceUpdatedParameter forkChoice) { + logForkchoiceUpdatedCall(SYNCING, forkChoice); return new JsonRpcSuccessResponse( requestId, new EngineUpdateForkchoiceResult(SYNCING, null, null, Optional.empty())); } + // fcU calls are synchronous, no need to make volatile + private long lastFcuInfoLog = System.currentTimeMillis(); + private void logForkchoiceUpdatedCall( final EngineStatus status, final EngineForkchoiceUpdatedParameter forkChoice) { - LOG.info( - "{} for fork-choice-update: head: {}, finalized: {}, safeBlockHash: {}", - status.name(), - forkChoice.getHeadBlockHash(), - forkChoice.getFinalizedBlockHash(), - forkChoice.getSafeBlockHash()); + // cheaply limit the noise of fcU during consensus client syncing to once a minute: + if (lastFcuInfoLog + ENGINE_API_LOGGING_THRESHOLD < System.currentTimeMillis()) { + lastFcuInfoLog = System.currentTimeMillis(); + LOG.info( + "{} for fork-choice-update: head: {}, finalized: {}, safeBlockHash: {}", + status.name(), + forkChoice.getHeadBlockHash(), + forkChoice.getFinalizedBlockHash(), + forkChoice.getSafeBlockHash()); + } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java index f71d049fc1a..4713239f453 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java @@ -19,8 +19,9 @@ import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.INVALID_BLOCK_HASH; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.SYNCING; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.VALID; -import static org.hyperledger.besu.util.Slf4jLambdaHelper.infoLambda; +import static org.hyperledger.besu.util.Slf4jLambdaHelper.debugLambda; import static org.hyperledger.besu.util.Slf4jLambdaHelper.traceLambda; +import static org.hyperledger.besu.util.Slf4jLambdaHelper.warnLambda; import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; import org.hyperledger.besu.datatypes.Hash; @@ -155,7 +156,6 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) protocolContext.getBlockchain().getBlockHeader(blockParam.getParentHash()); if (parentHeader.isPresent() && (blockParam.getTimestamp() <= parentHeader.get().getTimestamp())) { - LOG.info("method parameter timestamp not greater than parent"); return respondWithInvalid( reqId, blockParam, @@ -167,7 +167,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) new Block(newBlockHeader, new BlockBody(transactions, Collections.emptyList())); if (mergeContext.isSyncing() || parentHeader.isEmpty()) { - LOG.info( + LOG.debug( "isSyncing: {} parentHeaderMissing: {}, adding {} to backwardsync", mergeContext.isSyncing(), parentHeader.isEmpty(), @@ -185,7 +185,6 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) // TODO: post-merge cleanup if (!mergeCoordinator.latestValidAncestorDescendsFromTerminal(newBlockHeader)) { - LOG.warn("payload did not descend from terminal: {}", newBlockHeader.toLogString()); mergeCoordinator.addBadBlock(block); return respondWithInvalid( reqId, @@ -217,7 +216,7 @@ JsonRpcResponse respondWith( final EnginePayloadParameter param, final Hash latestValidHash, final EngineStatus status) { - infoLambda( + debugLambda( LOG, "New payload: number: {}, hash: {}, parentHash: {}, latestValidHash: {}, status: {}", () -> param.getBlockNumber(), @@ -229,20 +228,26 @@ JsonRpcResponse respondWith( requestId, new EnginePayloadStatusResult(status, latestValidHash, Optional.empty())); } + // engine api calls are synchronous, no need for volatile + private long lastInvalidWarn = System.currentTimeMillis(); + JsonRpcResponse respondWithInvalid( final Object requestId, final EnginePayloadParameter param, final Hash latestValidHash, final String validationError) { - infoLambda( - LOG, - "Invalid new payload: number: {}, hash: {}, parentHash: {}, latestValidHash: {}, status: {}, validationError: {}", - () -> param.getBlockNumber(), - () -> param.getBlockHash(), - () -> param.getParentHash(), - () -> latestValidHash == null ? null : latestValidHash.toHexString(), - INVALID::name, - () -> validationError); + if (lastInvalidWarn + ENGINE_API_LOGGING_THRESHOLD < System.currentTimeMillis()) { + lastInvalidWarn = System.currentTimeMillis(); + warnLambda( + LOG, + "Invalid new payload: number: {}, hash: {}, parentHash: {}, latestValidHash: {}, status: {}, validationError: {}", + () -> param.getBlockNumber(), + () -> param.getBlockHash(), + () -> param.getParentHash(), + () -> latestValidHash == null ? null : latestValidHash.toHexString(), + INVALID::name, + () -> validationError); + } return new JsonRpcSuccessResponse( requestId, new EnginePayloadStatusResult(INVALID, latestValidHash, Optional.of(validationError))); From ebfdab1585651d5a5734f0c44057a350eeca8f35 Mon Sep 17 00:00:00 2001 From: Roman Vaseev <4833306+Filter94@users.noreply.github.com> Date: Tue, 26 Jul 2022 21:18:09 +0300 Subject: [PATCH 044/109] Fixed desired gas limit setting in the reference tests service (#4170) Signed-off-by: Roman Vaseev <4833306+Filter94@users.noreply.github.com> Co-authored-by: Justin Florentine --- .../besu/ethereum/retesteth/methods/TestMineBlocks.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestMineBlocks.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestMineBlocks.java index 2598451d8a9..047d6225ef7 100644 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestMineBlocks.java +++ b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestMineBlocks.java @@ -64,7 +64,7 @@ private boolean mineNewBlock() { final PoWBlockCreator blockCreator = new PoWBlockCreator( context.getCoinbase(), - () -> Optional.of(10_000_000L), + () -> Optional.of(blockchain.getChainHeadHeader().getGasLimit()), header -> context.getExtraData(), context.getTransactionPool().getPendingTransactions(), protocolContext, From 1400646ebf30d209fd2da86072557c1fd0715300 Mon Sep 17 00:00:00 2001 From: Justin Florentine Date: Tue, 26 Jul 2022 23:12:56 -0400 Subject: [PATCH 045/109] 4169 dont recurse (#4171) * reimplemented with simple loop instead of recursing Signed-off-by: Justin Florentine --- .../merge/blockcreation/MergeCoordinator.java | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java index 98b3728ea75..9254ccf5c61 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java @@ -530,17 +530,26 @@ public boolean isDescendantOf(final BlockHeader ancestorBlock, final BlockHeader newBlock.getNumber(), newBlock.getBlockHash()); - if (ancestorBlock.getBlockHash().equals(newBlock.getHash())) { + // start with self, because descending from yourself is valid + Optional parentOf = Optional.of(newBlock); + + while (parentOf.isPresent() + && !parentOf.get().getBlockHash().equals(ancestorBlock.getBlockHash()) + && parentOf.get().getNumber() + >= ancestorBlock.getNumber()) { // if on a fork, don't go further back than ancestor + parentOf = protocolContext.getBlockchain().getBlockHeader(parentOf.get().getParentHash()); + } + + if (parentOf.isPresent() + && ancestorBlock.getBlockHash().equals(parentOf.get().getBlockHash())) { return true; - } else if (ancestorBlock.getNumber() < newBlock.getNumber()) { - return protocolContext - .getBlockchain() - .getBlockHeader(newBlock.getParentHash()) - .map(parent -> isDescendantOf(ancestorBlock, parent)) - .orElse(Boolean.FALSE); + } else { + LOG.debug( + "looped all the way back, did not find ancestor {} of child {}", + ancestorBlock.getBlockHash(), + newBlock.getBlockHash()); + return false; } - // neither matching nor is the ancestor block height lower than newBlock - return false; } private boolean isPayloadAttributesValid( From f838572ec86faf4bf24479086187ab6abc79e5da Mon Sep 17 00:00:00 2001 From: Antoine Toulme Date: Wed, 27 Jul 2022 05:38:29 +0200 Subject: [PATCH 046/109] separate dco from spotless, make dco only run for pull requests. Run on workflow dispatch on demand (#4165) Signed-off-by: Antoine Toulme Co-authored-by: Sally MacFarlane --- .github/workflows/checks.yml | 16 ++-------------- .github/workflows/dco.yml | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/dco.yml diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 8fc4b98f560..a1fa3e3916f 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -3,6 +3,7 @@ on: push: branches: [ main ] pull_request: + workflow_dispatch: jobs: spotless: @@ -18,17 +19,4 @@ jobs: java-version: 11 cache: gradle - name: spotless - run: ./gradlew --no-daemon --parallel clean spotlessCheck - dco: - runs-on: ubuntu-latest - if: ${{ github.actor != 'dependabot[bot]' }} - steps: - - name: Get PR Commits - id: 'get-pr-commits' - uses: tim-actions/get-pr-commits@v1.2.0 - with: - token: ${{ secrets.GITHUB_TOKEN }} - - name: DCO Check - uses: tim-actions/dco@v1.1.0 - with: - commits: ${{ steps.get-pr-commits.outputs.commits }} \ No newline at end of file + run: ./gradlew --no-daemon --parallel clean spotlessCheck \ No newline at end of file diff --git a/.github/workflows/dco.yml b/.github/workflows/dco.yml new file mode 100644 index 00000000000..c50fa6219aa --- /dev/null +++ b/.github/workflows/dco.yml @@ -0,0 +1,19 @@ +name: dco +on: + pull_request: + workflow_dispatch: + +jobs: + dco: + runs-on: ubuntu-latest + if: ${{ github.actor != 'dependabot[bot]' }} + steps: + - name: Get PR Commits + id: 'get-pr-commits' + uses: tim-actions/get-pr-commits@v1.2.0 + with: + token: ${{ secrets.GITHUB_TOKEN }} + - name: DCO Check + uses: tim-actions/dco@v1.1.0 + with: + commits: ${{ steps.get-pr-commits.outputs.commits }} \ No newline at end of file From f05b45d4d2dc84b153c1dad0d6306f7291e6acb8 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Wed, 27 Jul 2022 14:09:52 +1000 Subject: [PATCH 047/109] Add mechanism to retrieve missing blocks (#4175) * Add mechanism to retrieve missing blocks that caused BlockPropagationManager to get stuck on pending blocks * Remove threshold and request the lowest block parent everytime a block is saved for future Signed-off-by: Gabriel Trintinalia Co-authored-by: Gabriel Trintinalia Co-authored-by: garyschulte Co-authored-by: Sally MacFarlane --- .../eth/sync/BlockPropagationManager.java | 24 +++++++++++- .../AbstractBlockPropagationManagerTest.java | 39 +++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java index d017009ee36..f53da690de5 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java @@ -66,7 +66,6 @@ public class BlockPropagationManager { private static final Logger LOG = LoggerFactory.getLogger(BlockPropagationManager.class); - private final SynchronizerConfiguration config; private final ProtocolSchedule protocolSchedule; private final ProtocolContext protocolContext; @@ -364,6 +363,25 @@ private CompletableFuture processAnnouncedBlock( return getBlockFromPeers(Optional.of(peer), blockHash.number(), Optional.of(blockHash.hash())); } + private void requestParentBlock(final BlockHeader blockHeader) { + if (requestedBlocks.add(blockHeader.getParentHash())) { + retrieveParentBlock(blockHeader); + } else { + LOG.trace("Parent block with hash {} was already requested", blockHeader.getParentHash()); + } + } + + private CompletableFuture retrieveParentBlock(final BlockHeader blockHeader) { + final long targetParentBlockNumber = blockHeader.getNumber() - 1L; + final Hash targetParentBlockHash = blockHeader.getParentHash(); + LOG.info( + "Retrieving parent {} of block #{} from peers", + targetParentBlockHash, + blockHeader.getNumber()); + return getBlockFromPeers( + Optional.empty(), targetParentBlockNumber, Optional.of(targetParentBlockHash)); + } + private CompletableFuture getBlockFromPeers( final Optional preferredPeer, final long blockNumber, @@ -421,6 +439,10 @@ CompletableFuture importOrSavePendingBlock(final Block block, final Bytes if (pendingBlocksManager.registerPendingBlock(block, nodeId)) { LOG.info("Saving announced block {} for future import", block.toLogString()); } + + // Request parent of the lowest announced block + pendingBlocksManager.lowestAnnouncedBlock().ifPresent(this::requestParentBlock); + return CompletableFuture.completedFuture(block); } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java index 8651b8e1aa1..7723ef5679e 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java @@ -59,6 +59,7 @@ import org.hyperledger.besu.testutil.TestClock; import java.util.Collections; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.function.Supplier; @@ -634,6 +635,44 @@ public void shouldNotImportBlocksThatAreAlreadyBeingImported() { verify(ethScheduler, times(1)).scheduleSyncWorkerTask(any(Supplier.class)); } + @Test + public void shouldRequestLowestAnnouncedPendingBlockParent() { + // test if block propagation manager can recover if one block is missed + + blockchainUtil.importFirstBlocks(2); + final List blocks = blockchainUtil.getBlocks().subList(2, 4); + + blockPropagationManager.start(); + + // Create peer and responder + final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 0); + final Responder responder = RespondingEthPeer.blockchainResponder(getFullBlockchain()); + + // skip first block then create messages from blocklist + blocks.stream() + .skip(1) + .map(this::createNewBlockHashMessage) + .forEach( + message -> { // Broadcast new block hash message + EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, peer, message); + }); + + peer.respondWhile(responder, peer::hasOutstandingRequests); + + // assert all blocks were imported + blocks.forEach( + block -> { + assertThat(blockchain.contains(block.getHash())).isTrue(); + }); + } + + private NewBlockHashesMessage createNewBlockHashMessage(final Block block) { + return NewBlockHashesMessage.create( + Collections.singletonList( + new NewBlockHashesMessage.NewBlockHash( + block.getHash(), block.getHeader().getNumber()))); + } + @Test public void verifyBroadcastBlockInvocation() { blockchainUtil.importFirstBlocks(2); From 604855e486a386d604e7baa434238b01fb16fcf6 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Wed, 27 Jul 2022 10:49:09 -0700 Subject: [PATCH 048/109] 22.7.0-RC3 release (#4180) Signed-off-by: garyschulte --- CHANGELOG.md | 8 ++++++++ gradle.properties | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24de4623e56..8653c140369 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,19 @@ # Changelog ## 22.7.0 +Known/Outstanding issues: +Besu requires a restart post-merge to re-enable remote transaction processing [#3890](https://github.com/hyperledger/besu/issues/3890) + ### Additions and Improvements - Engine API: Change expiration time for JWT tokens to 60s [#4168](https://github.com/hyperledger/besu/pull/4168) +- Sepolia mergeNetSplit block [#4158](https://github.com/hyperledger/besu/pull/4158) +- Goerli TTD [#4160](https://github.com/hyperledger/besu/pull/4160) +- Several logging improvements ### Bug Fixes +- fix for stack overflow when searching for TTD block [#4169](https://github.com/hyperledger/besu/pull/4169) +- fix for chain stuck issue [#4175](https://github.com/hyperledger/besu/pull/4175) ## 22.7.0-RC2 diff --git a/gradle.properties b/gradle.properties index 77ba4f70c9e..0972ec996f4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=22.7.0-SNAPSHOT +version=22.7.0-RC3 # Workaround for Java 16 and spotless bug 834 https://github.com/diffplug/spotless/issues/834 org.gradle.jvmargs=--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ From d2418bf000c977ab469a56745a2b0d5905779ab4 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Wed, 27 Jul 2022 12:02:24 -0700 Subject: [PATCH 049/109] Prepare for version 22.7.1-SNAPSHOT (#4181) Signed-off-by: garyschulte --- CHANGELOG.md | 15 +++++++++++++-- gradle.properties | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8653c140369..4a2cafc1df2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ # Changelog ## 22.7.0 + +### Additions and Improvements + +### Bug Fixes + + +## 22.7.0-RC3 Known/Outstanding issues: Besu requires a restart post-merge to re-enable remote transaction processing [#3890](https://github.com/hyperledger/besu/issues/3890) @@ -15,6 +22,10 @@ Besu requires a restart post-merge to re-enable remote transaction processing [# - fix for stack overflow when searching for TTD block [#4169](https://github.com/hyperledger/besu/pull/4169) - fix for chain stuck issue [#4175](https://github.com/hyperledger/besu/pull/4175) +### Download links +- https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/22.7.0-RC3/besu-22.7.0-RC3.tar.gz / sha256: `6a1ee89c82db9fa782d34733d8a8c726670378bcb71befe013da48d7928490a6` +- https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/22.7.0-RC3/besu-22.7.0-RC3.zip / sha256: `5de22445ab2a270cf33e1850cd28f1946442b7104738f0d1ac253a009c53414e` + ## 22.7.0-RC2 ### Additions and Improvements @@ -43,8 +54,8 @@ Besu requires a restart post-merge to re-enable remote transaction processing [# - Avoid starting or stopping the BlockPropagationManager more than once [#4122](https://github.com/hyperledger/besu/pull/4122) ### Download links -- https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/22.7.0-RC2/besu-22.7.0-RC2.tar.gz / sha256: `//FIXME` -- https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/22.7.0-RC2/besu-22.7.0-RC2.zip / sha256: `//FIXME` +- https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/22.7.0-RC2/besu-22.7.0-RC2.tar.gz / sha256: `befe15b893820c9c6451a74fd87b41f555ff28561494b3bebadd5da5c7ce25d3` +- https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/22.7.0-RC2/besu-22.7.0-RC2.zip / sha256: `d56c340f5982b882fbecca2697ca72a5bbefe0e978d2d4504211f012e2242a81` ## 22.7.0-RC1 diff --git a/gradle.properties b/gradle.properties index 0972ec996f4..77ba4f70c9e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=22.7.0-RC3 +version=22.7.0-SNAPSHOT # Workaround for Java 16 and spotless bug 834 https://github.com/diffplug/spotless/issues/834 org.gradle.jvmargs=--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ From b02653a0539bf91b7d1456b4ed0178fb4ca43367 Mon Sep 17 00:00:00 2001 From: Matt Nelson <85905982+matt-nelson-csi@users.noreply.github.com> Date: Wed, 27 Jul 2022 18:23:09 -0400 Subject: [PATCH 050/109] Switching info to trace on several noisey logs during sync. (#4185) Signed-off-by: matt-nelson-csi --- .../besu/ethereum/eth/sync/fastsync/FastSyncActions.java | 2 +- .../eth/sync/fastsync/PivotSelectorFromFinalizedBlock.java | 2 +- .../ethereum/eth/sync/fastsync/TransitionPivotSelector.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActions.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActions.java index bda9c4a74ac..2f1f7cc2b6f 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActions.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActions.java @@ -262,7 +262,7 @@ private CompletableFuture downloadPivotBlockHeader(final Hash has .getHeader() .thenApply( blockHeader -> { - LOG.info( + LOG.trace( "Successfully downloaded pivot block header by hash: {}", blockHeader.toLogString()); return new FastSyncState(blockHeader); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotSelectorFromFinalizedBlock.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotSelectorFromFinalizedBlock.java index e6503cfcfb0..8524592b401 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotSelectorFromFinalizedBlock.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotSelectorFromFinalizedBlock.java @@ -53,7 +53,7 @@ public Optional selectNewPivotBlock(final EthPeer peer) { } private FastSyncState selectLastFinalizedBlockAsPivot(final Hash finalizedHash) { - LOG.info("Returning finalized block hash as pivot: {}", finalizedHash); + LOG.trace("Returning finalized block hash as pivot: {}", finalizedHash); return new FastSyncState(finalizedHash); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/TransitionPivotSelector.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/TransitionPivotSelector.java index 509b7472d30..eff75b6eadd 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/TransitionPivotSelector.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/TransitionPivotSelector.java @@ -63,7 +63,7 @@ private Optional routeDependingOnTotalTerminalDifficulty(final Et Difficulty bestPeerEstDifficulty = peer.chainState().getEstimatedTotalDifficulty(); if (finalizedBlockHashSupplier.get().isPresent()) { - LOG.info("A finalized block is present, use it as pivot"); + LOG.trace("A finalized block is present, use it as pivot"); return pivotSelectorFromFinalizedBlock.selectNewPivotBlock(peer); } From 93da04cf0050fbdeae22e27d4976807b8475d727 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Thu, 28 Jul 2022 13:50:53 +0200 Subject: [PATCH 051/109] Allow to set any value for baseFeePerGas in the genesis file (#4177) Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 6 ++++-- .../ethereum/mainnet/feemarket/LondonFeeMarket.java | 12 ++---------- .../mainnet/feemarket/LondonFeeMarketTest.java | 7 ------- 3 files changed, 6 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a2cafc1df2..e988a70fe74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,13 +19,15 @@ Besu requires a restart post-merge to re-enable remote transaction processing [# - Several logging improvements ### Bug Fixes -- fix for stack overflow when searching for TTD block [#4169](https://github.com/hyperledger/besu/pull/4169) -- fix for chain stuck issue [#4175](https://github.com/hyperledger/besu/pull/4175) +- Allow to set any value for baseFeePerGas in the genesis file [#4177](https://github.com/hyperledger/besu/pull/4177) +- Fix for stack overflow when searching for TTD block [#4169](https://github.com/hyperledger/besu/pull/4169) +- Fix for chain stuck issue [#4175](https://github.com/hyperledger/besu/pull/4175) ### Download links - https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/22.7.0-RC3/besu-22.7.0-RC3.tar.gz / sha256: `6a1ee89c82db9fa782d34733d8a8c726670378bcb71befe013da48d7928490a6` - https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/22.7.0-RC3/besu-22.7.0-RC3.zip / sha256: `5de22445ab2a270cf33e1850cd28f1946442b7104738f0d1ac253a009c53414e` + ## 22.7.0-RC2 ### Additions and Improvements diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java index 5f2164a2a69..b1789a0bae6 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java @@ -32,14 +32,13 @@ public class LondonFeeMarket implements BaseFeeMarket { GenesisConfigFile.BASEFEE_AT_GENESIS_DEFAULT_VALUE; static final long DEFAULT_BASEFEE_MAX_CHANGE_DENOMINATOR = 8L; static final long DEFAULT_SLACK_COEFFICIENT = 2L; - // required for integer arithmetic to work when baseFee > 0 private static final Wei DEFAULT_BASEFEE_FLOOR = Wei.of(7L); private static final Logger LOG = LoggerFactory.getLogger(LondonFeeMarket.class); private final Wei baseFeeInitialValue; private final long londonForkBlockNumber; private final TransactionPriceCalculator txPriceCalculator; - private Wei baseFeeFloor = DEFAULT_BASEFEE_FLOOR; + private final Wei baseFeeFloor; public LondonFeeMarket(final long londonForkBlockNumber) { this(londonForkBlockNumber, Optional.empty()); @@ -50,14 +49,7 @@ public LondonFeeMarket( this.txPriceCalculator = TransactionPriceCalculator.eip1559(); this.londonForkBlockNumber = londonForkBlockNumber; this.baseFeeInitialValue = baseFeePerGasOverride.orElse(DEFAULT_BASEFEE_INITIAL_VALUE); - if (baseFeeInitialValue.isZero()) { - baseFeeFloor = Wei.ZERO; - } else if (baseFeeInitialValue.lessThan(DEFAULT_BASEFEE_FLOOR)) { - throw new IllegalStateException( - String.format( - "baseFee must be either 0 or > %s wei to avoid integer arithmetic issues", - DEFAULT_BASEFEE_FLOOR)); - } + this.baseFeeFloor = baseFeeInitialValue.isZero() ? Wei.ZERO : DEFAULT_BASEFEE_FLOOR; } @Override diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarketTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarketTest.java index 0411116e2c5..cf7e89619c7 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarketTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarketTest.java @@ -15,7 +15,6 @@ package org.hyperledger.besu.ethereum.mainnet.feemarket; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; @@ -72,10 +71,4 @@ public void satisfiesFloorTxCostWhenBaseFeeInitialValueIsZero() { final LondonFeeMarket londonFeeMarket = new LondonFeeMarket(0, Optional.of(Wei.ZERO)); assertThat(londonFeeMarket.satisfiesFloorTxCost(transaction)).isTrue(); } - - @Test - public void throwsWhenBaseFeeOverrideIsNonZeroAndBelowFloor() { - assertThatThrownBy(() -> new LondonFeeMarket(0, Optional.of(Wei.of(6)))) - .isInstanceOf(IllegalStateException.class); - } } From 3913174f008be4fe6d9b5bd0e6b9d4e08a96affc Mon Sep 17 00:00:00 2001 From: Daniel Lehrner Date: Thu, 28 Jul 2022 23:41:08 +0200 Subject: [PATCH 052/109] Print warning for deprecated testnets (#4173) * print warning for deprecated testnets Signed-off-by: Daniel Lehrner --- CHANGELOG.md | 1 + besu/build.gradle | 1 + .../org/hyperledger/besu/cli/BesuCommand.java | 3 + .../besu/cli/NetworkDeprecationMessage.java | 63 +++++++++++++++++++ .../besu/cli/config/NetworkName.java | 35 ++++++++++- .../hyperledger/besu/cli/BesuCommandTest.java | 54 +++++++++++++++- .../cli/NetworkDeprecationMessageTest.java | 54 ++++++++++++++++ gradle/versions.gradle | 1 + 8 files changed, 206 insertions(+), 6 deletions(-) create mode 100644 besu/src/main/java/org/hyperledger/besu/cli/NetworkDeprecationMessage.java create mode 100644 besu/src/test/java/org/hyperledger/besu/cli/NetworkDeprecationMessageTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index e988a70fe74..8c82a904be7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 22.7.0 ### Additions and Improvements +- Deprecation warning for Ropsten, Rinkeby, Kiln [#4173](https://github.com/hyperledger/besu/pull/4173) ### Bug Fixes diff --git a/besu/build.gradle b/besu/build.gradle index 6252d0bbe29..ffb34ad77d3 100644 --- a/besu/build.gradle +++ b/besu/build.gradle @@ -67,6 +67,7 @@ dependencies { implementation 'info.picocli:picocli' implementation 'io.vertx:vertx-core' implementation 'io.vertx:vertx-web' + implementation 'org.apache.commons:commons-lang3' implementation 'org.apache.logging.log4j:log4j-core' implementation 'org.apache.tuweni:tuweni-bytes' implementation 'org.apache.tuweni:tuweni-config' diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index ce53d8cdb43..0d9097a0f11 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -1393,6 +1393,9 @@ public void parse( @Override public void run() { + if (network != null && network.isDeprecated()) { + logger.warn(NetworkDeprecationMessage.generate(network)); + } try { configureLogging(true); diff --git a/besu/src/main/java/org/hyperledger/besu/cli/NetworkDeprecationMessage.java b/besu/src/main/java/org/hyperledger/besu/cli/NetworkDeprecationMessage.java new file mode 100644 index 00000000000..d8e59329520 --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/cli/NetworkDeprecationMessage.java @@ -0,0 +1,63 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.cli; + +import org.hyperledger.besu.cli.config.NetworkName; + +import org.apache.commons.lang3.StringUtils; + +public class NetworkDeprecationMessage { + private static final int MAX_LINE_LENGTH = 80; + + public static String generate(final NetworkName network) { + if (network.getDeprecationDate().isEmpty()) { + throw new AssertionError("Deprecation date is not set. Cannot print a deprecation message"); + } + + final StringBuilder messageBuilder = new StringBuilder("\n"); + messageBuilder + .append("#".repeat(MAX_LINE_LENGTH)) + .append(emptyLine()) + .append( + String.format( + "#%s#", + StringUtils.center( + deprecationDetails( + network.humanReadableNetworkName(), network.getDeprecationDate().get()), + MAX_LINE_LENGTH - 2))) + .append(emptyLine()) + .append( + String.format( + "#%s#\n", StringUtils.center("For more details please go to", MAX_LINE_LENGTH - 2))) + .append( + String.format( + "#%s#", + StringUtils.center( + "https://blog.ethereum.org/2022/06/21/testnet-deprecation/", + MAX_LINE_LENGTH - 2))) + .append(emptyLine()) + .append("#".repeat(MAX_LINE_LENGTH)); + + return messageBuilder.toString(); + } + + private static String deprecationDetails(final String networkName, final String deprecationDate) { + return networkName + " is deprecated and will be shutdown " + deprecationDate; + } + + private static String emptyLine() { + return String.format("\n#%s#\n", StringUtils.center("", MAX_LINE_LENGTH - 2)); + } +} diff --git a/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java b/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java index 7aa15d5d3a0..0592fcffc51 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java @@ -15,6 +15,9 @@ package org.hyperledger.besu.cli.config; import java.math.BigInteger; +import java.util.Optional; + +import org.apache.commons.lang3.StringUtils; public enum NetworkName { MAINNET("/mainnet.json", BigInteger.valueOf(1)), @@ -33,17 +36,31 @@ public enum NetworkName { private final String genesisFile; private final BigInteger networkId; private final boolean canFastSync; + private final String deprecationDate; NetworkName(final String genesisFile, final BigInteger networkId) { - this.genesisFile = genesisFile; - this.networkId = networkId; - this.canFastSync = true; + this(genesisFile, networkId, true); } NetworkName(final String genesisFile, final BigInteger networkId, final boolean canFastSync) { this.genesisFile = genesisFile; this.networkId = networkId; this.canFastSync = canFastSync; + + // https://blog.ethereum.org/2022/06/21/testnet-deprecation/ + switch (networkId.intValue()) { + case 3: + deprecationDate = "in Q4 2022"; + break; + case 4: + deprecationDate = "in Q2/Q3 2023"; + break; + case 1337802: + deprecationDate = "after the Mainnet Merge"; + break; + default: + deprecationDate = null; + } } public String getGenesisFile() { @@ -57,4 +74,16 @@ public BigInteger getNetworkId() { public boolean canFastSync() { return canFastSync; } + + public String humanReadableNetworkName() { + return StringUtils.capitalize(name().toLowerCase()); + } + + public boolean isDeprecated() { + return deprecationDate != null; + } + + public Optional getDeprecationDate() { + return Optional.ofNullable(deprecationDate); + } } diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index eedb1c3a562..7608c2e6be9 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -21,11 +21,13 @@ import static org.hyperledger.besu.cli.config.NetworkName.CLASSIC; import static org.hyperledger.besu.cli.config.NetworkName.DEV; import static org.hyperledger.besu.cli.config.NetworkName.GOERLI; +import static org.hyperledger.besu.cli.config.NetworkName.KILN; import static org.hyperledger.besu.cli.config.NetworkName.KOTTI; import static org.hyperledger.besu.cli.config.NetworkName.MAINNET; import static org.hyperledger.besu.cli.config.NetworkName.MORDOR; import static org.hyperledger.besu.cli.config.NetworkName.RINKEBY; import static org.hyperledger.besu.cli.config.NetworkName.ROPSTEN; +import static org.hyperledger.besu.cli.config.NetworkName.SEPOLIA; import static org.hyperledger.besu.cli.util.CommandLineUtils.DEPENDENCY_WARNING_MSG; import static org.hyperledger.besu.cli.util.CommandLineUtils.DEPRECATED_AND_USELESS_WARNING_MSG; import static org.hyperledger.besu.cli.util.CommandLineUtils.DEPRECATION_WARNING_MSG; @@ -44,11 +46,13 @@ import static org.hyperledger.besu.nat.kubernetes.KubernetesNatManager.DEFAULT_BESU_SERVICE_NAME_FILTER; import static org.junit.Assume.assumeThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.contains; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNotNull; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atMost; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; @@ -996,6 +1000,8 @@ public void testGenesisPathMainnetEthConfig() throws Exception { assertThat(config.getBootNodes()).isEqualTo(MAINNET_BOOTSTRAP_NODES); assertThat(config.getDnsDiscoveryUrl()).isEqualTo(MAINNET_DISCOVERY_URL); assertThat(config.getNetworkId()).isEqualTo(BigInteger.valueOf(1)); + + verify(mockLogger, never()).warn(contains("Mainnet is deprecated and will be shutdown")); } @Test @@ -3829,7 +3835,7 @@ public void devModeOptionMustBeUsed() throws Exception { } @Test - public void rinkebyValuesAreUsed() throws Exception { + public void rinkebyValuesAreUsed() { parseCommand("--network", "rinkeby"); final ArgumentCaptor networkArg = @@ -3842,10 +3848,12 @@ public void rinkebyValuesAreUsed() throws Exception { assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + + verify(mockLogger, times(1)).warn(contains("Rinkeby is deprecated and will be shutdown")); } @Test - public void ropstenValuesAreUsed() throws Exception { + public void ropstenValuesAreUsed() { parseCommand("--network", "ropsten"); final ArgumentCaptor networkArg = @@ -3858,10 +3866,30 @@ public void ropstenValuesAreUsed() throws Exception { assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + + verify(mockLogger, times(1)).warn(contains("Ropsten is deprecated and will be shutdown")); + } + + @Test + public void kilnValuesAreUsed() { + parseCommand("--network", "kiln"); + + final ArgumentCaptor networkArg = + ArgumentCaptor.forClass(EthNetworkConfig.class); + + verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any()); + verify(mockControllerBuilder).build(); + + assertThat(networkArg.getValue()).isEqualTo(EthNetworkConfig.getNetworkConfig(KILN)); + + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + + verify(mockLogger, times(1)).warn(contains("Kiln is deprecated and will be shutdown")); } @Test - public void goerliValuesAreUsed() throws Exception { + public void goerliValuesAreUsed() { parseCommand("--network", "goerli"); final ArgumentCaptor networkArg = @@ -3874,6 +3902,26 @@ public void goerliValuesAreUsed() throws Exception { assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + + verify(mockLogger, never()).warn(contains("Goerli is deprecated and will be shutdown")); + } + + @Test + public void sepoliaValuesAreUsed() { + parseCommand("--network", "sepolia"); + + final ArgumentCaptor networkArg = + ArgumentCaptor.forClass(EthNetworkConfig.class); + + verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any()); + verify(mockControllerBuilder).build(); + + assertThat(networkArg.getValue()).isEqualTo(EthNetworkConfig.getNetworkConfig(SEPOLIA)); + + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + + verify(mockLogger, never()).warn(contains("Sepolia is deprecated and will be shutdown")); } @Test diff --git a/besu/src/test/java/org/hyperledger/besu/cli/NetworkDeprecationMessageTest.java b/besu/src/test/java/org/hyperledger/besu/cli/NetworkDeprecationMessageTest.java new file mode 100644 index 00000000000..f3dbc3b8041 --- /dev/null +++ b/besu/src/test/java/org/hyperledger/besu/cli/NetworkDeprecationMessageTest.java @@ -0,0 +1,54 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.cli; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.hyperledger.besu.cli.config.NetworkName; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +class NetworkDeprecationMessageTest { + + @ParameterizedTest + @EnumSource( + value = NetworkName.class, + names = {"RINKEBY", "ROPSTEN", "KILN"}) + void shouldGenerateDeprecationMessageForDeprecatedNetworks(final NetworkName network) { + assertThat(NetworkDeprecationMessage.generate(network)) + .contains(network.humanReadableNetworkName() + " is deprecated and will be shutdown"); + } + + @ParameterizedTest + @EnumSource( + value = NetworkName.class, + names = { + "MAINNET", + "SEPOLIA", + "GOERLI", + "DEV", + "CLASSIC", + "KOTTI", + "MORDOR", + "ECIP1049_DEV", + "ASTOR" + }) + void shouldThrowErrorForNonDeprecatedNetworks(final NetworkName network) { + assertThatThrownBy(() -> NetworkDeprecationMessage.generate(network)) + .isInstanceOf(AssertionError.class); + } +} diff --git a/gradle/versions.gradle b/gradle/versions.gradle index 0ce45ae4032..cd89dfb1c26 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -116,6 +116,7 @@ dependencyManagement { dependency 'net.java.dev.jna:jna:5.11.0' dependency 'org.apache.commons:commons-compress:1.21' + dependency 'org.apache.commons:commons-lang3:3.12.0' dependency 'org.apache.commons:commons-text:1.9' dependency 'org.apache.logging.log4j:log4j-api:2.17.2' From 962c805cae2258729e4443386ce625ab391cc45f Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Thu, 28 Jul 2022 16:53:55 -0600 Subject: [PATCH 053/109] Accept empty header set in range headers validation (#4189) If a response to the get header P2P request only returns the header that is the start of the range we may need to trim it to an empty response, this is breaking the validation response. One client has started returning only the range header start in some circumstances (which is a valid response per spec). Because we sometimes request an overlapping header this results in an empty stream once we cut the duplicates. fixes #3336 Signed-off-by: Danno Ferrin --- CHANGELOG.md | 7 ++- .../ethereum/eth/sync/range/RangeHeaders.java | 14 ++--- .../range/RangeHeadersValidationStep.java | 51 ++++++++++--------- .../sync/RangeHeadersValidationStepTest.java | 18 +++++++ 4 files changed, 52 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c82a904be7..c8a285d99a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,12 +6,12 @@ - Deprecation warning for Ropsten, Rinkeby, Kiln [#4173](https://github.com/hyperledger/besu/pull/4173) ### Bug Fixes - +- Stop producing stack traces when a get headers response only contains the range start header [#4189](https://github.com/hyperledger/besu/pull/4189) ## 22.7.0-RC3 -Known/Outstanding issues: -Besu requires a restart post-merge to re-enable remote transaction processing [#3890](https://github.com/hyperledger/besu/issues/3890) +### Known/Outstanding issues: +- Besu requires a restart post-merge to re-enable remote transaction processing [#3890](https://github.com/hyperledger/besu/issues/3890) ### Additions and Improvements - Engine API: Change expiration time for JWT tokens to 60s [#4168](https://github.com/hyperledger/besu/pull/4168) @@ -28,7 +28,6 @@ Besu requires a restart post-merge to re-enable remote transaction processing [# - https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/22.7.0-RC3/besu-22.7.0-RC3.tar.gz / sha256: `6a1ee89c82db9fa782d34733d8a8c726670378bcb71befe013da48d7928490a6` - https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/22.7.0-RC3/besu-22.7.0-RC3.zip / sha256: `5de22445ab2a270cf33e1850cd28f1946442b7104738f0d1ac253a009c53414e` - ## 22.7.0-RC2 ### Additions and Improvements diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/range/RangeHeaders.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/range/RangeHeaders.java index 250104cac59..bff5ceeffac 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/range/RangeHeaders.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/range/RangeHeaders.java @@ -14,29 +14,21 @@ */ package org.hyperledger.besu.ethereum.eth.sync.range; -import static com.google.common.base.Preconditions.checkArgument; - import org.hyperledger.besu.ethereum.core.BlockHeader; import java.util.List; import java.util.Objects; +import java.util.Optional; import com.google.common.base.MoreObjects; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class RangeHeaders { - private static final Logger LOG = LoggerFactory.getLogger(RangeHeaders.class); private final SyncTargetRange range; private final List headersToImport; public RangeHeaders( final SyncTargetRange checkpointRange, final List headersToImport) { - if (headersToImport.isEmpty()) { - LOG.debug(String.format("Headers list empty. Range: %s", checkpointRange.toString())); - } - checkArgument(!headersToImport.isEmpty(), "Must have at least one header to import"); this.range = checkpointRange; this.headersToImport = headersToImport; } @@ -49,8 +41,8 @@ public List getHeadersToImport() { return headersToImport; } - public BlockHeader getFirstHeaderToImport() { - return headersToImport.get(0); + public Optional getFirstHeaderToImport() { + return headersToImport.size() > 0 ? Optional.of(headersToImport.get(0)) : Optional.empty(); } @Override diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/range/RangeHeadersValidationStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/range/RangeHeadersValidationStep.java index 0ed34491737..79ed3c53108 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/range/RangeHeadersValidationStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/range/RangeHeadersValidationStep.java @@ -43,30 +43,35 @@ public RangeHeadersValidationStep( @Override public Stream apply(final RangeHeaders rangeHeaders) { final BlockHeader rangeStart = rangeHeaders.getRange().getStart(); - final BlockHeader firstHeaderToImport = rangeHeaders.getFirstHeaderToImport(); - if (isValid(rangeStart, firstHeaderToImport)) { - return rangeHeaders.getHeadersToImport().stream(); - } else { - final String rangeEndDescription; - if (rangeHeaders.getRange().hasEnd()) { - final BlockHeader rangeEnd = rangeHeaders.getRange().getEnd(); - rangeEndDescription = - String.format("#%d (%s)", rangeEnd.getNumber(), rangeEnd.getBlockHash()); - } else { - rangeEndDescription = "chain head"; - } - final String errorMessage = - String.format( - "Invalid range headers. Headers downloaded between #%d (%s) and %s do not connect at #%d (%s)", - rangeStart.getNumber(), - rangeStart.getHash(), - rangeEndDescription, - firstHeaderToImport.getNumber(), - firstHeaderToImport.getHash()); - throw new InvalidBlockException( - errorMessage, firstHeaderToImport.getNumber(), firstHeaderToImport.getHash()); - } + return rangeHeaders + .getFirstHeaderToImport() + .map( + firstHeader -> { + if (isValid(rangeStart, firstHeader)) { + return rangeHeaders.getHeadersToImport().stream(); + } else { + final String rangeEndDescription; + if (rangeHeaders.getRange().hasEnd()) { + final BlockHeader rangeEnd = rangeHeaders.getRange().getEnd(); + rangeEndDescription = + String.format("#%d (%s)", rangeEnd.getNumber(), rangeEnd.getBlockHash()); + } else { + rangeEndDescription = "chain head"; + } + final String errorMessage = + String.format( + "Invalid range headers. Headers downloaded between #%d (%s) and %s do not connect at #%d (%s)", + rangeStart.getNumber(), + rangeStart.getHash(), + rangeEndDescription, + firstHeader.getNumber(), + firstHeader.getHash()); + throw new InvalidBlockException( + errorMessage, firstHeader.getNumber(), firstHeader.getHash()); + } + }) + .orElse(Stream.empty()); } private boolean isValid(final BlockHeader expectedParent, final BlockHeader firstHeaderToImport) { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/RangeHeadersValidationStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/RangeHeadersValidationStepTest.java index 89b5930c29f..478adbfdc62 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/RangeHeadersValidationStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/RangeHeadersValidationStepTest.java @@ -35,6 +35,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; +import java.util.List; import java.util.stream.Stream; import org.junit.Before; @@ -107,4 +108,21 @@ public void shouldThrowExceptionWhenValidationFails() { + firstHeader.getHash() + ")"); } + + @Test + public void acceptResponseWithNoHeaders() { + var emptyRangeHeaders = + new RangeHeaders(new SyncTargetRange(syncTarget, rangeStart, rangeEnd), List.of()); + + final Stream result = validationStep.apply(emptyRangeHeaders); + assertThat(result).isEmpty(); + + verifyNoMoreInteractions( + protocolSchedule, + protocolSpec, + protocolContext, + headerValidator, + validationPolicy, + syncTarget); + } } From 049d234c0e572dd0e5c512476f1e948691eb4af7 Mon Sep 17 00:00:00 2001 From: Antoine Toulme Date: Fri, 29 Jul 2022 03:56:29 +0200 Subject: [PATCH 054/109] upgrade spotless to 6.8.0 (#4195) Signed-off-by: Antoine Toulme --- CHANGELOG.md | 1 + build.gradle | 2 +- gradle.properties | 9 --------- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8a285d99a4..95a24aa645d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ### Bug Fixes - Stop producing stack traces when a get headers response only contains the range start header [#4189](https://github.com/hyperledger/besu/pull/4189) +- Upgrade Gradle to 6.8.0 [#4195](https://github.com/hyperledger/besu/pull/4195) ## 22.7.0-RC3 diff --git a/build.gradle b/build.gradle index 71425653c21..356a7290114 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ import net.ltgt.gradle.errorprone.CheckSeverity import java.text.SimpleDateFormat plugins { - id 'com.diffplug.spotless' version '6.7.2' + id 'com.diffplug.spotless' version '6.8.0' id 'com.github.ben-manes.versions' version '0.42.0' id 'com.github.hierynomus.license' version '0.16.1-fix' id 'com.jfrog.artifactory' version '4.28.3' diff --git a/gradle.properties b/gradle.properties index 77ba4f70c9e..af182eba6f6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,11 +1,2 @@ version=22.7.0-SNAPSHOT -# Workaround for Java 16 and spotless bug 834 https://github.com/diffplug/spotless/issues/834 -org.gradle.jvmargs=--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ ---add-exports jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \ ---add-exports jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \ ---add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \ ---add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED \ ---add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \ ---add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \ ---add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED From 0d7eaf16d4e77383ff00ee71296d73656065a252 Mon Sep 17 00:00:00 2001 From: Antoine Toulme Date: Fri, 29 Jul 2022 06:38:18 +0200 Subject: [PATCH 055/109] Upgrade gradle to 7.5, silence the welcome message (#4196) Signed-off-by: Antoine Toulme --- CHANGELOG.md | 3 ++- gradle.properties | 1 + gradle/wrapper/gradle-wrapper.properties | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95a24aa645d..a3aa1a66423 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,8 @@ ### Bug Fixes - Stop producing stack traces when a get headers response only contains the range start header [#4189](https://github.com/hyperledger/besu/pull/4189) -- Upgrade Gradle to 6.8.0 [#4195](https://github.com/hyperledger/besu/pull/4195) +- Upgrade Spotless to 6.8.0 [#4195](https://github.com/hyperledger/besu/pull/4195) +- Upgrade Gradle to 7.5 [#4196](https://github.com/hyperledger/besu/pull/4196) ## 22.7.0-RC3 diff --git a/gradle.properties b/gradle.properties index af182eba6f6..db6c312064f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,3 @@ version=22.7.0-SNAPSHOT +org.gradle.welcome=never diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2e6e5897b52..8049c684f04 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 9b2fcde2b0a49f0bf9a09ce813979109f3fba7ac Mon Sep 17 00:00:00 2001 From: garyschulte Date: Fri, 29 Jul 2022 08:33:55 -0700 Subject: [PATCH 056/109] Panda print only when crossing TTD the first time (#4194) * add oldState to MergeStateHandler, move Pandas to Transition watcher Signed-off-by: garyschulte --- .../controller/BesuControllerBuilder.java | 2 - .../TransitionBesuControllerBuilder.java | 8 +++- .../besu/consensus/merge/PandaPrinter.java | 21 ++++++---- .../consensus/merge/PostMergeContext.java | 10 ++++- .../merge/TransitionBestPeerComparator.java | 4 +- .../consensus/merge/PandaPrinterTest.java | 39 ++++++++++++++++++- .../consensus/merge/PostMergeContextTest.java | 4 +- .../TransitionBestPeerComparatorTest.java | 2 +- .../consensus/merge/MergeStateHandler.java | 5 ++- .../ethereum/eth/manager/MergePeerFilter.java | 4 +- .../ethereum/eth/sync/state/SyncState.java | 2 - .../eth/manager/EthProtocolManagerTest.java | 2 +- 12 files changed, 81 insertions(+), 22 deletions(-) diff --git a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java index f791b269ee8..ae7490b6132 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java @@ -21,7 +21,6 @@ import org.hyperledger.besu.config.GenesisConfigOptions; import org.hyperledger.besu.consensus.merge.FinalizedBlockHashSupplier; import org.hyperledger.besu.consensus.merge.MergeContext; -import org.hyperledger.besu.consensus.merge.PandaPrinter; import org.hyperledger.besu.consensus.qbft.pki.PkiBlockCreationConfiguration; import org.hyperledger.besu.crypto.NodeKey; import org.hyperledger.besu.datatypes.Hash; @@ -379,7 +378,6 @@ public BesuController build() { final EthContext ethContext = new EthContext(ethPeers, ethMessages, snapMessages, scheduler); final boolean fastSyncEnabled = !SyncMode.isFullSync(syncConfig.getSyncMode()); final SyncState syncState = new SyncState(blockchain, ethPeers, fastSyncEnabled, checkpoint); - syncState.subscribeTTDReached(new PandaPrinter()); final TransactionPool transactionPool = TransactionPoolFactory.createTransactionPool( diff --git a/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java index 83f2d4e658d..3f83c2250c4 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.controller; import org.hyperledger.besu.config.GenesisConfigFile; +import org.hyperledger.besu.consensus.merge.PandaPrinter; import org.hyperledger.besu.consensus.merge.PostMergeContext; import org.hyperledger.besu.consensus.merge.TransitionBackwardSyncContext; import org.hyperledger.besu.consensus.merge.TransitionContext; @@ -180,7 +181,7 @@ private void initTransitionWatcher( PostMergeContext postMergeContext = protocolContext.getConsensusContext(PostMergeContext.class); postMergeContext.observeNewIsPostMergeState( - (isPoS, difficultyStoppedAt) -> { + (isPoS, priorState, difficultyStoppedAt) -> { if (isPoS) { // if we transitioned to post-merge, stop and disable any mining composedCoordinator.getPreMergeObject().disable(); @@ -190,6 +191,11 @@ private void initTransitionWatcher( .getBlockchain() .setBlockChoiceRule((newBlockHeader, currentBlockHeader) -> -1); + if (priorState.filter(prior -> !prior).isPresent()) { + // only print pandas if we had a prior merge state, and it was false + PandaPrinter.printOnFirstCrossing(); + } + } else if (composedCoordinator.isMiningBeforeMerge()) { // if our merge state is set to mine pre-merge and we are mining, start mining composedCoordinator.getPreMergeObject().enable(); diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PandaPrinter.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PandaPrinter.java index 1a028fd8dff..5ec89fabcf4 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PandaPrinter.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PandaPrinter.java @@ -16,8 +16,6 @@ package org.hyperledger.besu.consensus.merge; -import org.hyperledger.besu.plugin.services.BesuEvents.TTDReachedListener; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -28,11 +26,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class PandaPrinter implements TTDReachedListener { +public class PandaPrinter { private static final Logger LOG = LoggerFactory.getLogger(PandaPrinter.class); private static final String pandaBanner = PandaPrinter.loadBanner(); - private final AtomicBoolean beenDisplayed = new AtomicBoolean(); + private static final AtomicBoolean beenDisplayed = new AtomicBoolean(); private static String loadBanner() { Class c = PandaPrinter.class; @@ -50,10 +48,19 @@ private static String loadBanner() { return resultStringBuilder.toString(); } - @Override - public void onTTDReached(final boolean reached) { - if (reached && beenDisplayed.compareAndSet(false, true)) { + public static boolean printOnFirstCrossing() { + boolean shouldPrint = beenDisplayed.compareAndSet(false, true); + if (shouldPrint) { LOG.info("\n" + pandaBanner); } + return shouldPrint; + } + + static boolean hasDisplayed() { + return beenDisplayed.get(); + } + + static void resetForTesting() { + beenDisplayed.set(false); } } diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PostMergeContext.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PostMergeContext.java index c3013847852..6923419ff8f 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PostMergeContext.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PostMergeContext.java @@ -57,7 +57,12 @@ public class PostMergeContext implements MergeContext { @VisibleForTesting PostMergeContext() { - this.terminalTotalDifficulty = new AtomicReference<>(Difficulty.ZERO); + this(Difficulty.ZERO); + } + + @VisibleForTesting + PostMergeContext(final Difficulty difficulty) { + this.terminalTotalDifficulty = new AtomicReference<>(difficulty); this.syncState = new AtomicReference<>(); } @@ -100,7 +105,8 @@ public void setIsPostMerge(final Difficulty totalDifficulty) { if (oldState.isEmpty() || oldState.get() != newState) { newMergeStateCallbackSubscribers.forEach( newMergeStateCallback -> - newMergeStateCallback.mergeStateChanged(newState, Optional.of(totalDifficulty))); + newMergeStateCallback.mergeStateChanged( + newState, oldState, Optional.of(totalDifficulty))); } } diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionBestPeerComparator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionBestPeerComparator.java index b0df8d279b1..b944bcea4ab 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionBestPeerComparator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionBestPeerComparator.java @@ -56,7 +56,9 @@ public TransitionBestPeerComparator(final Difficulty configuredTerminalTotalDiff @Override public void mergeStateChanged( - final boolean isPoS, final Optional difficultyStoppedAt) { + final boolean isPoS, + final Optional oldState, + final Optional difficultyStoppedAt) { if (isPoS && difficultyStoppedAt.isPresent()) { terminalTotalDifficulty.set(difficultyStoppedAt.get()); } diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/PandaPrinterTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/PandaPrinterTest.java index 328f50de58b..1f5afbc075f 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/PandaPrinterTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/PandaPrinterTest.java @@ -16,13 +16,48 @@ package org.hyperledger.besu.consensus.merge; +import static org.assertj.core.api.Assertions.assertThat; + +import org.hyperledger.besu.ethereum.core.Difficulty; + import org.junit.Test; public class PandaPrinterTest { + final MergeStateHandler fauxTransitionHandler = + (isPoS, priorState, ttd) -> { + if (isPoS && priorState.filter(prior -> !prior).isPresent()) + PandaPrinter.printOnFirstCrossing(); + }; + @Test public void printsPanda() { - PandaPrinter panda = new PandaPrinter(); - panda.onTTDReached(true); + PandaPrinter.resetForTesting(); + assertThat(PandaPrinter.printOnFirstCrossing()).isTrue(); + assertThat(PandaPrinter.printOnFirstCrossing()).isFalse(); + } + + @Test + public void doesNotPrintAtInit() { + PandaPrinter.resetForTesting(); + var mergeContext = new PostMergeContext(Difficulty.ONE); + mergeContext.observeNewIsPostMergeState(fauxTransitionHandler); + + assertThat(PandaPrinter.hasDisplayed()).isFalse(); + mergeContext.setIsPostMerge(Difficulty.ONE); + assertThat(PandaPrinter.hasDisplayed()).isFalse(); + } + + @Test + public void printsWhenCrossingOnly() { + PandaPrinter.resetForTesting(); + var mergeContext = new PostMergeContext(Difficulty.ONE); + mergeContext.observeNewIsPostMergeState(fauxTransitionHandler); + + assertThat(PandaPrinter.hasDisplayed()).isFalse(); + mergeContext.setIsPostMerge(Difficulty.ZERO); + assertThat(PandaPrinter.hasDisplayed()).isFalse(); + mergeContext.setIsPostMerge(Difficulty.ONE); + assertThat(PandaPrinter.hasDisplayed()).isTrue(); } } diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/PostMergeContextTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/PostMergeContextTest.java index 6505d6f2e6e..5f022df5f0e 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/PostMergeContextTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/PostMergeContextTest.java @@ -173,7 +173,9 @@ private static class MergeStateChangeCollector implements MergeStateHandler { @Override public void mergeStateChanged( - final boolean isPoS, final Optional difficultyStoppedAt) { + final boolean isPoS, + final Optional oldState, + final Optional difficultyStoppedAt) { stateChanges.add(isPoS); } diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/TransitionBestPeerComparatorTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/TransitionBestPeerComparatorTest.java index 8c0d2cb9aa6..cce82e37809 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/TransitionBestPeerComparatorTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/TransitionBestPeerComparatorTest.java @@ -60,7 +60,7 @@ public void assertHandlesNewTTD() { assertThat(comparator.compare(a, b)).isEqualTo(-1); // update TTD with actual value - comparator.mergeStateChanged(true, Optional.of(Difficulty.of(5002))); + comparator.mergeStateChanged(true, Optional.empty(), Optional.of(Difficulty.of(5002))); assertThat(comparator.compare(a, b)).isEqualTo(1); } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/consensus/merge/MergeStateHandler.java b/ethereum/eth/src/main/java/org/hyperledger/besu/consensus/merge/MergeStateHandler.java index 4dd8210eadd..95325b46c32 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/consensus/merge/MergeStateHandler.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/consensus/merge/MergeStateHandler.java @@ -22,5 +22,8 @@ public interface MergeStateHandler { - void mergeStateChanged(final boolean isPoS, final Optional difficultyStoppedAt); + void mergeStateChanged( + final boolean isPoS, + final Optional priorState, + final Optional difficultyStoppedAt); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/MergePeerFilter.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/MergePeerFilter.java index 884bf78253f..a807785f948 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/MergePeerFilter.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/MergePeerFilter.java @@ -88,7 +88,9 @@ public void onNewForkchoiceMessage( @Override public void mergeStateChanged( - final boolean isPoS, final Optional difficultyStoppedAt) { + final boolean isPoS, + final Optional oldState, + final Optional difficultyStoppedAt) { if (isPoS && difficultyStoppedAt.isPresent()) { LOG.debug("terminal difficulty set to {}", difficultyStoppedAt.get().getValue()); long lockStamp = this.powTerminalDifficultyLock.writeLock(); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncState.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncState.java index 3be568069dd..026453c1bee 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncState.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncState.java @@ -177,8 +177,6 @@ public boolean isInSync(final long syncTolerance) { } public void setReachedTerminalDifficulty(final boolean stoppedAtTerminalDifficulty) { - // TODO: this is an inexpensive way to stop sync when we reach TTD, - // we should revisit when merge sync is better defined this.reachedTerminalDifficulty = Optional.of(stoppedAtTerminalDifficulty); ttdReachedListeners.forEach(listener -> listener.onTTDReached(stoppedAtTerminalDifficulty)); } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java index 4fee5d05e63..445c86949e1 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java @@ -235,7 +235,7 @@ public void disconnectNewPoWPeers() { ethManager.processMessage(EthProtocol.ETH63, new DefaultMessage(stakePeer, stakePeerStatus)); mergePeerFilter.mergeStateChanged( - true, Optional.of(blockchain.getChainHead().getTotalDifficulty())); + true, Optional.empty(), Optional.of(blockchain.getChainHead().getTotalDifficulty())); mergePeerFilter.onNewForkchoiceMessage( Hash.EMPTY, Optional.of(Hash.hash(Bytes.of(1))), Hash.EMPTY); mergePeerFilter.onNewForkchoiceMessage( From 992534e417dd45c072f2ba6a1ec7521c16ba03a8 Mon Sep 17 00:00:00 2001 From: Justin Florentine Date: Fri, 29 Jul 2022 12:14:17 -0400 Subject: [PATCH 057/109] Only stop block propagation, not tx handling. (#4186) * on block propagation stop, only kill the new block and new block hash handlers, leave all others (especially txs) alone Signed-off-by: Justin Florentine --- CHANGELOG.md | 4 +++- .../ethereum/eth/manager/EthMessages.java | 21 ++++++++++++++++--- .../besu/ethereum/eth/manager/EthPeers.java | 5 ++++- .../eth/sync/BlockPropagationManager.java | 5 +++-- .../AbstractBlockPropagationManagerTest.java | 3 +++ 5 files changed, 31 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3aa1a66423..c165eae6b8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,9 @@ ### Additions and Improvements - Deprecation warning for Ropsten, Rinkeby, Kiln [#4173](https://github.com/hyperledger/besu/pull/4173) -### Bug Fixes +### Bug Fixes + +- Fixes previous known issue [#3890](https://github.com/hyperledger/besu/issues/3890)from RC3 requiring a restart post-merge to continue correct transaction handling. - Stop producing stack traces when a get headers response only contains the range start header [#4189](https://github.com/hyperledger/besu/pull/4189) - Upgrade Spotless to 6.8.0 [#4195](https://github.com/hyperledger/besu/pull/4195) - Upgrade Gradle to 7.5 [#4196](https://github.com/hyperledger/besu/pull/4196) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthMessages.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthMessages.java index f1eca234bc0..fbaa6fbc310 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthMessages.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthMessages.java @@ -17,10 +17,14 @@ import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; import org.hyperledger.besu.util.Subscribers; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; +import com.google.common.annotations.VisibleForTesting; + public class EthMessages { private final Map> listenersByCode = new ConcurrentHashMap<>(); @@ -47,9 +51,12 @@ public long subscribe(final int messageCode, final MessageCallback callback) { .subscribe(callback); } - public void unsubsribe(final long id) { - for (Subscribers subscribers : listenersByCode.values()) { - subscribers.unsubscribe(id); + public void unsubscribe(final long subscriptionId, final int messageCode) { + if (listenersByCode.containsKey(messageCode)) { + listenersByCode.get(messageCode).unsubscribe(subscriptionId); + if (listenersByCode.get(messageCode).getSubscriberCount() < 1) { + listenersByCode.remove(messageCode); + } } } @@ -58,6 +65,14 @@ public void registerResponseConstructor( messageResponseConstructorsByCode.put(messageCode, messageResponseConstructor); } + @VisibleForTesting + public List messageCodesHandled() { + List retval = new ArrayList<>(); + retval.addAll(messageResponseConstructorsByCode.keySet()); + retval.addAll(listenersByCode.keySet()); + return retval; + } + @FunctionalInterface public interface MessageCallback { void exec(EthMessage message); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java index c5074a2f909..14ebf587c5c 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java @@ -107,7 +107,10 @@ public void registerConnection( clock, permissioningProviders); final EthPeer ethPeer = connections.putIfAbsent(peerConnection, peer); - LOG.debug("Adding new EthPeer {}", ethPeer); + LOG.debug( + "Adding new EthPeer {} {}", + peer.getShortNodeId(), + ethPeer == null ? "for the first time" : ""); } public void registerDisconnect(final PeerConnection connection) { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java index f53da690de5..d97c6b110d8 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java @@ -144,8 +144,9 @@ private void setupListeners() { private void clearListeners() { onBlockAddedSId.ifPresent(id -> protocolContext.getBlockchain().removeObserver(id)); - newBlockSId.ifPresent(id -> ethContext.getEthMessages().unsubsribe(id)); - newBlockHashesSId.ifPresent(id -> ethContext.getEthMessages().unsubsribe(id)); + newBlockSId.ifPresent(id -> ethContext.getEthMessages().unsubscribe(id, EthPV62.NEW_BLOCK)); + newBlockHashesSId.ifPresent( + id -> ethContext.getEthMessages().unsubscribe(id, EthPV62.NEW_BLOCK_HASHES)); onBlockAddedSId = Optional.empty(); newBlockSId = Optional.empty(); newBlockHashesSId = Optional.empty(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java index 7723ef5679e..d2ae85662f1 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java @@ -46,6 +46,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer.Responder; +import org.hyperledger.besu.ethereum.eth.messages.EthPV62; import org.hyperledger.besu.ethereum.eth.messages.NewBlockHashesMessage; import org.hyperledger.besu.ethereum.eth.messages.NewBlockMessage; import org.hyperledger.besu.ethereum.eth.sync.state.PendingBlocksManager; @@ -815,6 +816,8 @@ public void shouldStopWhenTTDReached() { blockPropagationManager.start(); syncState.setReachedTerminalDifficulty(true); assertThat(blockPropagationManager.isRunning()).isFalse(); + assertThat(ethProtocolManager.ethContext().getEthMessages().messageCodesHandled()) + .doesNotContain(EthPV62.NEW_BLOCK_HASHES, EthPV62.NEW_BLOCK); } @Test From 826648b2deecc40bf3eef731c7f7fed9ee60411c Mon Sep 17 00:00:00 2001 From: garyschulte Date: Sat, 30 Jul 2022 20:45:35 -0700 Subject: [PATCH 058/109] Feature/engine api override (#4190) * initial impl of engine-api override: * remove reliance on isMergeEnabled in pre-merge block header validation rules * create a merge-specific block header validtion stack rather than leveraging mainnet * re-add --engine-api-enabled cli param * make engine api usable without a merge config. leaves the door open to supporting the engine api with other MiningCoordinators, but disables all but engine_exchangeTransitionConfiguration in the absence of mergeCoordinator Signed-off-by: garyschulte --- .../org/hyperledger/besu/RunnerBuilder.java | 2 +- .../org/hyperledger/besu/cli/BesuCommand.java | 27 ++++++++-------- .../hyperledger/besu/cli/BesuCommandTest.java | 1 + .../src/test/resources/everything_config.toml | 1 + .../merge/MergeValidationRulesetFactory.java | 31 +++++++++++++------ .../blockcreation/MergeMiningCoordinator.java | 5 +++ .../methods/ExecutionEngineJsonRpcMethod.java | 8 +++-- ...EngineExchangeTransitionConfiguration.java | 12 +++++-- .../engine/EngineForkchoiceUpdated.java | 8 +++-- .../methods/engine/EngineGetPayload.java | 2 +- .../methods/engine/EngineNewPayload.java | 4 +-- .../ExecutionEngineJsonRpcMethods.java | 23 +++++++++----- .../methods/JsonRpcMethodsFactory.java | 7 +---- ...neExchangeTransitionConfigurationTest.java | 17 ++++++++++ .../engine/EngineForkchoiceUpdatedTest.java | 2 +- .../methods/engine/EngineGetPayloadTest.java | 2 +- .../methods/engine/EngineNewPayloadTest.java | 2 +- .../blockcreation/AbstractBlockCreator.java | 6 +--- .../blockcreation/MiningCoordinator.java | 4 +++ .../blockcreation/PoWMinerExecutor.java | 3 +- .../besu/ethereum/ProtocolContext.java | 8 +++++ .../mainnet/MainnetBlockHeaderValidator.java | 4 +-- .../CalculatedDifficultyValidationRule.java | 5 +-- .../ProofOfWorkValidationRule.java | 7 ----- .../TimestampMoreRecentThanParent.java | 4 --- 25 files changed, 122 insertions(+), 73 deletions(-) diff --git a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java index a21408a80d1..d8b1a38fc20 100644 --- a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java @@ -305,7 +305,7 @@ public RunnerBuilder jsonRpcConfiguration(final JsonRpcConfiguration jsonRpcConf public RunnerBuilder engineJsonRpcConfiguration( final JsonRpcConfiguration engineJsonRpcConfiguration) { - this.engineJsonRpcConfiguration = Optional.of(engineJsonRpcConfiguration); + this.engineJsonRpcConfiguration = Optional.ofNullable(engineJsonRpcConfiguration); return this; } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index 0d9097a0f11..9bada97133d 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -568,9 +568,9 @@ static class GraphQlOptionGroup { static class EngineRPCOptionGroup { @Option( names = {"--engine-rpc-enabled"}, - description = "deprectaed parameter, do not use.", - hidden = true) - private final Boolean deprecatedIsEngineRpcEnabled = false; + description = + "enable the engine api, even in the absence of merge-specific configurations.") + private final Boolean overrideEngineRpcEnabled = false; @Option( names = {"--engine-rpc-port", "--engine-rpc-http-port"}, @@ -1933,9 +1933,11 @@ private void configure() throws Exception { jsonRpcConfiguration = jsonRpcConfiguration( jsonRPCHttpOptionGroup.rpcHttpPort, jsonRPCHttpOptionGroup.rpcHttpApis, hostsAllowlist); - engineJsonRpcConfiguration = - createEngineJsonRpcConfiguration( - engineRPCOptionGroup.engineRpcPort, engineRPCOptionGroup.engineHostsAllowlist); + if (isEngineApiEnabled()) { + engineJsonRpcConfiguration = + createEngineJsonRpcConfiguration( + engineRPCOptionGroup.engineRpcPort, engineRPCOptionGroup.engineHostsAllowlist); + } p2pTLSConfiguration = p2pTLSConfigOptions.p2pTLSConfiguration(commandLine); graphQLConfiguration = graphQLConfiguration(); webSocketConfiguration = @@ -2129,12 +2131,7 @@ private JsonRpcConfiguration createEngineJsonRpcConfiguration( final Integer listenPort, final List allowCallsFrom) { JsonRpcConfiguration engineConfig = jsonRpcConfiguration(listenPort, Arrays.asList("ENGINE", "ETH"), allowCallsFrom); - if (engineRPCOptionGroup.deprecatedIsEngineRpcEnabled) { - logger.warn( - "--engine-api-enabled parameter has been deprecated and will be removed in a future release. " - + "Merge support is implicitly enabled by the presence of terminalTotalDifficulty in the genesis config."); - } - engineConfig.setEnabled(isMergeEnabled()); + engineConfig.setEnabled(isEngineApiEnabled()); if (!engineRPCOptionGroup.isEngineAuthDisabled) { engineConfig.setAuthenticationEnabled(true); engineConfig.setAuthenticationAlgorithm(JwtAlgorithm.HS256); @@ -3098,7 +3095,7 @@ private List getEffectivePorts() { effectivePorts, jsonRPCWebsocketOptionGroup.rpcWsPort, jsonRPCWebsocketOptionGroup.isRpcWsEnabled); - addPortIfEnabled(effectivePorts, engineRPCOptionGroup.engineRpcPort, isMergeEnabled()); + addPortIfEnabled(effectivePorts, engineRPCOptionGroup.engineRpcPort, isEngineApiEnabled()); addPortIfEnabled( effectivePorts, metricsOptionGroup.metricsPort, metricsOptionGroup.isMetricsEnabled); addPortIfEnabled( @@ -3222,6 +3219,10 @@ private boolean isMergeEnabled() { return MergeConfigOptions.isMergeEnabled(); } + private boolean isEngineApiEnabled() { + return engineRPCOptionGroup.overrideEngineRpcEnabled || isMergeEnabled(); + } + public static List getJDKEnabledCypherSuites() { try { SSLContext context = SSLContext.getInstance("TLS"); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index 7608c2e6be9..3ab6e7bbc7c 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -2760,6 +2760,7 @@ public void rpcHttpTlsWarnIfCipherSuitesSpecifiedWithoutTls() { parseCommand( "--rpc-http-enabled", + "--engine-rpc-enabled", "--rpc-http-host", host, "--rpc-http-port", diff --git a/besu/src/test/resources/everything_config.toml b/besu/src/test/resources/everything_config.toml index be722a507ba..0855f14605c 100644 --- a/besu/src/test/resources/everything_config.toml +++ b/besu/src/test/resources/everything_config.toml @@ -44,6 +44,7 @@ random-peer-priority-enabled=false host-whitelist=["all"] host-allowlist=["all"] engine-host-allowlist=["all"] +engine-rpc-enabled=true engine-jwt-disabled=true engine-jwt-secret="/tmp/jwt.hex" required-blocks=["8675309=123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"] diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeValidationRulesetFactory.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeValidationRulesetFactory.java index 1c26bdcd50d..e5f4f6b82f4 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeValidationRulesetFactory.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeValidationRulesetFactory.java @@ -14,17 +14,27 @@ */ package org.hyperledger.besu.consensus.merge; +import static org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderValidator.MIN_GAS_LIMIT; +import static org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderValidator.TIMESTAMP_TOLERANCE_S; + import org.hyperledger.besu.consensus.merge.headervalidationrules.ConstantOmmersHashRule; import org.hyperledger.besu.consensus.merge.headervalidationrules.IncrementalTimestampRule; import org.hyperledger.besu.consensus.merge.headervalidationrules.MergeUnfinalizedValidationRule; import org.hyperledger.besu.consensus.merge.headervalidationrules.NoDifficultyRule; import org.hyperledger.besu.consensus.merge.headervalidationrules.NoNonceRule; +import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.mainnet.BlockHeaderValidator; import org.hyperledger.besu.ethereum.mainnet.EpochCalculator; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderValidator; import org.hyperledger.besu.ethereum.mainnet.PoWHasher; import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; +import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.AncestryValidationRule; +import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.BaseFeeMarketBlockHeaderGasPriceValidationRule; +import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.ExtraDataMaxLengthValidationRule; +import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.GasLimitRangeAndDeltaValidationRule; +import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.GasUsageValidationRule; +import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.TimestampBoundedByFutureParameter; import java.util.Optional; @@ -40,7 +50,7 @@ public class MergeValidationRulesetFactory { *

Specifically the set of rules provided by this function are to be used for a Mainnet Merge * chain. * - * @param feeMarket the applicable {@link FeeMarket}, either PGA or BaseFee. + * @param feeMarket the applicable {@link FeeMarket} * @return the header validator. */ public static BlockHeaderValidator.Builder mergeBlockHeaderValidator(final FeeMarket feeMarket) { @@ -49,14 +59,17 @@ public static BlockHeaderValidator.Builder mergeBlockHeaderValidator(final FeeMa return MainnetBlockHeaderValidator.createPgaBlockHeaderValidator( preMergeCalculator, PoWHasher.ETHASH_LIGHT); } else { - return MainnetBlockHeaderValidator.createBaseFeeMarketValidator( - Optional.of(feeMarket) - .filter(FeeMarket::implementsBaseFee) - .map(BaseFeeMarket.class::cast) - .orElseThrow( - () -> - new RuntimeException( - "Invalid configuration: missing BaseFeeMarket for merge net"))) + var baseFeeMarket = (BaseFeeMarket) feeMarket; + + return new BlockHeaderValidator.Builder() + .addRule(new AncestryValidationRule()) + .addRule(new GasUsageValidationRule()) + .addRule( + new GasLimitRangeAndDeltaValidationRule( + MIN_GAS_LIMIT, Long.MAX_VALUE, Optional.of(baseFeeMarket))) + .addRule(new TimestampBoundedByFutureParameter(TIMESTAMP_TOLERANCE_S)) + .addRule(new ExtraDataMaxLengthValidationRule(BlockHeader.MAX_EXTRA_DATA_BYTES)) + .addRule((new BaseFeeMarketBlockHeaderGasPriceValidationRule(baseFeeMarket))) .addRule(new MergeUnfinalizedValidationRule()) .addRule(new ConstantOmmersHashRule()) .addRule(new NoNonceRule()) diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeMiningCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeMiningCoordinator.java index b5f616520a7..d83d16eb2c3 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeMiningCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeMiningCoordinator.java @@ -36,6 +36,11 @@ PayloadIdentifier preparePayload( final Bytes32 random, final Address feeRecipient); + @Override + default boolean isCompatibleWithEngineApi() { + return true; + } + Result rememberBlock(final Block block); Result validateBlock(final Block block); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecutionEngineJsonRpcMethod.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecutionEngineJsonRpcMethod.java index 0e031cae3c7..8f6ad7bcb60 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecutionEngineJsonRpcMethod.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecutionEngineJsonRpcMethod.java @@ -21,8 +21,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.function.Supplier; import io.vertx.core.Vertx; import org.slf4j.Logger; @@ -40,13 +42,15 @@ public enum EngineStatus { public static final long ENGINE_API_LOGGING_THRESHOLD = 60000L; private final Vertx syncVertx; private static final Logger LOG = LoggerFactory.getLogger(ExecutionEngineJsonRpcMethod.class); - protected final MergeContext mergeContext; + protected final Optional mergeContextOptional; + protected final Supplier mergeContext; protected final ProtocolContext protocolContext; protected ExecutionEngineJsonRpcMethod(final Vertx vertx, final ProtocolContext protocolContext) { this.syncVertx = vertx; this.protocolContext = protocolContext; - this.mergeContext = protocolContext.getConsensusContext(MergeContext.class); + this.mergeContextOptional = protocolContext.safeConsensusContext(MergeContext.class); + this.mergeContext = mergeContextOptional::orElseThrow; } @Override diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfiguration.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfiguration.java index 62118a0b862..f42efd4d70f 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfiguration.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfiguration.java @@ -27,11 +27,13 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineExchangeTransitionConfigurationResult; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.Difficulty; import java.util.Optional; import io.vertx.core.Vertx; import io.vertx.core.json.Json; +import org.apache.tuweni.units.bigints.UInt256; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,6 +41,9 @@ public class EngineExchangeTransitionConfiguration extends ExecutionEngineJsonRp private static final Logger LOG = LoggerFactory.getLogger(EngineExchangeTransitionConfiguration.class); + // use (2^256 - 2^10) if engine is enabled in the absence of a TTD configuration + static final Difficulty FALLBACK_TTD_DEFAULT = + Difficulty.MAX_VALUE.subtract(UInt256.valueOf(1024L)); static final long QOS_TIMEOUT_MILLIS = 120000L; private final QosTimer qosTimer; @@ -76,11 +81,14 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) "received transitionConfiguration: {}", () -> Json.encodePrettily(remoteTransitionConfiguration)); - final Optional maybeTerminalPoWBlockHeader = mergeContext.getTerminalPoWBlock(); + final Optional maybeTerminalPoWBlockHeader = + mergeContextOptional.get().getTerminalPoWBlock(); final EngineExchangeTransitionConfigurationResult localTransitionConfiguration = new EngineExchangeTransitionConfigurationResult( - mergeContext.getTerminalTotalDifficulty(), + mergeContextOptional + .map(c -> c.getTerminalTotalDifficulty()) + .orElse(FALLBACK_TTD_DEFAULT), maybeTerminalPoWBlockHeader.map(BlockHeader::getHash).orElse(Hash.ZERO), maybeTerminalPoWBlockHeader.map(BlockHeader::getNumber).orElse(0L)); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdated.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdated.java index bd8c7f70a15..2429d8e2790 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdated.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdated.java @@ -73,10 +73,12 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) Optional.ofNullable(forkChoice.getFinalizedBlockHash()) .filter(finalized -> !finalized.isZero()); - mergeContext.fireNewUnverifiedForkchoiceMessageEvent( - forkChoice.getHeadBlockHash(), maybeFinalizedHash, forkChoice.getSafeBlockHash()); + mergeContext + .get() + .fireNewUnverifiedForkchoiceMessageEvent( + forkChoice.getHeadBlockHash(), maybeFinalizedHash, forkChoice.getSafeBlockHash()); - if (mergeContext.isSyncing()) { + if (mergeContext.get().isSyncing()) { return syncingResponse(requestId, forkChoice); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayload.java index 1006ee90941..a2de8d1d433 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayload.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayload.java @@ -57,7 +57,7 @@ public String getName() { public JsonRpcResponse syncResponse(final JsonRpcRequestContext request) { final PayloadIdentifier payloadId = request.getRequiredParameter(0, PayloadIdentifier.class); - final Optional block = mergeContext.retrieveBlockById(payloadId); + final Optional block = mergeContext.get().retrieveBlockById(payloadId); if (block.isPresent()) { var proposal = block.get(); var proposalHeader = proposal.getHeader(); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java index 4713239f453..73c94f47796 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java @@ -166,10 +166,10 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) final var block = new Block(newBlockHeader, new BlockBody(transactions, Collections.emptyList())); - if (mergeContext.isSyncing() || parentHeader.isEmpty()) { + if (mergeContext.get().isSyncing() || parentHeader.isEmpty()) { LOG.debug( "isSyncing: {} parentHeaderMissing: {}, adding {} to backwardsync", - mergeContext.isSyncing(), + mergeContext.get().isSyncing(), parentHeader.isEmpty(), block.getHash()); mergeCoordinator diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java index d18d4e49262..8c81681974e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java @@ -26,6 +26,7 @@ import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; import java.util.Map; +import java.util.Optional; import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; @@ -34,12 +35,16 @@ public class ExecutionEngineJsonRpcMethods extends ApiGroupJsonRpcMethods { private final BlockResultFactory blockResultFactory = new BlockResultFactory(); - private final MergeMiningCoordinator mergeCoordinator; + private final Optional mergeCoordinator; private final ProtocolContext protocolContext; ExecutionEngineJsonRpcMethods( final MiningCoordinator miningCoordinator, final ProtocolContext protocolContext) { - this.mergeCoordinator = (MergeMiningCoordinator) miningCoordinator; + this.mergeCoordinator = + Optional.ofNullable(miningCoordinator) + .filter(mc -> mc.isCompatibleWithEngineApi()) + .map(MergeMiningCoordinator.class::cast); + this.protocolContext = protocolContext; } @@ -51,10 +56,14 @@ protected String getApiGroup() { @Override protected Map create() { Vertx syncVertx = Vertx.vertx(new VertxOptions().setWorkerPoolSize(1)); - return mapOf( - new EngineGetPayload(syncVertx, protocolContext, blockResultFactory), - new EngineNewPayload(syncVertx, protocolContext, mergeCoordinator), - new EngineForkchoiceUpdated(syncVertx, protocolContext, mergeCoordinator), - new EngineExchangeTransitionConfiguration(syncVertx, protocolContext)); + if (mergeCoordinator.isPresent()) { + return mapOf( + new EngineGetPayload(syncVertx, protocolContext, blockResultFactory), + new EngineNewPayload(syncVertx, protocolContext, mergeCoordinator.get()), + new EngineForkchoiceUpdated(syncVertx, protocolContext, mergeCoordinator.get()), + new EngineExchangeTransitionConfiguration(syncVertx, protocolContext)); + } else { + return mapOf(new EngineExchangeTransitionConfiguration(syncVertx, protocolContext)); + } } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java index e71816ab2c8..59bf78ee886 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java @@ -15,7 +15,6 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.methods; import org.hyperledger.besu.config.GenesisConfigOptions; -import org.hyperledger.besu.config.MergeConfigOptions; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; @@ -95,6 +94,7 @@ public Map methods( blockchainQueries, protocolSchedule, metricsSystem, transactionPool, dataDir), new EeaJsonRpcMethods( blockchainQueries, protocolSchedule, transactionPool, privacyParameters), + new ExecutionEngineJsonRpcMethods(miningCoordinator, protocolContext), new GoQuorumJsonRpcPrivacyMethods( blockchainQueries, protocolSchedule, transactionPool, privacyParameters), new EthJsonRpcMethods( @@ -127,11 +127,6 @@ public Map methods( new TxPoolJsonRpcMethods(transactionPool), new PluginsJsonRpcMethods(namedPlugins)); - if (MergeConfigOptions.isMergeEnabled()) { - enabled.putAll( - new ExecutionEngineJsonRpcMethods(miningCoordinator, protocolContext).create(rpcApis)); - } - for (final JsonRpcMethods apiGroup : availableApiGroups) { enabled.putAll(apiGroup.create(rpcApis)); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java index 04b54ceaaaf..88a5dc211b4 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineExchangeTransitionConfiguration.FALLBACK_TTD_DEFAULT; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -70,6 +71,7 @@ public class EngineExchangeTransitionConfigurationTest { @Before public void setUp() { when(protocolContext.getConsensusContext(Mockito.any())).thenReturn(mergeContext); + when(protocolContext.safeConsensusContext(Mockito.any())).thenReturn(Optional.of(mergeContext)); this.method = new EngineExchangeTransitionConfiguration(vertx, protocolContext); } @@ -114,6 +116,21 @@ public void shouldReturnZerosOnTerminalPoWBlockHeaderEmpty() { assertThat(result.getTerminalBlockNumber()).isEqualTo(0L); } + @Test + public void shouldReturnDefaultOnNoTerminalTotalDifficultyConfigured() { + when(mergeContext.getTerminalPoWBlock()).thenReturn(Optional.empty()); + + var response = + resp( + new EngineExchangeTransitionConfigurationParameter( + "0", Hash.ZERO.toHexString(), new UnsignedLongParameter(0L))); + + var result = fromSuccessResp(response); + assertThat(result.getTerminalTotalDifficulty()).isEqualTo(FALLBACK_TTD_DEFAULT); + assertThat(result.getTerminalBlockHash()).isEqualTo(Hash.ZERO); + assertThat(result.getTerminalBlockNumber()).isEqualTo(0L); + } + @Test public void shouldReturnConfigurationOnConfigurationMisMatch() { final BlockHeader fakeBlockHeader = createBlockHeader(Hash.fromHexStringLenient("0x01"), 42); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedTest.java index b95724218be..233d1fe9a6e 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedTest.java @@ -79,7 +79,7 @@ public class EngineForkchoiceUpdatedTest { @Before public void before() { - when(protocolContext.getConsensusContext(Mockito.any())).thenReturn(mergeContext); + when(protocolContext.safeConsensusContext(Mockito.any())).thenReturn(Optional.of(mergeContext)); when(protocolContext.getBlockchain()).thenReturn(blockchain); this.method = new EngineForkchoiceUpdated(vertx, protocolContext, mergeCoordinator); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadTest.java index 3c1ee216f46..0cfb2b62153 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadTest.java @@ -66,7 +66,7 @@ public class EngineGetPayloadTest { @Before public void before() { when(mergeContext.retrieveBlockById(mockPid)).thenReturn(Optional.of(mockBlock)); - when(protocolContext.getConsensusContext(Mockito.any())).thenReturn(mergeContext); + when(protocolContext.safeConsensusContext(Mockito.any())).thenReturn(Optional.of(mergeContext)); this.method = new EngineGetPayload(vertx, protocolContext, factory); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java index c98a42e5187..74d48c62d29 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java @@ -79,7 +79,7 @@ public class EngineNewPayloadTest { @Before public void before() { - when(protocolContext.getConsensusContext(Mockito.any())).thenReturn(mergeContext); + when(protocolContext.safeConsensusContext(Mockito.any())).thenReturn(Optional.of(mergeContext)); when(protocolContext.getBlockchain()).thenReturn(blockchain); this.method = new EngineNewPayload(vertx, protocolContext, mergeCoordinator); } diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java index a5d4eae0942..333191667eb 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java @@ -14,7 +14,6 @@ */ package org.hyperledger.besu.ethereum.blockcreation; -import org.hyperledger.besu.config.MergeConfigOptions; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; @@ -44,7 +43,6 @@ import org.hyperledger.besu.plugin.services.securitymodule.SecurityModuleException; import java.math.BigInteger; -import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.concurrent.CancellationException; @@ -191,9 +189,7 @@ protected Block createBlock( final SealableBlockHeader sealableBlockHeader = BlockHeaderBuilder.create() .populateFrom(processableBlockHeader) - .ommersHash( - BodyValidation.ommersHash( - MergeConfigOptions.isMergeEnabled() ? Collections.emptyList() : ommers)) + .ommersHash(BodyValidation.ommersHash(ommers)) .stateRoot(disposableWorldState.rootHash()) .transactionsRoot( BodyValidation.transactionsRoot(transactionResults.getTransactions())) diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/MiningCoordinator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/MiningCoordinator.java index 642ebd8393e..68353f7ae7e 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/MiningCoordinator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/MiningCoordinator.java @@ -117,4 +117,8 @@ Optional createBlock( default void addEthHashObserver(final PoWObserver observer) {} void changeTargetGasLimit(final Long targetGasLimit); + + default boolean isCompatibleWithEngineApi() { + return false; + } } diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java index c570a434cff..5750b2c6672 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java @@ -14,7 +14,6 @@ */ package org.hyperledger.besu.ethereum.blockcreation; -import org.hyperledger.besu.config.MergeConfigOptions; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.MinedBlockObserver; @@ -85,7 +84,7 @@ public PoWBlockMiner createMiner( final Function blockCreator = (header) -> new PoWBlockCreator( - coinbase.orElseGet(() -> MergeConfigOptions.isMergeEnabled() ? Address.ZERO : null), + coinbase.orElse(Address.ZERO), () -> targetGasLimit.map(AtomicLong::longValue), parent -> extraData, pendingTransactions, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/ProtocolContext.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/ProtocolContext.java index 750c06a1e66..0b115937053 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/ProtocolContext.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/ProtocolContext.java @@ -18,6 +18,8 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import java.util.Optional; + /** * Holds the mutable state used to track the current context of the protocol. This is primarily the * blockchain and world state archive, but can also hold arbitrary context required by a particular @@ -59,4 +61,10 @@ public WorldStateArchive getWorldStateArchive() { public C getConsensusContext(final Class klass) { return consensusContext.as(klass); } + + public Optional safeConsensusContext(final Class klass) { + return Optional.ofNullable(consensusContext) + .filter(c -> klass.isAssignableFrom(c.getClass())) + .map(klass::cast); + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java index 2c3a054aea0..84b9357d317 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java @@ -34,8 +34,8 @@ public final class MainnetBlockHeaderValidator { public static final Bytes DAO_EXTRA_DATA = Bytes.fromHexString("0x64616f2d686172642d666f726b"); - private static final int MIN_GAS_LIMIT = 5000; - private static final long MAX_GAS_LIMIT = 0x7fffffffffffffffL; + public static final int MIN_GAS_LIMIT = 5000; + public static final long MAX_GAS_LIMIT = 0x7fffffffffffffffL; public static final int TIMESTAMP_TOLERANCE_S = 15; public static final int MINIMUM_SECONDS_SINCE_PARENT = 1; public static final Bytes CLASSIC_FORK_BLOCK_HEADER = diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/CalculatedDifficultyValidationRule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/CalculatedDifficultyValidationRule.java index 2bffde67cc5..bcc4e213586 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/CalculatedDifficultyValidationRule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/CalculatedDifficultyValidationRule.java @@ -14,7 +14,6 @@ */ package org.hyperledger.besu.ethereum.mainnet.headervalidationrules; -import org.hyperledger.besu.config.MergeConfigOptions; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.mainnet.AttachedBlockHeaderValidationRule; @@ -37,9 +36,7 @@ public CalculatedDifficultyValidationRule(final DifficultyCalculator difficultyC @Override public boolean validate( final BlockHeader header, final BlockHeader parent, final ProtocolContext context) { - if (MergeConfigOptions.isMergeEnabled()) { - return true; - } + final BigInteger actualDifficulty = new BigInteger(1, header.getDifficulty().toArray()); final BigInteger expectedDifficulty = difficultyCalculator.nextDifficulty(header.getTimestamp(), parent, context); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ProofOfWorkValidationRule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ProofOfWorkValidationRule.java index 2c98f311b24..6f1612f1c89 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ProofOfWorkValidationRule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ProofOfWorkValidationRule.java @@ -16,7 +16,6 @@ import static java.lang.Boolean.FALSE; -import org.hyperledger.besu.config.MergeConfigOptions; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.mainnet.DetachedBlockHeaderValidationRule; @@ -70,12 +69,6 @@ public boolean validate(final BlockHeader header, final BlockHeader parent) { return false; } - // TODO: remove this rule bypass, use post-merge headervalidation rules - // https://github.com/hyperledger/besu/issues/2898 - if (MergeConfigOptions.isMergeEnabled()) { - return true; - } - final Hash headerHash = hashHeader(header); PoWSolution solution = hasher.hash(header.getNonce(), header.getNumber(), epochCalculator, headerHash); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/TimestampMoreRecentThanParent.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/TimestampMoreRecentThanParent.java index 2af6d23d87b..6aa7e5479ef 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/TimestampMoreRecentThanParent.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/TimestampMoreRecentThanParent.java @@ -16,7 +16,6 @@ import static com.google.common.base.Preconditions.checkArgument; -import org.hyperledger.besu.config.MergeConfigOptions; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.mainnet.DetachedBlockHeaderValidationRule; @@ -36,9 +35,6 @@ public TimestampMoreRecentThanParent(final long minimumSecondsSinceParent) { @Override public boolean validate(final BlockHeader header, final BlockHeader parent) { - if (MergeConfigOptions.isMergeEnabled()) { - return true; - } return validateTimestamp(header.getTimestamp(), parent.getTimestamp()); } From 7c29709fe36d537621cf4bcc5dee033a53076d54 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Mon, 1 Aug 2022 20:41:50 -0700 Subject: [PATCH 059/109] =?UTF-8?q?fix=20optional=20handling=20and=20merge?= =?UTF-8?q?Context=20mock=20in=20unit=20test=20for=20EngineEx=E2=80=A6chan?= =?UTF-8?q?geTransitionConfiguration=20(#4205)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: garyschulte --- .../methods/engine/EngineExchangeTransitionConfiguration.java | 3 ++- .../engine/EngineExchangeTransitionConfigurationTest.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfiguration.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfiguration.java index f42efd4d70f..e4db64e5226 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfiguration.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfiguration.java @@ -17,6 +17,7 @@ import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod.ENGINE_EXCHANGE_TRANSITION_CONFIGURATION; import static org.hyperledger.besu.util.Slf4jLambdaHelper.traceLambda; +import org.hyperledger.besu.consensus.merge.MergeContext; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; @@ -82,7 +83,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) () -> Json.encodePrettily(remoteTransitionConfiguration)); final Optional maybeTerminalPoWBlockHeader = - mergeContextOptional.get().getTerminalPoWBlock(); + mergeContextOptional.flatMap(MergeContext::getTerminalPoWBlock); final EngineExchangeTransitionConfigurationResult localTransitionConfiguration = new EngineExchangeTransitionConfigurationResult( diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java index 88a5dc211b4..bc60a44d2be 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java @@ -118,7 +118,7 @@ public void shouldReturnZerosOnTerminalPoWBlockHeaderEmpty() { @Test public void shouldReturnDefaultOnNoTerminalTotalDifficultyConfigured() { - when(mergeContext.getTerminalPoWBlock()).thenReturn(Optional.empty()); + when(protocolContext.safeConsensusContext(Mockito.any())).thenReturn(Optional.empty()); var response = resp( From e1c8eb7fb04f6602da602e75b84795f2e3220326 Mon Sep 17 00:00:00 2001 From: Justin Florentine Date: Tue, 2 Aug 2022 13:36:12 -0400 Subject: [PATCH 060/109] applies merge filtering to peers after 2 finalized (#4124) * applies merge filtering to peers after 2 finalized * fixes logical error in handling status messages Signed-off-by: Justin Florentine --- .../besu/controller/MergeBesuControllerBuilder.java | 10 ++++++---- .../besu/ethereum/eth/manager/EthProtocolManager.java | 8 +++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java index bb140b87edd..860385ae44c 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java @@ -104,11 +104,13 @@ protected EthProtocolManager createEthProtocolManager( ethPeers.setBestChainComparator(mergeBestPeerComparator); mergeContext.observeNewIsPostMergeState(mergeBestPeerComparator); - if (mergePeerFilter.isPresent()) { + Optional filterToUse = Optional.of(new MergePeerFilter()); - mergeContext.observeNewIsPostMergeState(mergePeerFilter.get()); - mergeContext.addNewForkchoiceMessageListener(mergePeerFilter.get()); + if (mergePeerFilter.isPresent()) { + filterToUse = mergePeerFilter; } + mergeContext.observeNewIsPostMergeState(filterToUse.get()); + mergeContext.addNewForkchoiceMessageListener(filterToUse.get()); EthProtocolManager ethProtocolManager = super.createEthProtocolManager( @@ -121,7 +123,7 @@ protected EthProtocolManager createEthProtocolManager( ethMessages, scheduler, peerValidators, - mergePeerFilter); + filterToUse); return ethProtocolManager; } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java index 5edcb3236d8..2710cc18790 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java @@ -376,11 +376,9 @@ private void handleStatusMessage(final EthPeer peer, final MessageData data) { networkId, status.genesisHash()); peer.disconnect(DisconnectReason.SUBPROTOCOL_TRIGGERED); - } else if (mergePeerFilter.isPresent()) { - final boolean disconnected = mergePeerFilter.get().disconnectIfPoW(status, peer); - if (disconnected) { - handleDisconnect(peer.getConnection(), DisconnectReason.SUBPROTOCOL_TRIGGERED, false); - } + } else if (mergePeerFilter.isPresent() + && mergePeerFilter.get().disconnectIfPoW(status, peer)) { + handleDisconnect(peer.getConnection(), DisconnectReason.SUBPROTOCOL_TRIGGERED, false); } else { LOG.debug("Received status message from {}: {}", peer, status); peer.registerStatusReceived( From 42cfff0acb76983dc8807b398670d891afb714d2 Mon Sep 17 00:00:00 2001 From: Stefan Pingel <16143240+pinges@users.noreply.github.com> Date: Wed, 3 Aug 2022 05:48:33 +1000 Subject: [PATCH 061/109] DNS peers handled the same as boot nodes (#4178) * DNS peers handled the same as boot nodes * make sure that non bonded peers can be used as initial peers * try to connect to DNS nodes Signed-off-by: Stefan Co-authored-by: Justin Florentine --- .../options/unstable/NetworkingOptions.java | 4 +- .../eth/manager/EthProtocolManager.java | 11 +++ .../p2p/discovery/PeerDiscoveryAgent.java | 4 + .../internal/PeerDiscoveryController.java | 23 +++--- .../discovery/internal/PeerRequirement.java | 2 +- .../p2p/discovery/internal/PeerTable.java | 19 ++++- .../discovery/internal/PingPacketData.java | 4 +- .../discovery/internal/PongPacketData.java | 6 +- .../internal/RecursivePeerRefreshState.java | 1 + .../p2p/network/DefaultP2PNetwork.java | 25 +++--- .../besu/ethereum/p2p/rlpx/RlpxAgent.java | 3 +- .../rlpx/connections/netty/ApiHandler.java | 4 +- .../p2p/network/DefaultP2PNetworkTest.java | 32 -------- .../rlpx/connections/netty/DeFramerTest.java | 78 ++++++++++--------- 14 files changed, 111 insertions(+), 105 deletions(-) diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/NetworkingOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/NetworkingOptions.java index bb0045d612f..a737883f74b 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/NetworkingOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/NetworkingOptions.java @@ -85,7 +85,7 @@ public static NetworkingOptions fromConfig(final NetworkingConfiguration network @Override public NetworkingConfiguration toDomainObject() { - NetworkingConfiguration config = NetworkingConfiguration.create(); + final NetworkingConfiguration config = NetworkingConfiguration.create(); config.setCheckMaintainedConnectionsFrequency(checkMaintainedConnectionsFrequencySec); config.setInitiateConnectionsFrequency(initiateConnectionsFrequencySec); config.setDnsDiscoveryServerOverride(dnsDiscoveryServerOverride); @@ -95,7 +95,7 @@ public NetworkingConfiguration toDomainObject() { @Override public List getCLIOptions() { - List retval = + final List retval = Arrays.asList( CHECK_MAINTAINED_CONNECTIONS_FREQUENCY_FLAG, OptionParser.format(checkMaintainedConnectionsFrequencySec), diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java index 2710cc18790..f065e0b1416 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java @@ -72,6 +72,7 @@ public class EthProtocolManager implements ProtocolManager, MinedBlockObserver { private final BlockBroadcaster blockBroadcaster; private final List peerValidators; private final Optional mergePeerFilter; + private final int maxMessageSize; public EthProtocolManager( final Blockchain blockchain, @@ -101,6 +102,8 @@ public EthProtocolManager( this.ethMessages = ethMessages; this.ethContext = ethContext; + this.maxMessageSize = ethereumWireProtocolConfiguration.getMaxMessageSize(); + this.blockBroadcaster = new BlockBroadcaster(ethContext); supportedCapabilities = calculateCapabilities(fastSyncEnabled); @@ -278,6 +281,14 @@ public void processMessage(final Capability cap, final Message message) { return; } + if (messageData.getSize() > this.maxMessageSize) { + LOG.debug( + "Peer {} sent a message with size {}, larger than the max message size {}", + ethPeer, + messageData.getSize(), + this.maxMessageSize); + } + // This will handle responses ethPeers.dispatchMessage(ethPeer, ethMessage, getSupportedProtocol()); diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryAgent.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryAgent.java index 96937a51304..df1f6df0776 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryAgent.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryAgent.java @@ -179,6 +179,10 @@ public CompletableFuture start(final int tcpPort) { } } + public Optional getPeerDiscoveryController() { + return controller; + } + public void updateNodeRecord() { if (!config.isActive()) { return; diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryController.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryController.java index 9ed33d51b4f..e6103d2ba49 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryController.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryController.java @@ -315,7 +315,7 @@ public void onMessage(final Packet packet, final DiscoveryPeer sender) { .ifPresent( interaction -> { bondingPeers.invalidate(peer.getId()); - addToPeerTable(peer); + addBondedPeerToPeerTable(peer); recursivePeerRefreshState.onBondingComplete(peer); }); break; @@ -369,16 +369,11 @@ private List getPeersFromNeighborsPacket(final Packet packet) { .collect(Collectors.toList()); } - private boolean addToPeerTable(final DiscoveryPeer peer) { + private boolean addBondedPeerToPeerTable(final DiscoveryPeer peer) { if (!peerPermissions.isAllowedInPeerTable(peer)) { return false; } - final PeerTable.AddResult result = peerTable.tryAdd(peer); - if (result.getOutcome() == PeerTable.AddResult.AddOutcome.SELF) { - return false; - } - // Reset the last seen timestamp. final long now = System.currentTimeMillis(); if (peer.getFirstDiscovered() == 0) { @@ -391,6 +386,16 @@ private boolean addToPeerTable(final DiscoveryPeer peer) { notifyPeerBonded(peer, now); } + return addToPeerTable(peer); + } + + public boolean addToPeerTable(final DiscoveryPeer peer) { + final PeerTable.AddResult result = peerTable.tryAdd(peer); + + if (result.getOutcome() == PeerTable.AddResult.AddOutcome.SELF) { + return false; + } + if (result.getOutcome() == PeerTable.AddResult.AddOutcome.ALREADY_EXISTED) { // Bump peer. peerTable.tryEvict(peer); @@ -584,7 +589,7 @@ private void respondToFindNeighbors( // 16 + 4 + 4 + 64 = 88 bytes // 88 * 13 = 1144 bytes // To fit under 1280 bytes, we must return just 13 peers maximum. - final List peers = peerTable.nearestPeers(packetData.getTarget(), 13); + final List peers = peerTable.nearestBondedPeers(packetData.getTarget(), 13); final PacketData data = NeighborsPacketData.create(peers); sendPacket(sender, PacketType.NEIGHBORS, data); } @@ -636,7 +641,7 @@ private DiscoveryPeer resolvePeer(final DiscoveryPeer peer) { peerTable.get(peer).filter(known -> known.discoveryEndpointMatches(peer)); DiscoveryPeer resolvedPeer = maybeKnownPeer.orElse(peer); if (maybeKnownPeer.isEmpty()) { - DiscoveryPeer bondingPeer = bondingPeers.getIfPresent(peer.getId()); + final DiscoveryPeer bondingPeer = bondingPeers.getIfPresent(peer.getId()); if (bondingPeer != null) { resolvedPeer = bondingPeer; } diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerRequirement.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerRequirement.java index 2658ebbab68..9da923bbbc9 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerRequirement.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerRequirement.java @@ -25,7 +25,7 @@ public interface PeerRequirement { static PeerRequirement combine(final Collection peerRequirements) { return () -> { - for (PeerRequirement peerRequirement : peerRequirements) { + for (final PeerRequirement peerRequirement : peerRequirements) { if (!peerRequirement.hasSufficientPeers()) { return false; } diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerTable.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerTable.java index 48fd3af294b..dee6e0cf99d 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerTable.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerTable.java @@ -182,6 +182,24 @@ private void buildBloomFilter() { this.idBloom = bf; } + /** + * Returns the limit peers (at most) bonded closest to the provided target, based on + * the XOR distance between the keccak-256 hash of the ID and the keccak-256 hash of the target. + * + * @param target The target node ID. + * @param limit The amount of results to return. + * @return The limit closest peers, at most. + */ + public List nearestBondedPeers(final Bytes target, final int limit) { + final Bytes keccak256 = Hash.keccak256(target); + return streamAllPeers() + .filter(p -> p.getStatus() == PeerDiscoveryStatus.BONDED) + .sorted( + comparingInt((peer) -> PeerDistanceCalculator.distance(peer.keccak256(), keccak256))) + .limit(limit) + .collect(toList()); + } + /** * Returns the limit peers (at most) closest to the provided target, based on the XOR * distance between the keccak-256 hash of the ID and the keccak-256 hash of the target. @@ -193,7 +211,6 @@ private void buildBloomFilter() { public List nearestPeers(final Bytes target, final int limit) { final Bytes keccak256 = Hash.keccak256(target); return streamAllPeers() - .filter(p -> p.getStatus() == PeerDiscoveryStatus.BONDED) .sorted( comparingInt((peer) -> PeerDistanceCalculator.distance(peer.keccak256(), keccak256))) .limit(limit) diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PingPacketData.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PingPacketData.java index dba2cafd8e3..88c0e4ac708 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PingPacketData.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PingPacketData.java @@ -98,9 +98,9 @@ public static PingPacketData readFrom(final RLPInput in) { if (!in.isEndOfCurrentList()) { try { enrSeq = UInt64.valueOf(in.readBigIntegerScalar()); - LOG.debug("read PING enr as long scalar"); + LOG.trace("read PING enr as long scalar"); } catch (MalformedRLPInputException malformed) { - LOG.debug("failed to read PING enr as scalar, trying to read bytes instead"); + LOG.trace("failed to read PING enr as scalar, trying to read bytes instead"); enrSeq = UInt64.fromBytes(in.readBytes()); } } diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PongPacketData.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PongPacketData.java index 80ed430242c..dd832c17032 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PongPacketData.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PongPacketData.java @@ -63,9 +63,9 @@ public static PongPacketData readFrom(final RLPInput in) { if (!in.isEndOfCurrentList()) { try { enrSeq = UInt64.valueOf(in.readBigIntegerScalar()); - LOG.debug("read PONG enr from scalar"); - } catch (MalformedRLPInputException malformed) { - LOG.debug("failed to read PONG enr from scalar, trying as byte array"); + LOG.trace("read PONG enr from scalar"); + } catch (final MalformedRLPInputException malformed) { + LOG.trace("failed to read PONG enr from scalar, trying as byte array"); enrSeq = UInt64.fromBytes(in.readBytes()); } } diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/RecursivePeerRefreshState.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/RecursivePeerRefreshState.java index 62105b2686b..dbbe594d38b 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/RecursivePeerRefreshState.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/RecursivePeerRefreshState.java @@ -93,6 +93,7 @@ private boolean reachedMaximumNumberOfRounds() { } private void addInitialPeers(final List initialPeers) { + LOG.debug("INITIAL PEERS: {}", initialPeers); this.initialPeers = initialPeers; for (final DiscoveryPeer peer : initialPeers) { final MetadataPeer iterationParticipant = diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java index afbf7872837..2efdb8cbc0d 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java @@ -25,6 +25,7 @@ import org.hyperledger.besu.ethereum.p2p.discovery.PeerDiscoveryEvent.PeerBondedEvent; import org.hyperledger.besu.ethereum.p2p.discovery.PeerDiscoveryStatus; import org.hyperledger.besu.ethereum.p2p.discovery.VertxPeerDiscoveryAgent; +import org.hyperledger.besu.ethereum.p2p.discovery.internal.PeerDiscoveryController; import org.hyperledger.besu.ethereum.p2p.peers.DefaultPeerPrivileges; import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl; import org.hyperledger.besu.ethereum.p2p.peers.LocalNode; @@ -56,7 +57,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Optional; @@ -67,7 +67,6 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -149,8 +148,6 @@ public class DefaultP2PNetwork implements P2PNetwork { private final Duration shutdownTimeout = Duration.ofMinutes(1); private DNSDaemon dnsDaemon; - @VisibleForTesting final AtomicReference> dnsPeers = new AtomicReference<>(); - /** * Creates a peer networking service for production purposes. * @@ -215,6 +212,8 @@ public void start() { Optional.ofNullable(config.getDiscovery().getDNSDiscoveryURL()) .ifPresent( disco -> { + // These lists are updated every 12h + // We retrieve the list every 30 minutes (1800000 msec) LOG.info("Starting DNS discovery with URL {}", disco); config .getDnsDiscoveryServerOverride() @@ -228,7 +227,7 @@ public void start() { disco, createDaemonListener(), 0L, - 60000L, + 1800000L, config.getDnsDiscoveryServerOverride().orElse(null)); dnsDaemon.start(); }); @@ -347,11 +346,16 @@ DNSDaemonListener createDaemonListener() { .build(); final DiscoveryPeer peer = DiscoveryPeer.fromEnode(enodeURL); peers.add(peer); - rlpxAgent.connect(peer); } - // only replace dnsPeers if the lookup was successful: if (!peers.isEmpty()) { - dnsPeers.set(peers); + final Optional peerDiscoveryController = + peerDiscoveryAgent.getPeerDiscoveryController(); + if (peerDiscoveryController.isPresent()) { + final PeerDiscoveryController controller = peerDiscoveryController.get(); + LOG.debug("Adding {} DNS peers to PeerTable", peers.size()); + peers.forEach(controller::addToPeerTable); + peers.forEach(rlpxAgent::connect); + } } }; } @@ -383,11 +387,6 @@ public Collection getPeers() { @Override public Stream streamDiscoveredPeers() { - final List peers = dnsPeers.get(); - if (peers != null) { - Collections.shuffle(peers); - return Stream.concat(peerDiscoveryAgent.streamDiscoveredPeers(), peers.stream()); - } return peerDiscoveryAgent.streamDiscoveredPeers(); } diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgent.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgent.java index 5691c63bdba..38c85dbffb8 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgent.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgent.java @@ -222,8 +222,7 @@ public CompletableFuture connect(final Peer peer) { // Check peer is valid final EnodeURL enode = peer.getEnodeURL(); if (!enode.isListening()) { - final String errorMsg = - "Attempt to connect to peer with no listening port: " + enode.toString(); + final String errorMsg = "Attempt to connect to peer with no listening port: " + enode; LOG.warn(errorMsg); return CompletableFuture.failedFuture((new IllegalArgumentException(errorMsg))); } diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/ApiHandler.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/ApiHandler.java index 39dbfb2d8bd..c5793df074f 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/ApiHandler.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/ApiHandler.java @@ -63,7 +63,7 @@ protected void channelRead0(final ChannelHandlerContext ctx, final MessageData o if (demultiplexed.getCapability() == null) { switch (message.getCode()) { case WireMessageCodes.PING: - LOG.debug("Received Wire PING"); + LOG.trace("Received Wire PING"); try { connection.send(null, PongMessage.get()); } catch (final PeerConnection.PeerNotConnected peerNotConnected) { @@ -71,7 +71,7 @@ protected void channelRead0(final ChannelHandlerContext ctx, final MessageData o } break; case WireMessageCodes.PONG: - LOG.debug("Received Wire PONG"); + LOG.trace("Received Wire PONG"); waitingForPong.set(false); break; case WireMessageCodes.DISCONNECT: diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetworkTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetworkTest.java index f9847c816be..a1002577917 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetworkTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetworkTest.java @@ -53,7 +53,6 @@ import org.hyperledger.besu.nat.core.domain.NetworkProtocol; import org.hyperledger.besu.nat.upnp.UpnpNatManager; -import java.net.InetAddress; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -65,8 +64,6 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.crypto.SECP256K1; -import org.apache.tuweni.devp2p.EthereumNodeRecord; -import org.apache.tuweni.discovery.DNSDaemonListener; import org.assertj.core.api.Assertions; import org.junit.Before; import org.junit.Test; @@ -410,35 +407,6 @@ public void shouldUseDnsServerOverrideIfPresent() { verify(dnsConfig, times(2)).getDnsDiscoveryServerOverride(); } - @Test - public void shouldNotDropDnsHostsOnEmptyLookup() { - DefaultP2PNetwork network = network(); - DNSDaemonListener listenerUnderTest = network.createDaemonListener(); - - // assert no entries prior to lookup - assertThat(network.dnsPeers.get()).isNull(); - - // simulate successful lookup of 1 peer - listenerUnderTest.newRecords( - 1, - List.of( - EthereumNodeRecord.create( - SECP256K1.KeyPair.fromSecretKey(mockKey), - 1L, - null, - null, - InetAddress.getLoopbackAddress(), - 30303, - 30303))); - assertThat(network.dnsPeers.get()).isNotEmpty(); - assertThat(network.dnsPeers.get().size()).isEqualTo(1); - - // simulate failed lookup empty list - listenerUnderTest.newRecords(2, Collections.emptyList()); - assertThat(network.dnsPeers.get()).isNotEmpty(); - assertThat(network.dnsPeers.get().size()).isEqualTo(1); - } - private DefaultP2PNetwork network() { return (DefaultP2PNetwork) builder().build(); } diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramerTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramerTest.java index a9d7ea4acc7..232b33c65fd 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramerTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramerTest.java @@ -167,26 +167,26 @@ public void exceptionCaught_shouldHandleGenericExceptionWhenFutureCompletedExcep @Test public void decode_handlesHello() throws ExecutionException, InterruptedException { - ChannelFuture future = NettyMocks.channelFuture(false); + final ChannelFuture future = NettyMocks.channelFuture(false); when(channel.closeFuture()).thenReturn(future); final Peer peer = createRemotePeer(); final PeerInfo remotePeerInfo = createPeerInfo(peer); - HelloMessage helloMessage = HelloMessage.create(remotePeerInfo); - ByteBuf data = Unpooled.wrappedBuffer(helloMessage.getData().toArray()); + final HelloMessage helloMessage = HelloMessage.create(remotePeerInfo); + final ByteBuf data = Unpooled.wrappedBuffer(helloMessage.getData().toArray()); when(framer.deframe(eq(data))) .thenReturn(new RawMessage(helloMessage.getCode(), helloMessage.getData())) .thenReturn(null); - List out = new ArrayList<>(); + final List out = new ArrayList<>(); deFramer.decode(ctx, data, out); assertThat(connectFuture).isDone(); assertThat(connectFuture).isNotCompletedExceptionally(); - PeerConnection peerConnection = connectFuture.get(); + final PeerConnection peerConnection = connectFuture.get(); assertThat(peerConnection.getPeerInfo()).isEqualTo(remotePeerInfo); - EnodeURL expectedEnode = + final EnodeURL expectedEnode = EnodeURLImpl.builder() .configureFromEnode(peer.getEnodeURL()) // Discovery information is not available from peer info @@ -199,8 +199,8 @@ public void decode_handlesHello() throws ExecutionException, InterruptedExceptio verify(pipeline, times(1)).addLast(any()); // Next message should be pushed out - PingMessage nextMessage = PingMessage.get(); - ByteBuf nextData = Unpooled.wrappedBuffer(nextMessage.getData().toArray()); + final PingMessage nextMessage = PingMessage.get(); + final ByteBuf nextData = Unpooled.wrappedBuffer(nextMessage.getData().toArray()); when(framer.deframe(eq(nextData))) .thenReturn(new RawMessage(nextMessage.getCode(), nextMessage.getData())) .thenReturn(null); @@ -212,7 +212,7 @@ public void decode_handlesHello() throws ExecutionException, InterruptedExceptio @Test public void decode_handlesHelloFromPeerWithAdvertisedPortOf0() throws ExecutionException, InterruptedException { - ChannelFuture future = NettyMocks.channelFuture(false); + final ChannelFuture future = NettyMocks.channelFuture(false); when(channel.closeFuture()).thenReturn(future); final Peer peer = createRemotePeer(); @@ -220,17 +220,17 @@ public void decode_handlesHelloFromPeerWithAdvertisedPortOf0() new PeerInfo(p2pVersion, clientId, capabilities, 0, peer.getId()); final DeFramer deFramer = createDeFramer(null); - HelloMessage helloMessage = HelloMessage.create(remotePeerInfo); - ByteBuf data = Unpooled.wrappedBuffer(helloMessage.getData().toArray()); + final HelloMessage helloMessage = HelloMessage.create(remotePeerInfo); + final ByteBuf data = Unpooled.wrappedBuffer(helloMessage.getData().toArray()); when(framer.deframe(eq(data))) .thenReturn(new RawMessage(helloMessage.getCode(), helloMessage.getData())) .thenReturn(null); - List out = new ArrayList<>(); + final List out = new ArrayList<>(); deFramer.decode(ctx, data, out); assertThat(connectFuture).isDone(); assertThat(connectFuture).isNotCompletedExceptionally(); - PeerConnection peerConnection = connectFuture.get(); + final PeerConnection peerConnection = connectFuture.get(); assertThat(peerConnection.getPeerInfo()).isEqualTo(remotePeerInfo); assertThat(out).isEmpty(); @@ -249,8 +249,8 @@ public void decode_handlesHelloFromPeerWithAdvertisedPortOf0() verify(pipeline, times(1)).addLast(any()); // Next message should be pushed out - PingMessage nextMessage = PingMessage.get(); - ByteBuf nextData = Unpooled.wrappedBuffer(nextMessage.getData().toArray()); + final PingMessage nextMessage = PingMessage.get(); + final ByteBuf nextData = Unpooled.wrappedBuffer(nextMessage.getData().toArray()); when(framer.deframe(eq(nextData))) .thenReturn(new RawMessage(nextMessage.getCode(), nextMessage.getData())) .thenReturn(null); @@ -261,7 +261,7 @@ public void decode_handlesHelloFromPeerWithAdvertisedPortOf0() @Test public void decode_handlesUnexpectedPeerId() { - ChannelFuture future = NettyMocks.channelFuture(false); + final ChannelFuture future = NettyMocks.channelFuture(false); when(channel.closeFuture()).thenReturn(future); final Peer peer = createRemotePeer(); @@ -275,12 +275,12 @@ public void decode_handlesUnexpectedPeerId() { mismatchedId); final DeFramer deFramer = createDeFramer(peer); - HelloMessage helloMessage = HelloMessage.create(remotePeerInfo); - ByteBuf data = Unpooled.wrappedBuffer(helloMessage.getData().toArray()); + final HelloMessage helloMessage = HelloMessage.create(remotePeerInfo); + final ByteBuf data = Unpooled.wrappedBuffer(helloMessage.getData().toArray()); when(framer.deframe(eq(data))) .thenReturn(new RawMessage(helloMessage.getCode(), helloMessage.getData())) .thenReturn(null); - List out = new ArrayList<>(); + final List out = new ArrayList<>(); deFramer.decode(ctx, data, out); assertThat(connectFuture).isDone(); @@ -297,22 +297,22 @@ public void decode_handlesUnexpectedPeerId() { @Test public void decode_handlesNoSharedCaps() { - ChannelFuture future = NettyMocks.channelFuture(false); + final ChannelFuture future = NettyMocks.channelFuture(false); when(channel.closeFuture()).thenReturn(future); - PeerInfo remotePeerInfo = + final PeerInfo remotePeerInfo = new PeerInfo( p2pVersion, "bla", Arrays.asList(Capability.create("eth", 254)), 30303, Peer.randomId()); - HelloMessage helloMessage = HelloMessage.create(remotePeerInfo); - ByteBuf data = Unpooled.wrappedBuffer(helloMessage.getData().toArray()); + final HelloMessage helloMessage = HelloMessage.create(remotePeerInfo); + final ByteBuf data = Unpooled.wrappedBuffer(helloMessage.getData().toArray()); when(framer.deframe(eq(data))) .thenReturn(new RawMessage(helloMessage.getCode(), helloMessage.getData())) .thenReturn(null); - List out = new ArrayList<>(); + final List out = new ArrayList<>(); deFramer.decode(ctx, data, out); assertThat(connectFuture).isDone(); @@ -326,12 +326,13 @@ public void decode_handlesNoSharedCaps() { @Test public void decode_shouldHandleImmediateDisconnectMessage() { - DisconnectMessage disconnectMessage = DisconnectMessage.create(DisconnectReason.TOO_MANY_PEERS); - ByteBuf disconnectData = Unpooled.wrappedBuffer(disconnectMessage.getData().toArray()); + final DisconnectMessage disconnectMessage = + DisconnectMessage.create(DisconnectReason.TOO_MANY_PEERS); + final ByteBuf disconnectData = Unpooled.wrappedBuffer(disconnectMessage.getData().toArray()); when(framer.deframe(eq(disconnectData))) .thenReturn(new RawMessage(disconnectMessage.getCode(), disconnectMessage.getData())) .thenReturn(null); - List out = new ArrayList<>(); + final List out = new ArrayList<>(); deFramer.decode(ctx, disconnectData, out); assertThat(connectFuture).isDone(); @@ -347,15 +348,15 @@ public void decode_shouldHandleRemoteSocketAddressIsNull() { final Peer peer = createRemotePeer(); final PeerInfo remotePeerInfo = new PeerInfo(p2pVersion, clientId, capabilities, 0, peer.getId()); - HelloMessage helloMessage = HelloMessage.create(remotePeerInfo); - ByteBuf data = Unpooled.wrappedBuffer(helloMessage.getData().toArray()); + final HelloMessage helloMessage = HelloMessage.create(remotePeerInfo); + final ByteBuf data = Unpooled.wrappedBuffer(helloMessage.getData().toArray()); when(framer.deframe(any())) .thenReturn(new RawMessage(helloMessage.getCode(), helloMessage.getData())) .thenReturn(null); when(ctx.channel().remoteAddress()).thenReturn(null); - ChannelFuture future = NettyMocks.channelFuture(true); + final ChannelFuture future = NettyMocks.channelFuture(true); when(ctx.writeAndFlush(any())).thenReturn(future); - List out = new ArrayList<>(); + final List out = new ArrayList<>(); deFramer.decode(ctx, data, out); assertThat(connectFuture).isDone(); @@ -367,22 +368,23 @@ public void decode_shouldHandleRemoteSocketAddressIsNull() { @Test public void decode_shouldHandleInvalidMessage() { - MessageData messageData = PingMessage.get(); - ByteBuf data = Unpooled.wrappedBuffer(messageData.getData().toArray()); + final MessageData messageData = PingMessage.get(); + final ByteBuf data = Unpooled.wrappedBuffer(messageData.getData().toArray()); when(framer.deframe(eq(data))) .thenReturn(new RawMessage(messageData.getCode(), messageData.getData())) .thenReturn(null); - ChannelFuture future = NettyMocks.channelFuture(true); + final ChannelFuture future = NettyMocks.channelFuture(true); when(ctx.writeAndFlush(any())).thenReturn(future); - List out = new ArrayList<>(); + final List out = new ArrayList<>(); deFramer.decode(ctx, data, out); - ArgumentCaptor outboundMessageArgumentCaptor = + final ArgumentCaptor outboundMessageArgumentCaptor = ArgumentCaptor.forClass(OutboundMessage.class); verify(ctx, times(1)).writeAndFlush(outboundMessageArgumentCaptor.capture()); - OutboundMessage outboundMessage = (OutboundMessage) outboundMessageArgumentCaptor.getValue(); + final OutboundMessage outboundMessage = + (OutboundMessage) outboundMessageArgumentCaptor.getValue(); assertThat(outboundMessage.getCapability()).isNull(); - MessageData outboundMessageData = outboundMessage.getData(); + final MessageData outboundMessageData = outboundMessage.getData(); assertThat(outboundMessageData.getCode()).isEqualTo(WireMessageCodes.DISCONNECT); assertThat(DisconnectMessage.readFrom(outboundMessageData).getReason()) .isEqualTo(DisconnectReason.BREACH_OF_PROTOCOL); From b1bff9ce1f4082ac35a6ef54c68943f62ff049d9 Mon Sep 17 00:00:00 2001 From: matkt Date: Wed, 3 Aug 2022 06:44:29 +0200 Subject: [PATCH 062/109] fix enr request order (#4179) * fix enr request * add tests * removed errant debug * adds pr feedback and test to ensure ENR responses never go out to incomplete ping/pong handshakes Signed-off-by: Karim TAAM Co-authored-by: Justin Florentine --- .../internal/PeerDiscoveryController.java | 41 +++++-- .../internal/PeerDiscoveryControllerTest.java | 107 ++++++++++++++++++ 2 files changed, 141 insertions(+), 7 deletions(-) diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryController.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryController.java index e6103d2ba49..556d3ee951a 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryController.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryController.java @@ -111,6 +111,7 @@ public class PeerDiscoveryController { private final PeerTable peerTable; private final Cache bondingPeers = CacheBuilder.newBuilder().maximumSize(50).expireAfterWrite(10, TimeUnit.MINUTES).build(); + private final Cache cachedEnrRequests; private final Collection bootstrapNodes; @@ -159,7 +160,8 @@ private PeerDiscoveryController( final PeerRequirement peerRequirement, final PeerPermissions peerPermissions, final Subscribers peerBondedObservers, - final MetricsSystem metricsSystem) { + final MetricsSystem metricsSystem, + final Optional> maybeCacheForEnrRequests) { this.timerUtil = timerUtil; this.nodeKey = nodeKey; this.localPeer = localPeer; @@ -194,6 +196,9 @@ private PeerDiscoveryController( "discovery_interaction_retry_count", "Total number of interaction retries performed", "type"); + this.cachedEnrRequests = + maybeCacheForEnrRequests.orElse( + CacheBuilder.newBuilder().maximumSize(50).expireAfterWrite(10, SECONDS).build()); } public static Builder builder() { @@ -317,6 +322,8 @@ public void onMessage(final Packet packet, final DiscoveryPeer sender) { bondingPeers.invalidate(peer.getId()); addBondedPeerToPeerTable(peer); recursivePeerRefreshState.onBondingComplete(peer); + Optional.ofNullable(cachedEnrRequests.getIfPresent(peer.getId())) + .ifPresent(cachedEnrRequest -> processEnrRequest(peer, cachedEnrRequest)); }); break; case NEIGHBORS: @@ -337,12 +344,15 @@ public void onMessage(final Packet packet, final DiscoveryPeer sender) { break; case ENR_REQUEST: if (PeerDiscoveryStatus.BONDED.equals(peer.getStatus())) { - LOG.trace("ENR_REQUEST received from bonded peer Id: {}", peer.getId()); - packet - .getPacketData(ENRRequestPacketData.class) - .ifPresent(p -> respondToENRRequest(p, packet.getHash(), peer)); + processEnrRequest(peer, packet); + } else if (PeerDiscoveryStatus.BONDING.equals(peer.getStatus())) { + LOG.trace("ENR_REQUEST cached for bonding peer Id: {}", peer.getId()); + // Due to UDP, it may happen that we receive the ENR_REQUEST just before the PONG. + // Because peers want to send the ENR_REQUEST directly after the pong. + // If this happens we don't want to ignore the request but process when bonded. + // this cache allows to keep the request and to respond after having processed the PONG + cachedEnrRequests.put(peer.getId(), packet); } - break; case ENR_RESPONSE: // Currently there is no use case where an ENRResponse will be sent otherwise @@ -356,6 +366,13 @@ public void onMessage(final Packet packet, final DiscoveryPeer sender) { } } + private void processEnrRequest(final DiscoveryPeer peer, final Packet packet) { + LOG.trace("ENR_REQUEST received from bonded peer Id: {}", peer.getId()); + packet + .getPacketData(ENRRequestPacketData.class) + .ifPresent(p -> respondToENRRequest(p, packet.getHash(), peer)); + } + private List getPeersFromNeighborsPacket(final Packet packet) { final Optional maybeNeighborsData = packet.getPacketData(NeighborsPacketData.class); @@ -748,6 +765,9 @@ public static class Builder { private AsyncExecutor workerExecutor; private MetricsSystem metricsSystem; + private Cache cachedEnrRequests = + CacheBuilder.newBuilder().maximumSize(50).expireAfterWrite(10, SECONDS).build(); + private Builder() {} public PeerDiscoveryController build() { @@ -770,7 +790,8 @@ public PeerDiscoveryController build() { peerRequirement, peerPermissions, peerBondedObservers, - metricsSystem); + metricsSystem, + Optional.of(cachedEnrRequests)); } private void validate() { @@ -862,5 +883,11 @@ public Builder metricsSystem(final MetricsSystem metricsSystem) { this.metricsSystem = metricsSystem; return this; } + + public Builder cacheForEnrRequests(final Cache cacheToUse) { + checkNotNull(cacheToUse); + this.cachedEnrRequests = cacheToUse; + return this; + } } } diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryControllerTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryControllerTest.java index 5a9377bf5c5..31a496d1cf5 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryControllerTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryControllerTest.java @@ -57,6 +57,9 @@ import java.util.function.Consumer; import java.util.stream.Collectors; +import com.google.common.base.Ticker; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.MutableBytes; @@ -1371,6 +1374,101 @@ public void shouldNotRespondToENRRequestForNonBondedPeer() { .send(eq(peers.get(0)), matchPacketOfType(PacketType.ENR_REQUEST)); } + @Test + public void shouldRespondToRecentENRRequestAfterBonding() { + final List nodeKeys = PeerDiscoveryTestHelper.generateNodeKeys(1); + final List peers = helper.createDiscoveryPeers(nodeKeys); + final OutboundMessageHandler outboundMessageHandler = mock(OutboundMessageHandler.class); + controller = + getControllerBuilder() + .peers(peers.get(0)) + .outboundMessageHandler(outboundMessageHandler) + .build(); + + // Mock the creation of the PING packet, so that we can control the hash, which gets validated + // when receiving the PONG. + final PingPacketData mockPing = + PingPacketData.create( + Optional.ofNullable(localPeer.getEndpoint()), peers.get(0).getEndpoint(), UInt64.ONE); + final Packet mockPacket = Packet.create(PacketType.PING, mockPing, nodeKeys.get(0)); + mockPingPacketCreation(mockPacket); + + controller.start(); + + final PongPacketData pongRequestPacketData = + PongPacketData.create(localPeer.getEndpoint(), mockPacket.getHash(), UInt64.ONE); + + final ENRRequestPacketData enrRequestPacketData = ENRRequestPacketData.create(); + + final Packet enrPacket = + Packet.create(PacketType.ENR_REQUEST, enrRequestPacketData, nodeKeys.get(0)); + final Packet pongPacket = + Packet.create(PacketType.PONG, pongRequestPacketData, nodeKeys.get(0)); + + controller.onMessage(enrPacket, peers.get(0)); + verify(outboundMessageHandler, never()).send(any(), matchPacketOfType(PacketType.ENR_RESPONSE)); + controller.onMessage(pongPacket, peers.get(0)); + + verify(outboundMessageHandler, times(1)) + .send(any(), matchPacketOfType(PacketType.ENR_RESPONSE)); + } + + @Test + public void shouldNotRespondENRPriorToPong() { + final List nodeKeys = PeerDiscoveryTestHelper.generateNodeKeys(1); + final List peers = helper.createDiscoveryPeers(nodeKeys); + final OutboundMessageHandler outboundMessageHandler = mock(OutboundMessageHandler.class); + final Cache enrs = + CacheBuilder.newBuilder() + .maximumSize(50) + .expireAfterWrite(1, TimeUnit.NANOSECONDS) + .ticker( + new Ticker() { + int tickCount = 1; + + @Override + public long read() { + return tickCount += 10; + } + }) + .build(); + controller = + getControllerBuilder() + .peers(peers.get(0)) + .outboundMessageHandler(outboundMessageHandler) + .enrCache(enrs) + .build(); + + // Mock the creation of the PING packet, so that we can control the hash, which gets validated + // when receiving the PONG. + final PingPacketData mockPing = + PingPacketData.create( + Optional.ofNullable(localPeer.getEndpoint()), peers.get(0).getEndpoint(), UInt64.ONE); + final Packet mockPacket = Packet.create(PacketType.PING, mockPing, nodeKeys.get(0)); + mockPingPacketCreation(mockPacket); + + controller.start(); + + final PongPacketData pongRequestPacketData = + PongPacketData.create(localPeer.getEndpoint(), mockPacket.getHash(), UInt64.ONE); + + final ENRRequestPacketData enrRequestPacketData = ENRRequestPacketData.create(); + + final Packet enrPacket = + Packet.create(PacketType.ENR_REQUEST, enrRequestPacketData, nodeKeys.get(0)); + final Packet pongPacket = + Packet.create(PacketType.PONG, pongRequestPacketData, nodeKeys.get(0)); + + controller.onMessage(enrPacket, peers.get(0)); + enrs.cleanUp(); + controller.onMessage(pongPacket, peers.get(0)); + + verify(outboundMessageHandler, never()) + .send( + argThat((DiscoveryPeer peer) -> peer.equals(peers.get(0))), + matchPacketOfType(PacketType.ENR_RESPONSE)); + } + private static Packet mockPingPacket(final DiscoveryPeer from, final DiscoveryPeer to) { final Packet packet = mock(Packet.class); @@ -1441,10 +1539,18 @@ static class ControllerBuilder { private final Subscribers peerBondedObservers = Subscribers.create(); private PeerPermissions peerPermissions = PeerPermissions.noop(); + private Cache enrs = + CacheBuilder.newBuilder().maximumSize(50).expireAfterWrite(10, TimeUnit.SECONDS).build(); + public static ControllerBuilder create() { return new ControllerBuilder(); } + ControllerBuilder enrCache(final Cache cacheToUse) { + this.enrs = cacheToUse; + return this; + } + ControllerBuilder peers(final Collection discoPeers) { this.discoPeers = discoPeers; return this; @@ -1507,6 +1613,7 @@ PeerDiscoveryController build() { .peerPermissions(peerPermissions) .peerBondedObservers(peerBondedObservers) .metricsSystem(new NoOpMetricsSystem()) + .cacheForEnrRequests(enrs) .build()); } } From 721638dc045694f822838df020bad98c8345499b Mon Sep 17 00:00:00 2001 From: garyschulte Date: Wed, 3 Aug 2022 08:34:50 -0700 Subject: [PATCH 063/109] revert for now (#4210) Signed-off-by: garyschulte --- .../CalculatedDifficultyValidationRule.java | 5 ++++- .../headervalidationrules/ProofOfWorkValidationRule.java | 7 +++++++ .../TimestampMoreRecentThanParent.java | 4 ++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/CalculatedDifficultyValidationRule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/CalculatedDifficultyValidationRule.java index bcc4e213586..2bffde67cc5 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/CalculatedDifficultyValidationRule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/CalculatedDifficultyValidationRule.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.ethereum.mainnet.headervalidationrules; +import org.hyperledger.besu.config.MergeConfigOptions; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.mainnet.AttachedBlockHeaderValidationRule; @@ -36,7 +37,9 @@ public CalculatedDifficultyValidationRule(final DifficultyCalculator difficultyC @Override public boolean validate( final BlockHeader header, final BlockHeader parent, final ProtocolContext context) { - + if (MergeConfigOptions.isMergeEnabled()) { + return true; + } final BigInteger actualDifficulty = new BigInteger(1, header.getDifficulty().toArray()); final BigInteger expectedDifficulty = difficultyCalculator.nextDifficulty(header.getTimestamp(), parent, context); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ProofOfWorkValidationRule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ProofOfWorkValidationRule.java index 6f1612f1c89..2c98f311b24 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ProofOfWorkValidationRule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ProofOfWorkValidationRule.java @@ -16,6 +16,7 @@ import static java.lang.Boolean.FALSE; +import org.hyperledger.besu.config.MergeConfigOptions; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.mainnet.DetachedBlockHeaderValidationRule; @@ -69,6 +70,12 @@ public boolean validate(final BlockHeader header, final BlockHeader parent) { return false; } + // TODO: remove this rule bypass, use post-merge headervalidation rules + // https://github.com/hyperledger/besu/issues/2898 + if (MergeConfigOptions.isMergeEnabled()) { + return true; + } + final Hash headerHash = hashHeader(header); PoWSolution solution = hasher.hash(header.getNonce(), header.getNumber(), epochCalculator, headerHash); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/TimestampMoreRecentThanParent.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/TimestampMoreRecentThanParent.java index 6aa7e5479ef..2af6d23d87b 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/TimestampMoreRecentThanParent.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/TimestampMoreRecentThanParent.java @@ -16,6 +16,7 @@ import static com.google.common.base.Preconditions.checkArgument; +import org.hyperledger.besu.config.MergeConfigOptions; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.mainnet.DetachedBlockHeaderValidationRule; @@ -35,6 +36,9 @@ public TimestampMoreRecentThanParent(final long minimumSecondsSinceParent) { @Override public boolean validate(final BlockHeader header, final BlockHeader parent) { + if (MergeConfigOptions.isMergeEnabled()) { + return true; + } return validateTimestamp(header.getTimestamp(), parent.getTimestamp()); } From 6eaa5b52d7a79c8a2e35d72ccdcb4be94512c041 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 3 Aug 2022 10:31:28 -0600 Subject: [PATCH 064/109] Release 22.7.0 (#4213) Release Besu 22.7.0 Signed-off-by: Danno Ferrin --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index db6c312064f..3332e11b7c4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ -version=22.7.0-SNAPSHOT +version=22.7.0 org.gradle.welcome=never From e87482ab6f0b4eae28f96ba11c69380dc0eb88f1 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 3 Aug 2022 11:27:35 -0600 Subject: [PATCH 065/109] update for next release (#4214) Ser versions for next release - 22.7.1-SNAPSHOT Signed-off-by: Danno Ferrin --- CHANGELOG.md | 10 ++++++++++ gradle.properties | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c165eae6b8b..bbfe8a1b5d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 22.7.1 + +### Additions and Improvements + +### Bug Fixes + ## 22.7.0 ### Additions and Improvements @@ -12,6 +18,10 @@ - Upgrade Spotless to 6.8.0 [#4195](https://github.com/hyperledger/besu/pull/4195) - Upgrade Gradle to 7.5 [#4196](https://github.com/hyperledger/besu/pull/4196) +### Download links +- https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/22.7.0/besu-22.7.0.tar.gz / sha256: `af21104a880c37706b660aa816e1c38b2b3f603a97420ddcbc889324b71aa50e` +- https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/22.7.0/besu-22.7.0.zip / sha256: `5b1586362e6e739c206c25224bb753a372bad70c0b22dbe091f9253024ebdc45` + ## 22.7.0-RC3 ### Known/Outstanding issues: diff --git a/gradle.properties b/gradle.properties index 3332e11b7c4..cd43a4336ac 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ -version=22.7.0 +version=22.7.1-SNAPSHOT org.gradle.welcome=never From 49244791f07aebd09bc98132c15bc343e7a3ddcd Mon Sep 17 00:00:00 2001 From: ahamlat Date: Wed, 3 Aug 2022 21:37:18 +0200 Subject: [PATCH 066/109] Apply RocksDB LZ4 compression and compare the performance/resource metrics after sync. (#4166) Signed-off-by: Ameziane H Co-authored-by: Fabio Di Fabio --- .../rocksdb/segmented/RocksDBColumnarKeyValueStorage.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java index f8d7852dcdb..b3f35098c4c 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java @@ -47,6 +47,7 @@ import org.rocksdb.ColumnFamilyDescriptor; import org.rocksdb.ColumnFamilyHandle; import org.rocksdb.ColumnFamilyOptions; +import org.rocksdb.CompressionType; import org.rocksdb.DBOptions; import org.rocksdb.Env; import org.rocksdb.LRUCache; @@ -98,6 +99,7 @@ public RocksDBColumnarKeyValueStorage( segment.getId(), new ColumnFamilyOptions() .setTtl(0) + .setCompressionType(CompressionType.LZ4_COMPRESSION) .setTableFormatConfig(createBlockBasedTableConfig(configuration)))) .collect(Collectors.toList()); columnDescriptors.add( @@ -105,6 +107,7 @@ public RocksDBColumnarKeyValueStorage( DEFAULT_COLUMN.getBytes(StandardCharsets.UTF_8), columnFamilyOptions .setTtl(0) + .setCompressionType(CompressionType.LZ4_COMPRESSION) .setTableFormatConfig(createBlockBasedTableConfig(configuration)))); final Statistics stats = new Statistics(); From ebdb19a958cfd5f47d2c583e356904457023c9f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diego=20L=C3=B3pez=20Le=C3=B3n?= Date: Wed, 3 Aug 2022 23:58:12 -0300 Subject: [PATCH 067/109] Increase Gradle max heap size (#4207) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Diego López León Co-authored-by: Sally MacFarlane --- gradle.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/gradle.properties b/gradle.properties index cd43a4336ac..538911ba47a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,4 @@ version=22.7.1-SNAPSHOT org.gradle.welcome=never +org.gradle.jvmargs=-Xmx1g \ No newline at end of file From 80ab6489279fde7d61d896e2030bb578362d1fcf Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Thu, 4 Aug 2022 13:35:53 +1000 Subject: [PATCH 068/109] typo (#4217) Signed-off-by: Sally MacFarlane --- .../java/org/hyperledger/besu/ethereum/eth/manager/EthPeer.java | 2 +- .../hyperledger/besu/ethereum/eth/manager/PeerReputation.java | 2 +- .../besu/ethereum/eth/manager/PeerReputationTest.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeer.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeer.java index ff7c992d713..a8a2a302e10 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeer.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeer.java @@ -215,7 +215,7 @@ public void recordUselessResponse(final String requestType) { } public void recordUsefulResponse() { - reputation.recordUsefulResposne(); + reputation.recordUsefulResponse(); } public void disconnect(final DisconnectReason reason) { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputation.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputation.java index aa1c37f3218..d0010b0fcf3 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputation.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputation.java @@ -85,7 +85,7 @@ public Optional recordUselessResponse(final long timestamp) { } } - public void recordUsefulResposne() { + public void recordUsefulResponse() { score += SMALL_ADJUSTMENT; } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputationTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputationTest.java index e8a8c6d9a7d..5d7cb5962fc 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputationTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputationTest.java @@ -83,7 +83,7 @@ public void shouldDiscardEmptyResponseRecordsAfterTimeWindowElapses() { @Test public void shouldIncreaseScore() { - reputation.recordUsefulResposne(); + reputation.recordUsefulResponse(); assertThat(reputation.compareTo(new PeerReputation())).isGreaterThan(0); } } From 98dc2ace3756c10de857c2f8c47d694822a0e41e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diego=20L=C3=B3pez=20Le=C3=B3n?= Date: Thu, 4 Aug 2022 11:59:02 -0300 Subject: [PATCH 069/109] Upgrade Web3J (#3752) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Upgrade web3j dependencies to latest versions Signed-off-by: Diego López León Signed-off-by: Antony Denyer Co-authored-by: Antony Denyer Co-authored-by: Miguel Rojo Co-authored-by: Miguel Angel Rojo --- .../besu/tests/acceptance/dsl/BlockUtils.java | 4 +++- acceptance-tests/tests/build.gradle | 14 ++++++++++---- besu/build.gradle | 6 ------ .../besu/tests/container/ContainerTests.java | 10 +++++----- ethereum/p2p/build.gradle | 6 ------ gradle/check-licenses.gradle | 1 - gradle/versions.gradle | 12 +++++++----- 7 files changed, 25 insertions(+), 28 deletions(-) diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/BlockUtils.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/BlockUtils.java index f0b89f9c594..a02651a98fe 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/BlockUtils.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/BlockUtils.java @@ -23,6 +23,8 @@ import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.evm.log.LogsBloomFilter; +import java.math.BigInteger; + import org.apache.tuweni.bytes.Bytes; import org.web3j.protocol.core.methods.response.EthBlock.Block; @@ -50,7 +52,7 @@ public static BlockHeader createBlockHeader( Bytes.fromHexString(block.getExtraData()), null, mixHash, - block.getNonce().longValue(), + new BigInteger(block.getNonceRaw().substring(2), 16).longValue(), blockHeaderFunctions); } } diff --git a/acceptance-tests/tests/build.gradle b/acceptance-tests/tests/build.gradle index 8c9657b4d67..8b891615dc9 100644 --- a/acceptance-tests/tests/build.gradle +++ b/acceptance-tests/tests/build.gradle @@ -12,10 +12,19 @@ */ plugins { - id 'org.web3j' version '4.8.9' + id 'org.web3j' version '4.9.2' id 'org.web3j.solidity' version '0.3.5' } +configurations.all { + resolutionStrategy.eachDependency { DependencyResolveDetails details -> + if (details.requested.group == 'org.web3j' && details.requested.version == '4.9.2') { + details.useVersion '4.9.4' + details.because 'Plugin version is 4.9.2 (latest), but we want it to use web3j libs version 4.9.4' + } + } +} + web3j { generatedPackageName = 'org.hyperledger.besu.tests.web3j.generated' } sourceSets.main.solidity.srcDirs = ["$projectDir/contracts"] @@ -72,9 +81,6 @@ dependencies { testImplementation 'org.web3j:abi' testImplementation 'org.web3j:besu' testImplementation 'org.web3j:core' - constraints { - implementation('jnr-posix:3.1.15') { because '3.0.47 from web3j has issues' } - } testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' } diff --git a/besu/build.gradle b/besu/build.gradle index ffb34ad77d3..2dcaf2312fe 100644 --- a/besu/build.gradle +++ b/besu/build.gradle @@ -98,12 +98,6 @@ dependencies { testImplementation 'org.mockito:mockito-core' testImplementation 'org.testcontainers:testcontainers' testImplementation 'tech.pegasys.discovery:discovery' - constraints { - implementation('com.github.jnr:jnr-posix') { - version { require '3.1.15' } - because '3.0.47 from web3j has issues' - } - } testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' } diff --git a/container-tests/tests/src/test/java/org/hyperledger/besu/tests/container/ContainerTests.java b/container-tests/tests/src/test/java/org/hyperledger/besu/tests/container/ContainerTests.java index 717025b093c..b2476dc517c 100644 --- a/container-tests/tests/src/test/java/org/hyperledger/besu/tests/container/ContainerTests.java +++ b/container-tests/tests/src/test/java/org/hyperledger/besu/tests/container/ContainerTests.java @@ -91,10 +91,10 @@ public void contractShouldBeDeployedToBothNodes() throws IOException, Transactio final QuorumTransactionManager qtm = new QuorumTransactionManager( goQuorumWeb3j, + goQuorumEnclave, credentials, goQuorumTesseraPubKey, - Arrays.asList(goQuorumTesseraPubKey, besuTesseraPubKey), - goQuorumEnclave); + Arrays.asList(goQuorumTesseraPubKey, besuTesseraPubKey)); // Get the deployed contract address final String contractAddress = @@ -156,10 +156,10 @@ public void contractShouldBeDeployedOnlyToGoQuorumNode() final QuorumTransactionManager qtm = new QuorumTransactionManager( goQuorumWeb3j, + goQuorumEnclave, credentials, goQuorumTesseraPubKey, - List.of(goQuorumTesseraPubKey), - goQuorumEnclave); + List.of(goQuorumTesseraPubKey)); // Get the deployed contract address final String contractAddress = @@ -207,7 +207,7 @@ public void contractShouldBeDeployedOnlyToBesuNode() // create a GoQuorum transaction manager final QuorumTransactionManager qtm = new QuorumTransactionManager( - besuWeb3j, credentials, besuTesseraPubKey, List.of(besuTesseraPubKey), besuEnclave); + besuWeb3j, besuEnclave, credentials, besuTesseraPubKey, List.of(besuTesseraPubKey)); // Get the deployed contract address final String contractAddress = diff --git a/ethereum/p2p/build.gradle b/ethereum/p2p/build.gradle index 3b239c9cd11..9ecdafabd8e 100644 --- a/ethereum/p2p/build.gradle +++ b/ethereum/p2p/build.gradle @@ -62,12 +62,6 @@ dependencies { annotationProcessor "org.immutables:value" implementation "org.immutables:value-annotations" implementation 'tech.pegasys.discovery:discovery' - constraints { - implementation('com.github.jnr:jnr-posix') { - version { require '3.1.15' } - because '3.0.47 from web3j has issues' - } - } // test dependencies. testImplementation project(path: ':ethereum:core', configuration: 'testArtifacts') diff --git a/gradle/check-licenses.gradle b/gradle/check-licenses.gradle index 4ba187a401e..c8fdbf6001e 100644 --- a/gradle/check-licenses.gradle +++ b/gradle/check-licenses.gradle @@ -167,7 +167,6 @@ downloadLicenses { (group('javax.persistence')) : epl1, // jnr-posix is released under a tri EPL v2.0/GPL/LGPL license - 'com.github.jnr:jnr-posix:3.0.47' : epl2, 'com.github.jnr:jnr-posix:3.1.15' : epl2, // io.netty:netty-tcnative-boringssl-static license markings are not machine readable. diff --git a/gradle/versions.gradle b/gradle/versions.gradle index cd89dfb1c26..5232957ab25 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -187,11 +187,13 @@ dependencyManagement { dependency 'org.testcontainers:testcontainers:1.17.2' - dependency 'org.web3j:abi:4.8.9' - dependency 'org.web3j:besu:4.8.9' - dependency 'org.web3j:core:4.8.9' - dependency 'org.web3j:crypto:4.8.9' - dependency 'org.web3j:quorum:4.8.4' + dependency 'org.web3j:quorum:4.9.0' + dependencySet(group: 'org.web3j', version: '4.9.4') { + entry 'abi' + entry 'besu' + entry 'core' + entry 'crypto' + } dependency 'org.xerial.snappy:snappy-java:1.1.8.4' From 8f895805425b93b159da6b886f0a63480baa2f9c Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Fri, 5 Aug 2022 09:45:52 +1000 Subject: [PATCH 070/109] Fix ConcurrentModificationException on ReattemptPendingPeerRequests (#4206) * Handle ConcurrentModificationException on ReattemptPendingPeerRequests * Replace removeIf with Iterator Signed-off-by: Gabriel Trintinalia Co-authored-by: mark-terry <36909937+mark-terry@users.noreply.github.com> Co-authored-by: Sally MacFarlane --- .../besu/ethereum/eth/manager/EthPeers.java | 12 +++- .../ethereum/eth/manager/EthPeersTest.java | 72 +++++++++++++++++++ 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java index 14ebf587c5c..b45ab54a17d 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java @@ -36,6 +36,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import com.google.common.annotations.VisibleForTesting; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -164,9 +165,16 @@ public void dispatchMessage(final EthPeer peer, final EthMessage ethMessage) { dispatchMessage(peer, ethMessage, protocolName); } - private void reattemptPendingPeerRequests() { + @VisibleForTesting + void reattemptPendingPeerRequests() { synchronized (this) { - pendingRequests.removeIf(PendingPeerRequest::attemptExecution); + final Iterator iterator = pendingRequests.iterator(); + while (iterator.hasNext()) { + final PendingPeerRequest request = iterator.next(); + if (request.attemptExecution()) { + pendingRequests.remove(request); + } + } } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeersTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeersTest.java index 4ae23a01169..a3476f46900 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeersTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeersTest.java @@ -20,6 +20,7 @@ import static org.assertj.core.api.Assertions.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; @@ -40,6 +41,7 @@ import org.junit.Before; import org.junit.Test; +import org.mockito.stubbing.Answer; public class EthPeersTest { @@ -265,6 +267,76 @@ public void shouldFailRequestWithBusyDisconnectedAssignedPeer() throws Exception assertRequestFailure(pendingRequest, CancellationException.class); } + @Test + public void shouldNotFailWhenAttemptExecutionDisconnectSamePeer() throws PeerNotConnected { + final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 1000); + final EthPeer ethPeer = spy(peer.getEthPeer()); + + // Force request to be added to pending request list + when(ethPeer.hasAvailableRequestCapacity()).thenReturn(false); + + final PendingPeerRequest pendingPeerRequest = + ethPeers.executePeerRequest(peerRequest, 10, Optional.of(ethPeer)); + + // Force Request Attempt to cause the peer to disconnect + when(ethPeer.hasAvailableRequestCapacity()) + .thenAnswer( + (Answer) + invocation -> { + // Force Disconnect only on the first execution + if (!peer.getPeerConnection().isDisconnected()) { + peer.disconnect(DisconnectReason.UNKNOWN); // Force Peer to disconnect + } + return true; + }); + + // Sent Pending Requests + ethPeers.reattemptPendingPeerRequests(); + + // Request should be aborted. + assertRequestFailure(pendingPeerRequest, CancellationException.class); + + // Mock works + assertThat(peer.getEthPeer().isDisconnected()).isTrue(); // peer is disconnected + } + + @Test + public void shouldNotFailWhenAttemptExecutionDisconnectAnotherPeer() throws PeerNotConnected { + final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 1000); + final EthPeer ethPeer = spy(peer.getEthPeer()); + + // Force request to be added to pending request list + when(ethPeer.hasAvailableRequestCapacity()).thenReturn(false); + + final PendingPeerRequest pendingPeerRequest = + ethPeers.executePeerRequest(peerRequest, 10, Optional.of(ethPeer)); + + final RespondingEthPeer peerToDisconnect = + EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 1000); + + // Force Request Attempt to cause the peer to disconnect + when(ethPeer.hasAvailableRequestCapacity()) + .thenAnswer( + (Answer) + invocation -> { + // Force Disconnect only on the first execution + if (!peerToDisconnect.getPeerConnection().isDisconnected()) { + peerToDisconnect.disconnect( + DisconnectReason.UNKNOWN); // Force Peer to disconnect + } + return true; + }); + + // Sent Pending Requests + ethPeers.reattemptPendingPeerRequests(); + + // Request Should Execute + assertRequestSuccessful(pendingPeerRequest); + + // Mock works + assertThat(peerToDisconnect.getEthPeer().isDisconnected()).isTrue(); // peer is disconnected + } + @Test public void toString_hasExpectedInfo() { assertThat(ethPeers.toString()).isEqualTo("0 EthPeers {}"); From b02ae7037eef4f74c0c12dd7266f973e68d93556 Mon Sep 17 00:00:00 2001 From: Simon Dudley Date: Sat, 6 Aug 2022 00:53:33 +0100 Subject: [PATCH 071/109] Log unexpected exceptions in execution engine rpc (#4222) Signed-off-by: Simon Dudley --- .../jsonrpc/internal/methods/ExecutionEngineJsonRpcMethod.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecutionEngineJsonRpcMethod.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecutionEngineJsonRpcMethod.java index 8f6ad7bcb60..b1d05876d87 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecutionEngineJsonRpcMethod.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/ExecutionEngineJsonRpcMethod.java @@ -82,8 +82,10 @@ public final JsonRpcResponse response(final JsonRpcRequestContext request) { try { return cf.get(); } catch (InterruptedException e) { + LOG.error("Failed to get execution engine response", e); return new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.TIMEOUT_ERROR); } catch (ExecutionException e) { + LOG.error("Failed to get execution engine response", e); return new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INTERNAL_ERROR); } } From ca9a07691a5426c7f02f29b36e6cd757dc17c284 Mon Sep 17 00:00:00 2001 From: Daniel Lehrner Date: Mon, 8 Aug 2022 01:17:58 +0200 Subject: [PATCH 072/109] correct fallback ttd to correct value (#4223) * correct fallback ttd to correct value Signed-off-by: Daniel Lehrner Co-authored-by: Sally MacFarlane --- CHANGELOG.md | 2 ++ .../engine/EngineExchangeTransitionConfiguration.java | 5 +++-- .../EngineExchangeTransitionConfigurationTest.java | 10 ++++++++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bbfe8a1b5d1..e55536c6bde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ ### Additions and Improvements ### Bug Fixes +- Fixes off-by-one error for mainnet TTD fallback [#4223](https://github.com/hyperledger/besu/pull/4223) + ## 22.7.0 diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfiguration.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfiguration.java index e4db64e5226..90be85e4654 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfiguration.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfiguration.java @@ -34,7 +34,6 @@ import io.vertx.core.Vertx; import io.vertx.core.json.Json; -import org.apache.tuweni.units.bigints.UInt256; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,7 +43,9 @@ public class EngineExchangeTransitionConfiguration extends ExecutionEngineJsonRp // use (2^256 - 2^10) if engine is enabled in the absence of a TTD configuration static final Difficulty FALLBACK_TTD_DEFAULT = - Difficulty.MAX_VALUE.subtract(UInt256.valueOf(1024L)); + Difficulty.fromHexString( + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00"); + static final long QOS_TIMEOUT_MILLIS = 120000L; private final QosTimer qosTimer; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java index bc60a44d2be..09b39d08187 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java @@ -15,7 +15,6 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; import static org.assertj.core.api.Assertions.assertThat; -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineExchangeTransitionConfiguration.FALLBACK_TTD_DEFAULT; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -44,6 +43,7 @@ import org.hyperledger.besu.ethereum.core.ParsedExtraData; import org.hyperledger.besu.evm.log.LogsBloomFilter; +import java.math.BigInteger; import java.util.Map; import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; @@ -56,6 +56,7 @@ import io.vertx.ext.unit.junit.VertxUnitRunner; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; +import org.apache.tuweni.units.bigints.UInt256; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -126,7 +127,12 @@ public void shouldReturnDefaultOnNoTerminalTotalDifficultyConfigured() { "0", Hash.ZERO.toHexString(), new UnsignedLongParameter(0L))); var result = fromSuccessResp(response); - assertThat(result.getTerminalTotalDifficulty()).isEqualTo(FALLBACK_TTD_DEFAULT); + assertThat(result.getTerminalTotalDifficulty()) + .isEqualTo( + UInt256.valueOf( + new BigInteger( + "115792089237316195423570985008687907853269984665640564039457584007913129638912", + 10))); assertThat(result.getTerminalBlockHash()).isEqualTo(Hash.ZERO); assertThat(result.getTerminalBlockNumber()).isEqualTo(0L); } From 95d9626b0e969b2fba626e9db1938455976bb0e8 Mon Sep 17 00:00:00 2001 From: Miguel Angel Rojo Date: Mon, 8 Aug 2022 11:49:58 +0100 Subject: [PATCH 073/109] Enclave public key length constraint removed for private transactions (#4086) * removed constraint with the length of the privacy public key * refactor to include tessera ec encryptor * added EC snippet to the tessera json config, still need to replace base64string from web3j * acceptance tests working after modifying the web3j library to allow secp256r1 keys * using NACL encryptor by default * using web3j v4.9.4 and web3j-quorum v4.9.0 Signed-off-by: Miguel Rojo Co-authored-by: Antony Denyer --- .../privacy/PrivacyNodeFactory.java | 50 +++----- .../privacy/ParameterizedEnclaveTestBase.java | 16 ++- .../privacy/PrivacyAcceptanceTestBase.java | 3 - .../dsl/privacy/account/PrivacyAccount.java | 27 ++++- .../account/PrivacyAccountResolver.java | 113 +++++++++++------- .../BftPrivacyClusterAcceptanceTest.java | 54 +++++++-- ...loyPrivateSmartContractAcceptanceTest.java | 15 ++- .../privacy/EnclaveErrorAcceptanceTest.java | 45 +++++-- .../FlexiblePrivacyAcceptanceTest.java | 8 +- .../PluginPrivacySigningAcceptanceTest.java | 34 +++++- .../privacy/PrivCallAcceptanceTest.java | 10 +- ...tStateRootFlexibleGroupAcceptanceTest.java | 5 +- ...tStateRootOffchainGroupAcceptanceTest.java | 12 +- .../privacy/PrivGetCodeAcceptanceTest.java | 10 +- .../privacy/PrivGetLogsAcceptanceTest.java | 10 +- ...ivGetPrivateTransactionAcceptanceTest.java | 13 +- .../privacy/PrivacyClusterAcceptanceTest.java | 81 ++++++++++--- .../privacy/PrivacyGroupAcceptanceTest.java | 26 ++-- .../privacy/PrivacyReceiptAcceptanceTest.java | 10 +- ...vateContractPublicStateAcceptanceTest.java | 13 +- .../privacy/PrivateGenesisAcceptanceTest.java | 10 +- .../PrivateLogFilterAcceptanceTest.java | 10 +- .../FlexibleMultiTenancyAcceptanceTest.java | 7 +- .../org/hyperledger/besu/cli/BesuCommand.java | 4 - .../hyperledger/besu/cli/BesuCommandTest.java | 3 +- .../org/hyperledger/besu/enclave/Enclave.java | 4 +- .../besu/ethereum/core/PrivacyParameters.java | 12 +- .../testutil/EnclaveConfiguration.java | 7 ++ .../testutil/EnclaveEncryptorType.java | 44 +++++++ .../testutil/EnclaveKeyConfiguration.java | 15 ++- .../enclave/testutil/TesseraTestHarness.java | 6 +- .../testutil/TesseraTestHarnessFactory.java | 9 +- .../src/main/resources/enclave_ec_key_0.key | 1 + .../src/main/resources/enclave_ec_key_0.pub | 1 + .../src/main/resources/enclave_ec_key_1.key | 1 + .../src/main/resources/enclave_ec_key_1.pub | 1 + .../src/main/resources/enclave_ec_key_2.key | 1 + .../src/main/resources/enclave_ec_key_2.pub | 1 + 38 files changed, 493 insertions(+), 199 deletions(-) create mode 100644 testutil/src/main/java/org/hyperledger/enclave/testutil/EnclaveEncryptorType.java create mode 100644 testutil/src/main/resources/enclave_ec_key_0.key create mode 100644 testutil/src/main/resources/enclave_ec_key_0.pub create mode 100644 testutil/src/main/resources/enclave_ec_key_1.key create mode 100644 testutil/src/main/resources/enclave_ec_key_1.pub create mode 100644 testutil/src/main/resources/enclave_ec_key_2.key create mode 100644 testutil/src/main/resources/enclave_ec_key_2.pub diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/privacy/PrivacyNodeFactory.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/privacy/PrivacyNodeFactory.java index 57455e4614a..0d96b6c3f2b 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/privacy/PrivacyNodeFactory.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/privacy/PrivacyNodeFactory.java @@ -48,16 +48,6 @@ public PrivacyNode create( return new PrivacyNode(privacyNodeConfig, vertx, enclaveType, containerNetwork); } - public PrivacyNode createPrivateTransactionEnabledMinerNode( - final String name, - final PrivacyAccount privacyAccount, - final EnclaveType enclaveType, - final Optional containerNetwork) - throws IOException { - return createPrivateTransactionEnabledMinerNode( - name, privacyAccount, enclaveType, containerNetwork, false, false, false); - } - public PrivacyNode createPrivateTransactionEnabledMinerNode( final String name, final PrivacyAccount privacyAccount, @@ -83,21 +73,13 @@ public PrivacyNode createPrivateTransactionEnabledMinerNode( .extraCLIOptions(List.of("--plugin-privacy-service-encryption-prefix=0xAA")) .build(), new EnclaveKeyConfiguration( - privacyAccount.getEnclaveKeyPaths(), privacyAccount.getEnclavePrivateKeyPaths())), + privacyAccount.getEnclaveKeyPaths(), + privacyAccount.getEnclavePrivateKeyPaths(), + privacyAccount.getEnclaveEncryptorType())), enclaveType, containerNetwork); } - public PrivacyNode createPrivateTransactionEnabledNode( - final String name, - final PrivacyAccount privacyAccount, - final EnclaveType enclaveType, - final Optional containerNetwork) - throws IOException { - return createPrivateTransactionEnabledNode( - name, privacyAccount, enclaveType, containerNetwork, false, false, false); - } - public PrivacyNode createPrivateTransactionEnabledNode( final String name, final PrivacyAccount privacyAccount, @@ -122,21 +104,13 @@ public PrivacyNode createPrivateTransactionEnabledNode( .extraCLIOptions(List.of("--plugin-privacy-service-encryption-prefix=0xBB")) .build(), new EnclaveKeyConfiguration( - privacyAccount.getEnclaveKeyPaths(), privacyAccount.getEnclavePrivateKeyPaths())), + privacyAccount.getEnclaveKeyPaths(), + privacyAccount.getEnclavePrivateKeyPaths(), + privacyAccount.getEnclaveEncryptorType())), enclaveType, containerNetwork); } - public PrivacyNode createIbft2NodePrivacyEnabled( - final String name, - final PrivacyAccount privacyAccount, - final EnclaveType enclaveType, - final Optional containerNetwork) - throws IOException { - return createIbft2NodePrivacyEnabled( - name, privacyAccount, false, enclaveType, containerNetwork, false, false, false, "0xAA"); - } - public PrivacyNode createIbft2NodePrivacyEnabled( final String name, final PrivacyAccount privacyAccount, @@ -167,7 +141,9 @@ public PrivacyNode createIbft2NodePrivacyEnabled( List.of("--plugin-privacy-service-encryption-prefix=" + unrestrictedPrefix)) .build(), new EnclaveKeyConfiguration( - privacyAccount.getEnclaveKeyPaths(), privacyAccount.getEnclavePrivateKeyPaths())), + privacyAccount.getEnclaveKeyPaths(), + privacyAccount.getEnclavePrivateKeyPaths(), + privacyAccount.getEnclaveEncryptorType())), enclaveType, containerNetwork); } @@ -204,7 +180,9 @@ public PrivacyNode createIbft2NodePrivacyEnabledWithGenesis( "--plugin-privacy-service-genesis-enabled=true")) .build(), new EnclaveKeyConfiguration( - privacyAccount.getEnclaveKeyPaths(), privacyAccount.getEnclavePrivateKeyPaths())), + privacyAccount.getEnclaveKeyPaths(), + privacyAccount.getEnclavePrivateKeyPaths(), + privacyAccount.getEnclaveEncryptorType())), enclaveType, containerNetwork); } @@ -238,7 +216,9 @@ public PrivacyNode createQbftNodePrivacyEnabled( List.of("--plugin-privacy-service-encryption-prefix=" + unrestrictedPrefix)) .build(), new EnclaveKeyConfiguration( - privacyAccount.getEnclaveKeyPaths(), privacyAccount.getEnclavePrivateKeyPaths())), + privacyAccount.getEnclaveKeyPaths(), + privacyAccount.getEnclavePrivateKeyPaths(), + privacyAccount.getEnclaveEncryptorType())), enclaveType, containerNetwork); } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/ParameterizedEnclaveTestBase.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/ParameterizedEnclaveTestBase.java index c9ecaa7a113..581fd71722d 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/ParameterizedEnclaveTestBase.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/ParameterizedEnclaveTestBase.java @@ -14,6 +14,8 @@ */ package org.hyperledger.besu.tests.acceptance.dsl.privacy; +import static org.hyperledger.enclave.testutil.EnclaveEncryptorType.EC; +import static org.hyperledger.enclave.testutil.EnclaveEncryptorType.NACL; import static org.hyperledger.enclave.testutil.EnclaveType.NOOP; import static org.hyperledger.enclave.testutil.EnclaveType.TESSERA; import static org.web3j.utils.Restriction.RESTRICTED; @@ -22,6 +24,7 @@ import org.hyperledger.besu.tests.acceptance.dsl.privacy.transaction.PluginCreateRandomPrivacyGroupIdTransaction; import org.hyperledger.besu.tests.acceptance.dsl.privacy.transaction.RestrictedCreatePrivacyGroupTransaction; import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction; +import org.hyperledger.enclave.testutil.EnclaveEncryptorType; import org.hyperledger.enclave.testutil.EnclaveType; import java.util.Arrays; @@ -36,19 +39,24 @@ public abstract class ParameterizedEnclaveTestBase extends PrivacyAcceptanceTestBase { protected final Restriction restriction; protected final EnclaveType enclaveType; + protected final EnclaveEncryptorType enclaveEncryptorType; protected ParameterizedEnclaveTestBase( - final Restriction restriction, final EnclaveType enclaveType) { + final Restriction restriction, + final EnclaveType enclaveType, + final EnclaveEncryptorType enclaveEncryptorType) { this.restriction = restriction; this.enclaveType = enclaveType; + this.enclaveEncryptorType = enclaveEncryptorType; } - @Parameters(name = "{0} tx with {1} enclave") + @Parameters(name = "{0} tx with {1} enclave and {2} encryptor type") public static Collection params() { return Arrays.asList( new Object[][] { - {RESTRICTED, TESSERA}, - {UNRESTRICTED, NOOP} + {RESTRICTED, TESSERA, NACL}, + {RESTRICTED, TESSERA, EC}, + {UNRESTRICTED, NOOP, EnclaveEncryptorType.NOOP} }); } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/PrivacyAcceptanceTestBase.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/PrivacyAcceptanceTestBase.java index 5fe784573cf..8e12cbc7a80 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/PrivacyAcceptanceTestBase.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/PrivacyAcceptanceTestBase.java @@ -21,7 +21,6 @@ import org.hyperledger.besu.tests.acceptance.dsl.condition.net.NetConditions; import org.hyperledger.besu.tests.acceptance.dsl.condition.priv.PrivConditions; import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.privacy.PrivacyNodeFactory; -import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver; import org.hyperledger.besu.tests.acceptance.dsl.privacy.condition.PrivateContractVerifier; import org.hyperledger.besu.tests.acceptance.dsl.privacy.condition.PrivateTransactionVerifier; import org.hyperledger.besu.tests.acceptance.dsl.privacy.contract.PrivateContractTransactions; @@ -47,7 +46,6 @@ public class PrivacyAcceptanceTestBase { protected final PrivateContractTransactions privateContractTransactions; protected final PrivConditions priv; protected final PrivacyCluster privacyCluster; - protected final PrivacyAccountResolver privacyAccountResolver; protected final ContractTransactions contractTransactions; protected final NetConditions net; protected final EthTransactions ethTransactions; @@ -63,7 +61,6 @@ public PrivacyAcceptanceTestBase() { privacyBesu = new PrivacyNodeFactory(vertx); privateContractTransactions = new PrivateContractTransactions(); privacyCluster = new PrivacyCluster(net); - privacyAccountResolver = new PrivacyAccountResolver(); priv = new PrivConditions( new org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/account/PrivacyAccount.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/account/PrivacyAccount.java index 07267342d52..c246dd585a5 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/account/PrivacyAccount.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/account/PrivacyAccount.java @@ -14,6 +14,8 @@ */ package org.hyperledger.besu.tests.acceptance.dsl.privacy.account; +import org.hyperledger.enclave.testutil.EnclaveEncryptorType; + import java.io.File; import java.net.URL; import java.util.Arrays; @@ -23,27 +25,38 @@ public class PrivacyAccount { private final URL privateKeyPath; private final URL[] enclaveKeyPaths; private final URL[] enclavePrivateKeyPaths; + private final EnclaveEncryptorType enclaveEncryptorType; private PrivacyAccount( final URL privateKeyPath, final URL[] enclavePublicKeyPaths, - final URL[] enclavePrivateKeyPaths) { + final URL[] enclavePrivateKeyPaths, + final EnclaveEncryptorType enclaveEncryptorType) { this.privateKeyPath = privateKeyPath; this.enclaveKeyPaths = enclavePublicKeyPaths; this.enclavePrivateKeyPaths = enclavePrivateKeyPaths; + this.enclaveEncryptorType = enclaveEncryptorType; } public static PrivacyAccount create( - final URL privateKeyPath, final URL enclavePublicKeyPath, final URL enclavePrivateKeyPath) { + final URL privateKeyPath, + final URL enclavePublicKeyPath, + final URL enclavePrivateKeyPath, + final EnclaveEncryptorType enclaveEncryptorType) { return new PrivacyAccount( - privateKeyPath, new URL[] {enclavePublicKeyPath}, new URL[] {enclavePrivateKeyPath}); + privateKeyPath, + new URL[] {enclavePublicKeyPath}, + new URL[] {enclavePrivateKeyPath}, + enclaveEncryptorType); } public static PrivacyAccount create( final URL privateKeyPath, final URL[] enclavePublicKeyPath, - final URL[] enclavePrivateKeyPath) { - return new PrivacyAccount(privateKeyPath, enclavePublicKeyPath, enclavePrivateKeyPath); + final URL[] enclavePrivateKeyPath, + final EnclaveEncryptorType enclaveEncryptorType) { + return new PrivacyAccount( + privateKeyPath, enclavePublicKeyPath, enclavePrivateKeyPath, enclaveEncryptorType); } public String getPrivateKeyPath() { @@ -62,6 +75,10 @@ public String[] getEnclavePrivateKeyPaths() { .toArray(String[]::new); } + public EnclaveEncryptorType getEnclaveEncryptorType() { + return enclaveEncryptorType; + } + private String toStringResource(final URL path) { return path.getPath().substring(path.getPath().lastIndexOf(File.separator) + 1); } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/account/PrivacyAccountResolver.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/account/PrivacyAccountResolver.java index be349b8bf22..7a6e26f7bce 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/account/PrivacyAccountResolver.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/account/PrivacyAccountResolver.java @@ -14,59 +14,88 @@ */ package org.hyperledger.besu.tests.acceptance.dsl.privacy.account; +import org.hyperledger.enclave.testutil.EnclaveEncryptorType; + import java.net.URL; /** Supplier of known funded accounts defined in dev.json */ -public class PrivacyAccountResolver { - - public static final PrivacyAccount ALICE = - PrivacyAccount.create( +public enum PrivacyAccountResolver { + ALICE { + @Override + public PrivacyAccount resolve(final EnclaveEncryptorType enclaveEncryptorType) { + return PrivacyAccount.create( resolveResource("key"), - resolveResource("enclave_key_0.pub"), - resolveResource("enclave_key_0.key")); - - public static final PrivacyAccount BOB = - PrivacyAccount.create( + enclaveEncryptorType.equals(EnclaveEncryptorType.EC) + ? resolveResource("enclave_ec_key_0.pub") + : resolveResource("enclave_key_0.pub"), + enclaveEncryptorType.equals(EnclaveEncryptorType.EC) + ? resolveResource("enclave_ec_key_0.key") + : resolveResource("enclave_key_0.key"), + enclaveEncryptorType); + } + }, + BOB { + @Override + public PrivacyAccount resolve(final EnclaveEncryptorType enclaveEncryptorType) { + return PrivacyAccount.create( resolveResource("key1"), - resolveResource("enclave_key_1.pub"), - resolveResource("enclave_key_1.key")); - - public static final PrivacyAccount CHARLIE = - PrivacyAccount.create( + enclaveEncryptorType.equals(EnclaveEncryptorType.EC) + ? resolveResource("enclave_ec_key_1.pub") + : resolveResource("enclave_key_1.pub"), + enclaveEncryptorType.equals(EnclaveEncryptorType.EC) + ? resolveResource("enclave_ec_key_1.key") + : resolveResource("enclave_key_1.key"), + enclaveEncryptorType); + } + }, + CHARLIE { + @Override + public PrivacyAccount resolve(final EnclaveEncryptorType enclaveEncryptorType) { + return PrivacyAccount.create( resolveResource("key2"), - resolveResource("enclave_key_2.pub"), - resolveResource("enclave_key_2.key")); - - public static final PrivacyAccount MULTI_TENANCY = - PrivacyAccount.create( + enclaveEncryptorType.equals(EnclaveEncryptorType.EC) + ? resolveResource("enclave_ec_key_2.pub") + : resolveResource("enclave_key_2.pub"), + enclaveEncryptorType.equals(EnclaveEncryptorType.EC) + ? resolveResource("enclave_ec_key_2.key") + : resolveResource("enclave_key_2.key"), + enclaveEncryptorType); + } + }, + MULTI_TENANCY { + @Override + public PrivacyAccount resolve(final EnclaveEncryptorType enclaveEncryptorType) { + return PrivacyAccount.create( resolveResource("key"), new URL[] { - resolveResource("enclave_key_0.pub"), - resolveResource("enclave_key_1.pub"), - resolveResource("enclave_key_2.pub") + enclaveEncryptorType.equals(EnclaveEncryptorType.EC) + ? resolveResource("enclave_ec_key_0.pub") + : resolveResource("enclave_key_0.pub"), + enclaveEncryptorType.equals(EnclaveEncryptorType.EC) + ? resolveResource("enclave_ec_key_1.pub") + : resolveResource("enclave_key_1.pub"), + enclaveEncryptorType.equals(EnclaveEncryptorType.EC) + ? resolveResource("enclave_ec_key_2.pub") + : resolveResource("enclave_key_2.pub") }, new URL[] { - resolveResource("enclave_key_0.key"), - resolveResource("enclave_key_1.key"), - resolveResource("enclave_key_2.key") - }); - - private static URL resolveResource(final String resource) { - return PrivacyAccountResolver.class.getClassLoader().getResource(resource); - } + enclaveEncryptorType.equals(EnclaveEncryptorType.EC) + ? resolveResource("enclave_ec_key_0.key") + : resolveResource("enclave_key_0.key"), + enclaveEncryptorType.equals(EnclaveEncryptorType.EC) + ? resolveResource("enclave_ec_key_1.key") + : resolveResource("enclave_key_1.key"), + enclaveEncryptorType.equals(EnclaveEncryptorType.EC) + ? resolveResource("enclave_ec_key_2.key") + : resolveResource("enclave_key_2.key") + }, + enclaveEncryptorType); + } + }; - public PrivacyAccountResolver() {} + public abstract PrivacyAccount resolve(final EnclaveEncryptorType enclaveEncryptorType); - public PrivacyAccount resolve(final Integer account) { - switch (account) { - case 0: - return ALICE; - case 1: - return BOB; - case 2: - return CHARLIE; - default: - throw new RuntimeException("Unknown privacy account"); - } + URL resolveResource(final String resource) { + return PrivacyAccountResolver.class.getClassLoader().getResource(resource); } } diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/BftPrivacyClusterAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/BftPrivacyClusterAcceptanceTest.java index 5f47cc565e5..2baf1d1f5ce 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/BftPrivacyClusterAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/BftPrivacyClusterAcceptanceTest.java @@ -16,8 +16,10 @@ import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyAcceptanceTestBase; import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode; +import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver; import org.hyperledger.besu.tests.acceptance.dsl.transaction.bft.ConsensusType; import org.hyperledger.besu.tests.web3j.generated.EventEmitter; +import org.hyperledger.enclave.testutil.EnclaveEncryptorType; import org.hyperledger.enclave.testutil.EnclaveType; import java.io.IOException; @@ -41,14 +43,17 @@ public class BftPrivacyClusterAcceptanceTest extends PrivacyAcceptanceTestBase { public static class BftPrivacyType { private final EnclaveType enclaveType; + private final EnclaveEncryptorType enclaveEncryptorType; private final ConsensusType consensusType; private final Restriction restriction; public BftPrivacyType( final EnclaveType enclaveType, + final EnclaveEncryptorType enclaveEncryptorType, final ConsensusType consensusType, final Restriction restriction) { this.enclaveType = enclaveType; + this.enclaveEncryptorType = enclaveEncryptorType; this.consensusType = consensusType; this.restriction = restriction; } @@ -56,7 +61,11 @@ public BftPrivacyType( @Override public String toString() { return String.join( - ",", enclaveType.toString(), consensusType.toString(), restriction.toString()); + ",", + enclaveType.toString(), + enclaveEncryptorType.toString(), + consensusType.toString(), + restriction.toString()); } } @@ -69,13 +78,21 @@ public static Collection bftPrivacyTypes() { final List bftPrivacyTypes = new ArrayList<>(); for (EnclaveType x : EnclaveType.valuesForTests()) { for (ConsensusType consensusType : ConsensusType.values()) { - bftPrivacyTypes.add(new BftPrivacyType(x, consensusType, Restriction.RESTRICTED)); + bftPrivacyTypes.add( + new BftPrivacyType( + x, EnclaveEncryptorType.NACL, consensusType, Restriction.RESTRICTED)); + bftPrivacyTypes.add( + new BftPrivacyType(x, EnclaveEncryptorType.EC, consensusType, Restriction.RESTRICTED)); } } for (ConsensusType consensusType : ConsensusType.values()) { bftPrivacyTypes.add( - new BftPrivacyType(EnclaveType.NOOP, consensusType, Restriction.UNRESTRICTED)); + new BftPrivacyType( + EnclaveType.NOOP, + EnclaveEncryptorType.NOOP, + consensusType, + Restriction.UNRESTRICTED)); } return bftPrivacyTypes; @@ -102,7 +119,8 @@ private PrivacyNode createNode( if (bftPrivacyType.consensusType == ConsensusType.IBFT2) { return privacyBesu.createIbft2NodePrivacyEnabled( nodeName, - privacyAccountResolver.resolve(privacyAccount), + PrivacyAccountResolver.values()[privacyAccount].resolve( + bftPrivacyType.enclaveEncryptorType), true, bftPrivacyType.enclaveType, Optional.of(containerNetwork), @@ -113,7 +131,8 @@ private PrivacyNode createNode( } else if (bftPrivacyType.consensusType == ConsensusType.QBFT) { return privacyBesu.createQbftNodePrivacyEnabled( nodeName, - privacyAccountResolver.resolve(privacyAccount), + PrivacyAccountResolver.values()[privacyAccount].resolve( + bftPrivacyType.enclaveEncryptorType), bftPrivacyType.enclaveType, Optional.of(containerNetwork), false, @@ -128,7 +147,10 @@ private PrivacyNode createNode( @Test public void onlyAliceAndBobCanExecuteContract() { // Contract address is generated from sender address and transaction nonce - final String contractAddress = "0xebf56429e6500e84442467292183d4d621359838"; + final String contractAddress = + EnclaveEncryptorType.EC.equals(bftPrivacyType.enclaveEncryptorType) + ? "0x3e5d325a03ad3ce5640502219833d30b89ce3ce1" + : "0xebf56429e6500e84442467292183d4d621359838"; final EventEmitter eventEmitter = alice.execute( @@ -166,7 +188,10 @@ public void onlyAliceAndBobCanExecuteContract() { @Test public void aliceCanDeployMultipleTimesInSingleGroup() { - final String firstDeployedAddress = "0xebf56429e6500e84442467292183d4d621359838"; + final String firstDeployedAddress = + EnclaveEncryptorType.EC.equals(bftPrivacyType.enclaveEncryptorType) + ? "0x3e5d325a03ad3ce5640502219833d30b89ce3ce1" + : "0xebf56429e6500e84442467292183d4d621359838"; privacyCluster.stopNode(charlie); @@ -182,7 +207,10 @@ public void aliceCanDeployMultipleTimesInSingleGroup() { .validPrivateContractDeployed(firstDeployedAddress, alice.getAddress().toString()) .verify(firstEventEmitter); - final String secondDeployedAddress = "0x10f807f8a905da5bd319196da7523c6bd768690f"; + final String secondDeployedAddress = + EnclaveEncryptorType.EC.equals(bftPrivacyType.enclaveEncryptorType) + ? "0x5194e214fae257530710d18c868df7a295d9d53b" + : "0x10f807f8a905da5bd319196da7523c6bd768690f"; final EventEmitter secondEventEmitter = alice.execute( @@ -200,7 +228,10 @@ public void aliceCanDeployMultipleTimesInSingleGroup() { @Test public void canInteractWithMultiplePrivacyGroups() { // alice deploys contract - final String firstDeployedAddress = "0xff206d21150a8da5b83629d8a722f3135ed532b1"; + final String firstDeployedAddress = + EnclaveEncryptorType.EC.equals(bftPrivacyType.enclaveEncryptorType) + ? "0x760359bc605b3848f5199829bde6b382d90fb8eb" + : "0xff206d21150a8da5b83629d8a722f3135ed532b1"; final EventEmitter firstEventEmitter = alice.execute( @@ -240,7 +271,10 @@ public void canInteractWithMultiplePrivacyGroups() { firstTransactionHash, aliceReceipt)); // alice deploys second contract - final String secondDeployedAddress = "0xebf56429e6500e84442467292183d4d621359838"; + final String secondDeployedAddress = + EnclaveEncryptorType.EC.equals(bftPrivacyType.enclaveEncryptorType) + ? "0x3e5d325a03ad3ce5640502219833d30b89ce3ce1" + : "0xebf56429e6500e84442467292183d4d621359838"; final EventEmitter secondEventEmitter = alice.execute( diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/DeployPrivateSmartContractAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/DeployPrivateSmartContractAcceptanceTest.java index 97e6ee1100b..71aa618cdd8 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/DeployPrivateSmartContractAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/DeployPrivateSmartContractAcceptanceTest.java @@ -20,6 +20,7 @@ import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode; import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver; import org.hyperledger.besu.tests.web3j.generated.EventEmitter; +import org.hyperledger.enclave.testutil.EnclaveEncryptorType; import org.hyperledger.enclave.testutil.EnclaveType; import java.io.IOException; @@ -33,13 +34,16 @@ public class DeployPrivateSmartContractAcceptanceTest extends ParameterizedEncla private final PrivacyNode minerNode; public DeployPrivateSmartContractAcceptanceTest( - final Restriction restriction, final EnclaveType enclaveType) throws IOException { - super(restriction, enclaveType); + final Restriction restriction, + final EnclaveType enclaveType, + final EnclaveEncryptorType enclaveEncryptorType) + throws IOException { + super(restriction, enclaveType, enclaveEncryptorType); minerNode = privacyBesu.createPrivateTransactionEnabledMinerNode( restriction + "-node", - PrivacyAccountResolver.ALICE, + PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType), enclaveType, Optional.empty(), false, @@ -51,7 +55,10 @@ public DeployPrivateSmartContractAcceptanceTest( @Test public void deployingMustGiveValidReceiptAndCode() throws Exception { - final String contractAddress = "0x89ce396d0f9f937ddfa71113e29b2081c4869555"; + final String contractAddress = + EnclaveEncryptorType.EC.equals(enclaveEncryptorType) + ? "0xfeeb2367e77e28f75fc3bcc55b70a535752db058" + : "0x89ce396d0f9f937ddfa71113e29b2081c4869555"; final EventEmitter eventEmitter = minerNode.execute( diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/EnclaveErrorAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/EnclaveErrorAcceptanceTest.java index c9e090019bc..7822768f140 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/EnclaveErrorAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/EnclaveErrorAcceptanceTest.java @@ -16,15 +16,23 @@ import static org.assertj.core.api.Assertions.catchThrowable; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.hyperledger.enclave.testutil.EnclaveEncryptorType.EC; +import static org.hyperledger.enclave.testutil.EnclaveEncryptorType.NACL; +import static org.hyperledger.enclave.testutil.EnclaveType.TESSERA; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyAcceptanceTestBase; import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode; +import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver; import org.hyperledger.besu.tests.web3j.generated.EventEmitter; +import org.hyperledger.enclave.testutil.EnclaveEncryptorType; import org.hyperledger.enclave.testutil.EnclaveType; import java.io.IOException; import java.math.BigInteger; +import java.security.KeyPairGenerator; +import java.security.spec.ECGenParameterSpec; +import java.util.Arrays; import java.util.Base64; import java.util.Collection; import java.util.Optional; @@ -47,19 +55,25 @@ public class EnclaveErrorAcceptanceTest extends PrivacyAcceptanceTestBase { private final PrivacyNode bob; private final String wrongPublicKey; - @Parameters(name = "{0}") - public static Collection enclaveTypes() { - return EnclaveType.valuesForTests(); + @Parameters(name = "{0} enclave type with {1} encryptor") + public static Collection enclaveParameters() { + return Arrays.asList( + new Object[][] { + {TESSERA, NACL}, + {TESSERA, EC} + }); } - public EnclaveErrorAcceptanceTest(final EnclaveType enclaveType) throws IOException { + public EnclaveErrorAcceptanceTest( + final EnclaveType enclaveType, final EnclaveEncryptorType enclaveEncryptorType) + throws IOException { final Network containerNetwork = Network.newNetwork(); alice = privacyBesu.createIbft2NodePrivacyEnabled( "node1", - privacyAccountResolver.resolve(0), + PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType), false, enclaveType, Optional.of(containerNetwork), @@ -70,7 +84,7 @@ public EnclaveErrorAcceptanceTest(final EnclaveType enclaveType) throws IOExcept bob = privacyBesu.createIbft2NodePrivacyEnabled( "node2", - privacyAccountResolver.resolve(1), + PrivacyAccountResolver.BOB.resolve(enclaveEncryptorType), false, enclaveType, Optional.of(containerNetwork), @@ -80,8 +94,12 @@ public EnclaveErrorAcceptanceTest(final EnclaveType enclaveType) throws IOExcept "0xBB"); privacyCluster.start(alice, bob); - wrongPublicKey = - Base64.getEncoder().encodeToString(Box.KeyPair.random().publicKey().bytesArray()); + final byte[] wrongPublicKeyBytes = + EnclaveEncryptorType.EC.equals(enclaveEncryptorType) + ? getSECP256r1PublicKeyByteArray() + : Box.KeyPair.random().publicKey().bytesArray(); + + wrongPublicKey = Base64.getEncoder().encodeToString(wrongPublicKeyBytes); } @Test @@ -205,4 +223,15 @@ private Condition matchTesseraEnclaveMessage(final String enclaveMessage message -> message.contains(enclaveMessage), "Message did not match Tessera expected output"); } + + private byte[] getSECP256r1PublicKeyByteArray() { + try { + final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); + final ECGenParameterSpec spec = new ECGenParameterSpec("secp256r1"); + keyGen.initialize(spec); + return keyGen.generateKeyPair().getPublic().getEncoded(); + } catch (Exception exception) { + return new byte[0]; + } + } } diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/FlexiblePrivacyAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/FlexiblePrivacyAcceptanceTest.java index 2db988787e4..d64f73d2a03 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/FlexiblePrivacyAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/FlexiblePrivacyAcceptanceTest.java @@ -21,8 +21,10 @@ import org.hyperledger.besu.tests.acceptance.dsl.condition.eth.EthConditions; import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode; +import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver; import org.hyperledger.besu.tests.acceptance.dsl.transaction.miner.MinerTransactions; import org.hyperledger.besu.tests.web3j.generated.EventEmitter; +import org.hyperledger.enclave.testutil.EnclaveEncryptorType; import org.hyperledger.enclave.testutil.EnclaveType; import java.math.BigInteger; @@ -80,21 +82,21 @@ public void setUp() throws Exception { alice = privacyBesu.createFlexiblePrivacyGroupEnabledMinerNode( "node1", - privacyAccountResolver.resolve(0), + PrivacyAccountResolver.ALICE.resolve(EnclaveEncryptorType.NACL), false, enclaveType, Optional.of(containerNetwork)); bob = privacyBesu.createFlexiblePrivacyGroupEnabledNode( "node2", - privacyAccountResolver.resolve(1), + PrivacyAccountResolver.BOB.resolve(EnclaveEncryptorType.NACL), false, enclaveType, Optional.of(containerNetwork)); charlie = privacyBesu.createFlexiblePrivacyGroupEnabledNode( "node3", - privacyAccountResolver.resolve(2), + PrivacyAccountResolver.CHARLIE.resolve(EnclaveEncryptorType.NACL), false, enclaveType, Optional.of(containerNetwork)); diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PluginPrivacySigningAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PluginPrivacySigningAcceptanceTest.java index acc3389b94d..68d5117fd6b 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PluginPrivacySigningAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PluginPrivacySigningAcceptanceTest.java @@ -15,33 +15,56 @@ package org.hyperledger.besu.tests.acceptance.privacy; import static org.assertj.core.api.Assertions.assertThat; -import static org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver.BOB; import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.BesuNodeConfigurationBuilder; import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.privacy.PrivacyNodeConfiguration; import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyAcceptanceTestBase; import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode; +import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccount; +import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver; import org.hyperledger.besu.tests.web3j.generated.EventEmitter; +import org.hyperledger.enclave.testutil.EnclaveEncryptorType; import org.hyperledger.enclave.testutil.EnclaveKeyConfiguration; import org.hyperledger.enclave.testutil.EnclaveType; import java.io.IOException; import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; import org.web3j.protocol.core.DefaultBlockParameter; import org.web3j.protocol.core.methods.response.EthBlock.Block; import org.web3j.protocol.core.methods.response.TransactionReceipt; +@RunWith(Parameterized.class) public class PluginPrivacySigningAcceptanceTest extends PrivacyAcceptanceTestBase { private PrivacyNode minerNode; + private final EnclaveEncryptorType enclaveEncryptorType; + + public PluginPrivacySigningAcceptanceTest(final EnclaveEncryptorType enclaveEncryptorType) { + this.enclaveEncryptorType = enclaveEncryptorType; + } + + @Parameterized.Parameters(name = "{0}") + public static Collection enclaveEncryptorTypes() { + return Arrays.stream(EnclaveEncryptorType.values()) + .filter(encryptorType -> !EnclaveEncryptorType.NOOP.equals(encryptorType)) + .collect(Collectors.toList()); + } + @Before public void setup() throws IOException { + final PrivacyAccount BOB = PrivacyAccountResolver.BOB.resolve(enclaveEncryptorType); + minerNode = privacyBesu.create( new PrivacyNodeConfiguration( @@ -63,7 +86,9 @@ public void setup() throws IOException { "--plugin-privacy-service-signing-key=8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63")) .build(), new EnclaveKeyConfiguration( - BOB.getEnclaveKeyPaths(), BOB.getEnclavePrivateKeyPaths())), + BOB.getEnclaveKeyPaths(), + BOB.getEnclavePrivateKeyPaths(), + BOB.getEnclaveEncryptorType())), EnclaveType.NOOP, Optional.empty()); @@ -72,7 +97,10 @@ public void setup() throws IOException { @Test public void canDeployContractSignedByPlugin() throws Exception { - final String contractAddress = "0xd0152772c54cecfa7684f09f7616dcc825545dff"; + final String contractAddress = + EnclaveEncryptorType.EC.equals(enclaveEncryptorType) + ? "0xf01ec73d91fdeb8bb9388ec74e6a3981da86e021" + : "0xd0152772c54cecfa7684f09f7616dcc825545dff"; final EventEmitter eventEmitter = minerNode.execute( diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivCallAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivCallAcceptanceTest.java index cf5adbb9486..b2c9c3bda54 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivCallAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivCallAcceptanceTest.java @@ -22,6 +22,7 @@ import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode; import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver; import org.hyperledger.besu.tests.web3j.generated.EventEmitter; +import org.hyperledger.enclave.testutil.EnclaveEncryptorType; import org.hyperledger.enclave.testutil.EnclaveType; import java.io.IOException; @@ -53,15 +54,18 @@ public class PrivCallAcceptanceTest extends ParameterizedEnclaveTestBase { private final PrivacyNode minerNode; - public PrivCallAcceptanceTest(final Restriction restriction, final EnclaveType enclaveType) + public PrivCallAcceptanceTest( + final Restriction restriction, + final EnclaveType enclaveType, + final EnclaveEncryptorType enclaveEncryptorType) throws IOException { - super(restriction, enclaveType); + super(restriction, enclaveType, enclaveEncryptorType); minerNode = privacyBesu.createPrivateTransactionEnabledMinerNode( restriction + "-node", - PrivacyAccountResolver.ALICE, + PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType), enclaveType, Optional.empty(), false, diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootFlexibleGroupAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootFlexibleGroupAcceptanceTest.java index e8aef87f371..59973fd00be 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootFlexibleGroupAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootFlexibleGroupAcceptanceTest.java @@ -21,6 +21,7 @@ import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver; import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.PrivacyRequestFactory; import org.hyperledger.besu.tests.web3j.generated.EventEmitter; +import org.hyperledger.enclave.testutil.EnclaveEncryptorType; import org.hyperledger.enclave.testutil.EnclaveType; import java.io.IOException; @@ -62,14 +63,14 @@ public void setUp() throws IOException, URISyntaxException { aliceNode = privacyBesu.createFlexiblePrivacyGroupEnabledMinerNode( "alice-node", - PrivacyAccountResolver.ALICE, + PrivacyAccountResolver.ALICE.resolve(EnclaveEncryptorType.NACL), false, enclaveType, Optional.of(containerNetwork)); bobNode = privacyBesu.createFlexiblePrivacyGroupEnabledNode( "bob-node", - PrivacyAccountResolver.BOB, + PrivacyAccountResolver.BOB.resolve(EnclaveEncryptorType.NACL), false, enclaveType, Optional.of(containerNetwork)); diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootOffchainGroupAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootOffchainGroupAcceptanceTest.java index 2d1b83e4340..92643446ddb 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootOffchainGroupAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootOffchainGroupAcceptanceTest.java @@ -22,6 +22,7 @@ import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode; import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver; import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.PrivacyRequestFactory; +import org.hyperledger.enclave.testutil.EnclaveEncryptorType; import org.hyperledger.enclave.testutil.EnclaveType; import java.io.IOException; @@ -38,16 +39,19 @@ public class PrivDebugGetStateRootOffchainGroupAcceptanceTest extends Parameteri private final PrivacyNode bobNode; public PrivDebugGetStateRootOffchainGroupAcceptanceTest( - final Restriction restriction, final EnclaveType enclaveType) throws IOException { + final Restriction restriction, + final EnclaveType enclaveType, + final EnclaveEncryptorType enclaveEncryptorType) + throws IOException { - super(restriction, enclaveType); + super(restriction, enclaveType, enclaveEncryptorType); final Network containerNetwork = Network.newNetwork(); aliceNode = privacyBesu.createIbft2NodePrivacyEnabled( "alice-node", - PrivacyAccountResolver.ALICE, + PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType), false, enclaveType, Optional.of(containerNetwork), @@ -58,7 +62,7 @@ public PrivDebugGetStateRootOffchainGroupAcceptanceTest( bobNode = privacyBesu.createIbft2NodePrivacyEnabled( "bob-node", - PrivacyAccountResolver.BOB, + PrivacyAccountResolver.BOB.resolve(enclaveEncryptorType), false, enclaveType, Optional.of(containerNetwork), diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetCodeAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetCodeAcceptanceTest.java index f2bb0399cd7..c08006f694b 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetCodeAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetCodeAcceptanceTest.java @@ -22,6 +22,7 @@ import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode; import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver; import org.hyperledger.besu.tests.web3j.generated.EventEmitter; +import org.hyperledger.enclave.testutil.EnclaveEncryptorType; import org.hyperledger.enclave.testutil.EnclaveType; import java.io.IOException; @@ -35,15 +36,18 @@ public class PrivGetCodeAcceptanceTest extends ParameterizedEnclaveTestBase { private final PrivacyNode alice; - public PrivGetCodeAcceptanceTest(final Restriction restriction, final EnclaveType enclaveType) + public PrivGetCodeAcceptanceTest( + final Restriction restriction, + final EnclaveType enclaveType, + final EnclaveEncryptorType enclaveEncryptorType) throws IOException { - super(restriction, enclaveType); + super(restriction, enclaveType, enclaveEncryptorType); alice = privacyBesu.createPrivateTransactionEnabledMinerNode( restriction + "-node", - PrivacyAccountResolver.ALICE, + PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType), enclaveType, Optional.empty(), false, diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetLogsAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetLogsAcceptanceTest.java index c97eb39662e..62519385a2e 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetLogsAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetLogsAcceptanceTest.java @@ -22,6 +22,7 @@ import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver; import org.hyperledger.besu.tests.acceptance.dsl.privacy.util.LogFilterJsonParameter; import org.hyperledger.besu.tests.web3j.generated.EventEmitter; +import org.hyperledger.enclave.testutil.EnclaveEncryptorType; import org.hyperledger.enclave.testutil.EnclaveType; import java.io.IOException; @@ -45,15 +46,18 @@ public class PrivGetLogsAcceptanceTest extends ParameterizedEnclaveTestBase { private final PrivacyNode node; - public PrivGetLogsAcceptanceTest(final Restriction restriction, final EnclaveType enclaveType) + public PrivGetLogsAcceptanceTest( + final Restriction restriction, + final EnclaveType enclaveType, + final EnclaveEncryptorType enclaveEncryptorType) throws IOException { - super(restriction, enclaveType); + super(restriction, enclaveType, enclaveEncryptorType); node = privacyBesu.createPrivateTransactionEnabledMinerNode( restriction + "-node", - PrivacyAccountResolver.ALICE, + PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType), enclaveType, Optional.empty(), false, diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetPrivateTransactionAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetPrivateTransactionAcceptanceTest.java index f395961058e..91896761d09 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetPrivateTransactionAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetPrivateTransactionAcceptanceTest.java @@ -23,7 +23,9 @@ import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.tests.acceptance.dsl.privacy.ParameterizedEnclaveTestBase; import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode; +import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver; import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction; +import org.hyperledger.enclave.testutil.EnclaveEncryptorType; import org.hyperledger.enclave.testutil.EnclaveType; import java.io.IOException; @@ -40,16 +42,19 @@ public class PrivGetPrivateTransactionAcceptanceTest extends ParameterizedEnclav private final PrivacyNode bob; public PrivGetPrivateTransactionAcceptanceTest( - final Restriction restriction, final EnclaveType enclaveType) throws IOException { + final Restriction restriction, + final EnclaveType enclaveType, + final EnclaveEncryptorType enclaveEncryptorType) + throws IOException { - super(restriction, enclaveType); + super(restriction, enclaveType, enclaveEncryptorType); final Network containerNetwork = Network.newNetwork(); alice = privacyBesu.createIbft2NodePrivacyEnabled( "node1", - privacyAccountResolver.resolve(0), + PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType), false, enclaveType, Optional.of(containerNetwork), @@ -60,7 +65,7 @@ public PrivGetPrivateTransactionAcceptanceTest( bob = privacyBesu.createIbft2NodePrivacyEnabled( "node2", - privacyAccountResolver.resolve(1), + PrivacyAccountResolver.BOB.resolve(enclaveEncryptorType), false, enclaveType, Optional.of(containerNetwork), diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyClusterAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyClusterAcceptanceTest.java index 5f10b1e0c0e..1284daf917e 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyClusterAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyClusterAcceptanceTest.java @@ -16,6 +16,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.hyperledger.besu.ethereum.core.PrivacyParameters.DEFAULT_PRIVACY; +import static org.hyperledger.enclave.testutil.EnclaveEncryptorType.EC; +import static org.hyperledger.enclave.testutil.EnclaveEncryptorType.NACL; +import static org.hyperledger.enclave.testutil.EnclaveType.TESSERA; import static org.web3j.utils.Restriction.RESTRICTED; import org.hyperledger.besu.enclave.Enclave; @@ -23,12 +26,15 @@ import org.hyperledger.besu.enclave.types.ReceiveResponse; import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyAcceptanceTestBase; import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode; +import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver; import org.hyperledger.besu.tests.web3j.generated.EventEmitter; +import org.hyperledger.enclave.testutil.EnclaveEncryptorType; import org.hyperledger.enclave.testutil.EnclaveType; import java.io.IOException; import java.math.BigInteger; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Optional; @@ -56,20 +62,28 @@ public class PrivacyClusterAcceptanceTest extends PrivacyAcceptanceTestBase { private final PrivacyNode alice; private final PrivacyNode bob; private final PrivacyNode charlie; + private final EnclaveEncryptorType enclaveEncryptorType; private final Vertx vertx = Vertx.vertx(); private final EnclaveFactory enclaveFactory = new EnclaveFactory(vertx); - @Parameters(name = "{0}") - public static Collection enclaveTypes() { - return EnclaveType.valuesForTests(); + @Parameters(name = "{0} enclave type with {1} encryptor") + public static Collection enclaveParameters() { + return Arrays.asList( + new Object[][] { + {TESSERA, NACL}, + {TESSERA, EC} + }); } - public PrivacyClusterAcceptanceTest(final EnclaveType enclaveType) throws IOException { + public PrivacyClusterAcceptanceTest( + final EnclaveType enclaveType, final EnclaveEncryptorType enclaveEncryptorType) + throws IOException { + this.enclaveEncryptorType = enclaveEncryptorType; final Network containerNetwork = Network.newNetwork(); alice = privacyBesu.createPrivateTransactionEnabledMinerNode( "node1", - privacyAccountResolver.resolve(0), + PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType), enclaveType, Optional.of(containerNetwork), false, @@ -78,7 +92,7 @@ public PrivacyClusterAcceptanceTest(final EnclaveType enclaveType) throws IOExce bob = privacyBesu.createPrivateTransactionEnabledNode( "node2", - privacyAccountResolver.resolve(1), + PrivacyAccountResolver.BOB.resolve(enclaveEncryptorType), enclaveType, Optional.of(containerNetwork), false, @@ -87,7 +101,7 @@ public PrivacyClusterAcceptanceTest(final EnclaveType enclaveType) throws IOExce charlie = privacyBesu.createPrivateTransactionEnabledNode( "node3", - privacyAccountResolver.resolve(2), + PrivacyAccountResolver.CHARLIE.resolve(enclaveEncryptorType), enclaveType, Optional.of(containerNetwork), false, @@ -104,7 +118,10 @@ public void cleanUp() { @Test public void onlyAliceAndBobCanExecuteContract() { // Contract address is generated from sender address and transaction nonce - final String contractAddress = "0xebf56429e6500e84442467292183d4d621359838"; + final String contractAddress = + EnclaveEncryptorType.EC.equals(enclaveEncryptorType) + ? "0x3e5d325a03ad3ce5640502219833d30b89ce3ce1" + : "0xebf56429e6500e84442467292183d4d621359838"; final EventEmitter eventEmitter = alice.execute( @@ -162,7 +179,10 @@ public void onlyAliceAndBobCanExecuteContract() { @Test public void aliceCanUsePrivDistributeTransaction() { // Contract address is generated from sender address and transaction nonce - final String contractAddress = "0xebf56429e6500e84442467292183d4d621359838"; + final String contractAddress = + EnclaveEncryptorType.EC.equals(enclaveEncryptorType) + ? "0x3e5d325a03ad3ce5640502219833d30b89ce3ce1" + : "0xebf56429e6500e84442467292183d4d621359838"; final RawPrivateTransaction rawPrivateTransaction = RawPrivateTransaction.createContractTransaction( @@ -208,6 +228,22 @@ public void aliceCanUsePrivDistributeTransaction() { final String transactionHash = alice.execute(ethTransactions.sendRawTransaction(signedPmt)); + final String receiptPrivateFrom = + EnclaveEncryptorType.EC.equals(enclaveEncryptorType) + ? "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAES8nC4qT/KdoAoTSF3qs/47DUsDihyVbWiRjZAiyvqp9eSDkqV1RzlM+58oOwnpFRwvWNZM+AxMVxT+MvxdsqMA==" + : "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; + final ArrayList receiptPrivateFor = + EnclaveEncryptorType.EC.equals(enclaveEncryptorType) + ? new ArrayList<>( + Collections.singletonList( + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXIgZqRA25V+3nN+Do6b5r0jiUunub6ubjPhqwHpPxP44uUYh9RKCQNRnsqCJ9PjeTnC8R3ieJk7HWAlycU1bug==")) + : new ArrayList<>( + Collections.singletonList("Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs=")); + final String receiptPrivacyGroupId = + EnclaveEncryptorType.EC.equals(enclaveEncryptorType) + ? "MjuFB4b9Hz+f8zvkWWasxZWRjHWXU4t7B2nOHo4mekA=" + : "DyAOiF/ynpc+JXa2YAGB0bCitSlOMNm+ShmB/7M6C4w="; + final PrivateTransactionReceipt expectedReceipt = new PrivateTransactionReceipt( contractAddress, @@ -217,10 +253,9 @@ public void aliceCanUsePrivDistributeTransaction() { Collections.emptyList(), "0x023955c49d6265c579561940287449242704d5fd239ff07ea36a3fc7aface61c", "0x82e521ee16ff13104c5f81e8354ecaaafd5450b710b07f620204032bfe76041a", - "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=", - new ArrayList<>( - Collections.singletonList("Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs=")), - "DyAOiF/ynpc+JXa2YAGB0bCitSlOMNm+ShmB/7M6C4w=", + receiptPrivateFrom, + receiptPrivateFor, + receiptPrivacyGroupId, "0x1", null); @@ -244,7 +279,10 @@ public void aliceCanUsePrivDistributeTransaction() { @Test public void aliceCanDeployMultipleTimesInSingleGroup() { - final String firstDeployedAddress = "0xebf56429e6500e84442467292183d4d621359838"; + final String firstDeployedAddress = + EnclaveEncryptorType.EC.equals(enclaveEncryptorType) + ? "0x3e5d325a03ad3ce5640502219833d30b89ce3ce1" + : "0xebf56429e6500e84442467292183d4d621359838"; final EventEmitter firstEventEmitter = alice.execute( @@ -258,7 +296,10 @@ public void aliceCanDeployMultipleTimesInSingleGroup() { .validPrivateContractDeployed(firstDeployedAddress, alice.getAddress().toString()) .verify(firstEventEmitter); - final String secondDeployedAddress = "0x10f807f8a905da5bd319196da7523c6bd768690f"; + final String secondDeployedAddress = + EnclaveEncryptorType.EC.equals(enclaveEncryptorType) + ? "0x5194e214fae257530710d18c868df7a295d9d53b" + : "0x10f807f8a905da5bd319196da7523c6bd768690f"; final EventEmitter secondEventEmitter = alice.execute( @@ -276,7 +317,10 @@ public void aliceCanDeployMultipleTimesInSingleGroup() { @Test public void canInteractWithMultiplePrivacyGroups() { // alice deploys contract - final String firstDeployedAddress = "0xff206d21150a8da5b83629d8a722f3135ed532b1"; + final String firstDeployedAddress = + EnclaveEncryptorType.EC.equals(enclaveEncryptorType) + ? "0x760359bc605b3848f5199829bde6b382d90fb8eb" + : "0xff206d21150a8da5b83629d8a722f3135ed532b1"; final EventEmitter firstEventEmitter = alice.execute( @@ -316,7 +360,10 @@ public void canInteractWithMultiplePrivacyGroups() { firstTransactionHash, firstExpectedReceipt)); // alice deploys second contract - final String secondDeployedAddress = "0xebf56429e6500e84442467292183d4d621359838"; + final String secondDeployedAddress = + EnclaveEncryptorType.EC.equals(enclaveEncryptorType) + ? "0x3e5d325a03ad3ce5640502219833d30b89ce3ce1" + : "0xebf56429e6500e84442467292183d4d621359838"; final EventEmitter secondEventEmitter = alice.execute( diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyGroupAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyGroupAcceptanceTest.java index 13e3a7fe567..ab1bd91d0e7 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyGroupAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyGroupAcceptanceTest.java @@ -15,16 +15,22 @@ package org.hyperledger.besu.tests.acceptance.privacy; import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.enclave.testutil.EnclaveEncryptorType.EC; +import static org.hyperledger.enclave.testutil.EnclaveEncryptorType.NACL; +import static org.hyperledger.enclave.testutil.EnclaveType.TESSERA; import static org.web3j.utils.Restriction.RESTRICTED; import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyAcceptanceTestBase; import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode; +import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver; import org.hyperledger.besu.tests.web3j.generated.EventEmitter; import org.hyperledger.besu.util.Log4j2ConfiguratorUtil; +import org.hyperledger.enclave.testutil.EnclaveEncryptorType; import org.hyperledger.enclave.testutil.EnclaveType; import java.io.IOException; import java.math.BigInteger; +import java.util.Arrays; import java.util.Collection; import java.util.Optional; @@ -45,19 +51,25 @@ public class PrivacyGroupAcceptanceTest extends PrivacyAcceptanceTestBase { private final PrivacyNode bob; private final PrivacyNode charlie; - @Parameters(name = "{0}") - public static Collection enclaveTypes() { - return EnclaveType.valuesForTests(); + @Parameters(name = "{0} enclave type with {1} encryptor") + public static Collection enclaveParameters() { + return Arrays.asList( + new Object[][] { + {TESSERA, NACL}, + {TESSERA, EC} + }); } - public PrivacyGroupAcceptanceTest(final EnclaveType enclaveType) throws IOException { + public PrivacyGroupAcceptanceTest( + final EnclaveType enclaveType, final EnclaveEncryptorType enclaveEncryptorType) + throws IOException { final Network containerNetwork = Network.newNetwork(); alice = privacyBesu.createPrivateTransactionEnabledMinerNode( "node1", - privacyAccountResolver.resolve(0), + PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType), enclaveType, Optional.of(containerNetwork), false, @@ -66,7 +78,7 @@ public PrivacyGroupAcceptanceTest(final EnclaveType enclaveType) throws IOExcept bob = privacyBesu.createPrivateTransactionEnabledNode( "node2", - privacyAccountResolver.resolve(1), + PrivacyAccountResolver.BOB.resolve(enclaveEncryptorType), enclaveType, Optional.of(containerNetwork), false, @@ -76,7 +88,7 @@ public PrivacyGroupAcceptanceTest(final EnclaveType enclaveType) throws IOExcept charlie = privacyBesu.createPrivateTransactionEnabledNode( "node3", - privacyAccountResolver.resolve(2), + PrivacyAccountResolver.CHARLIE.resolve(enclaveEncryptorType), enclaveType, Optional.of(containerNetwork), false, diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyReceiptAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyReceiptAcceptanceTest.java index ec8bb1f863e..0b45d29732a 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyReceiptAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyReceiptAcceptanceTest.java @@ -27,6 +27,7 @@ import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver; import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction; import org.hyperledger.besu.tests.acceptance.dsl.transaction.miner.MinerTransactions; +import org.hyperledger.enclave.testutil.EnclaveEncryptorType; import org.hyperledger.enclave.testutil.EnclaveType; import java.io.IOException; @@ -41,14 +42,17 @@ public class PrivacyReceiptAcceptanceTest extends ParameterizedEnclaveTestBase { private final PrivacyNode alice; - public PrivacyReceiptAcceptanceTest(final Restriction restriction, final EnclaveType enclaveType) + public PrivacyReceiptAcceptanceTest( + final Restriction restriction, + final EnclaveType enclaveType, + final EnclaveEncryptorType enclaveEncryptorType) throws IOException { - super(restriction, enclaveType); + super(restriction, enclaveType, enclaveEncryptorType); alice = privacyBesu.createIbft2NodePrivacyEnabled( "node1", - PrivacyAccountResolver.ALICE, + PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType), false, enclaveType, Optional.empty(), diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateContractPublicStateAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateContractPublicStateAcceptanceTest.java index a65ba9df7d9..83a7ce66d8b 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateContractPublicStateAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateContractPublicStateAcceptanceTest.java @@ -21,10 +21,12 @@ import org.hyperledger.besu.tests.acceptance.dsl.privacy.ParameterizedEnclaveTestBase; import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode; +import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver; import org.hyperledger.besu.tests.web3j.generated.CrossContractReader; import org.hyperledger.besu.tests.web3j.generated.EventEmitter; import org.hyperledger.besu.tests.web3j.generated.RemoteSimpleStorage; import org.hyperledger.besu.tests.web3j.generated.SimpleStorage; +import org.hyperledger.enclave.testutil.EnclaveEncryptorType; import org.hyperledger.enclave.testutil.EnclaveType; import java.io.IOException; @@ -45,14 +47,17 @@ public class PrivateContractPublicStateAcceptanceTest extends ParameterizedEncla private final PrivacyNode transactionNode; public PrivateContractPublicStateAcceptanceTest( - final Restriction restriction, final EnclaveType enclaveType) throws IOException { - super(restriction, enclaveType); + final Restriction restriction, + final EnclaveType enclaveType, + final EnclaveEncryptorType enclaveEncryptorType) + throws IOException { + super(restriction, enclaveType, enclaveEncryptorType); final Network containerNetwork = Network.newNetwork(); final PrivacyNode minerNode = privacyBesu.createPrivateTransactionEnabledMinerNode( restriction + "-miner-node", - privacyAccountResolver.resolve(0), + PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType), enclaveType, Optional.of(containerNetwork), false, @@ -62,7 +67,7 @@ public PrivateContractPublicStateAcceptanceTest( transactionNode = privacyBesu.createPrivateTransactionEnabledNode( restriction + "-transaction-node", - privacyAccountResolver.resolve(1), + PrivacyAccountResolver.BOB.resolve(enclaveEncryptorType), enclaveType, Optional.of(containerNetwork), false, diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateGenesisAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateGenesisAcceptanceTest.java index 531e0064511..29d5b655e3c 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateGenesisAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateGenesisAcceptanceTest.java @@ -22,6 +22,7 @@ import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode; import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver; import org.hyperledger.besu.tests.web3j.generated.EventEmitter; +import org.hyperledger.enclave.testutil.EnclaveEncryptorType; import org.hyperledger.enclave.testutil.EnclaveType; import java.io.IOException; @@ -38,15 +39,18 @@ public class PrivateGenesisAcceptanceTest extends ParameterizedEnclaveTestBase { private final PrivacyNode alice; - public PrivateGenesisAcceptanceTest(final Restriction restriction, final EnclaveType enclaveType) + public PrivateGenesisAcceptanceTest( + final Restriction restriction, + final EnclaveType enclaveType, + final EnclaveEncryptorType enclaveEncryptorType) throws IOException { - super(restriction, enclaveType); + super(restriction, enclaveType, enclaveEncryptorType); alice = privacyBesu.createIbft2NodePrivacyEnabledWithGenesis( "node1", - PrivacyAccountResolver.ALICE, + PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType), true, enclaveType, Optional.empty(), diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateLogFilterAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateLogFilterAcceptanceTest.java index 7d8c8d6209d..a6837f95465 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateLogFilterAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateLogFilterAcceptanceTest.java @@ -22,6 +22,7 @@ import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver; import org.hyperledger.besu.tests.acceptance.dsl.privacy.util.LogFilterJsonParameter; import org.hyperledger.besu.tests.web3j.generated.EventEmitter; +import org.hyperledger.enclave.testutil.EnclaveEncryptorType; import org.hyperledger.enclave.testutil.EnclaveType; import java.io.IOException; @@ -41,14 +42,17 @@ public class PrivateLogFilterAcceptanceTest extends ParameterizedEnclaveTestBase private final PrivacyNode node; public PrivateLogFilterAcceptanceTest( - final Restriction restriction, final EnclaveType enclaveType) throws IOException { + final Restriction restriction, + final EnclaveType enclaveType, + final EnclaveEncryptorType enclaveEncryptorType) + throws IOException { - super(restriction, enclaveType); + super(restriction, enclaveType, enclaveEncryptorType); node = privacyBesu.createPrivateTransactionEnabledMinerNode( restriction + "-node", - PrivacyAccountResolver.ALICE, + PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType), enclaveType, Optional.empty(), false, diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/FlexibleMultiTenancyAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/FlexibleMultiTenancyAcceptanceTest.java index 80dcf7a0a45..7907c37a110 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/FlexibleMultiTenancyAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/FlexibleMultiTenancyAcceptanceTest.java @@ -28,6 +28,7 @@ import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.PrivacyRequestFactory; import org.hyperledger.besu.tests.acceptance.privacy.FlexiblePrivacyAcceptanceTestBase; import org.hyperledger.besu.tests.web3j.generated.EventEmitter; +import org.hyperledger.enclave.testutil.EnclaveEncryptorType; import org.hyperledger.enclave.testutil.EnclaveType; import java.math.BigInteger; @@ -73,7 +74,11 @@ public static Collection enclaveTypes() { public void setUp() throws Exception { alice = privacyBesu.createFlexiblePrivacyGroupEnabledMinerNode( - "node1", PrivacyAccountResolver.MULTI_TENANCY, true, enclaveType, Optional.empty()); + "node1", + PrivacyAccountResolver.MULTI_TENANCY.resolve(EnclaveEncryptorType.NACL), + true, + enclaveType, + Optional.empty()); final BesuNode aliceBesu = alice.getBesu(); privacyCluster.startNodes(alice); final String alice1Token = diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index 9bada97133d..a6a5b5b2657 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -2024,10 +2024,6 @@ private String readEnclaveKey() { "--privacy-public-key-file must be set if isQuorum is set in the genesis file.", e); } - if (key.length() != 44) { - throw new IllegalArgumentException( - "Contents of enclave public key file needs to be 44 characters long to decode to a valid 32 byte public key."); - } // throws exception if invalid base 64 Base64.getDecoder().decode(key); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index 3ab6e7bbc7c..1e040e39adf 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -4826,7 +4826,8 @@ public void privEnclaveKeyFileInvalidContentTooShort() throws IOException { assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)) .startsWith("Contents of privacy-public-key-file invalid"); - assertThat(commandErrorOutput.toString(UTF_8)).contains("needs to be 44 characters long"); + assertThat(commandErrorOutput.toString(UTF_8)) + .contains("Last unit does not have enough valid bits"); } @Test diff --git a/enclave/src/main/java/org/hyperledger/besu/enclave/Enclave.java b/enclave/src/main/java/org/hyperledger/besu/enclave/Enclave.java index 58bc7101fc1..f1d54f9b1a8 100644 --- a/enclave/src/main/java/org/hyperledger/besu/enclave/Enclave.java +++ b/enclave/src/main/java/org/hyperledger/besu/enclave/Enclave.java @@ -195,9 +195,9 @@ private byte[] processTesseraError(final String errorMsg, final Class res private String removeBase64(final String input) { if (input.contains("=")) { - final String startInclBase64 = input.substring(0, input.indexOf('=')); + final String startInclBase64 = input.substring(0, input.lastIndexOf('=')); final String startTrimmed = startInclBase64.substring(0, startInclBase64.lastIndexOf(" ")); - final String end = input.substring(input.indexOf("=")); + final String end = input.substring(input.lastIndexOf("=")); if (end.length() > 1) { // Base64 in middle return startTrimmed + end.substring(1); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/PrivacyParameters.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/PrivacyParameters.java index 845aebddbda..fe75a5776a3 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/PrivacyParameters.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/PrivacyParameters.java @@ -339,7 +339,8 @@ public Builder setGoQuorumPrivacyParameters( public Builder setPrivacyUserIdUsingFile(final File publicKeyFile) throws IOException { this.enclavePublicKeyFile = publicKeyFile; this.privacyUserId = Files.asCharSource(publicKeyFile, UTF_8).read(); - validatePublicKey(publicKeyFile); + // throws exception if invalid base 64 + Base64.getDecoder().decode(this.privacyUserId); return this; } @@ -400,14 +401,5 @@ public PrivacyParameters build() { config.setGoQuorumPrivacyParameters(goQuorumPrivacyParameters); return config; } - - private void validatePublicKey(final File publicKeyFile) { - if (publicKeyFile.length() != 44) { - throw new IllegalArgumentException( - "Contents of enclave public key file needs to be 44 characters long to decode to a valid 32 byte public key."); - } - // throws exception if invalid base 64 - Base64.getDecoder().decode(this.privacyUserId); - } } } diff --git a/testutil/src/main/java/org/hyperledger/enclave/testutil/EnclaveConfiguration.java b/testutil/src/main/java/org/hyperledger/enclave/testutil/EnclaveConfiguration.java index 80dacbc6376..1e86234d70a 100644 --- a/testutil/src/main/java/org/hyperledger/enclave/testutil/EnclaveConfiguration.java +++ b/testutil/src/main/java/org/hyperledger/enclave/testutil/EnclaveConfiguration.java @@ -22,6 +22,7 @@ public class EnclaveConfiguration { private final Path[] publicKeys; private final Path[] privateKeys; + private final EnclaveEncryptorType enclaveEncryptorType; private final Path tempDir; private final List otherNodes = new ArrayList<>(); private final boolean clearKnownNodes; @@ -32,6 +33,7 @@ public EnclaveConfiguration( final String name, final Path[] publicKeys, final Path[] privateKeys, + final EnclaveEncryptorType enclaveEncryptorType, final Path tempDir, final List otherNodes, final boolean clearKnownNodes, @@ -39,6 +41,7 @@ public EnclaveConfiguration( this.publicKeys = publicKeys; this.privateKeys = privateKeys; + this.enclaveEncryptorType = enclaveEncryptorType; this.tempDir = tempDir; this.otherNodes.addAll(otherNodes); this.clearKnownNodes = clearKnownNodes; @@ -77,4 +80,8 @@ public String getStorage() { public String getName() { return name; } + + public EnclaveEncryptorType getEnclaveEncryptorType() { + return enclaveEncryptorType; + } } diff --git a/testutil/src/main/java/org/hyperledger/enclave/testutil/EnclaveEncryptorType.java b/testutil/src/main/java/org/hyperledger/enclave/testutil/EnclaveEncryptorType.java new file mode 100644 index 00000000000..e0dc61f1715 --- /dev/null +++ b/testutil/src/main/java/org/hyperledger/enclave/testutil/EnclaveEncryptorType.java @@ -0,0 +1,44 @@ +/* + * Copyright ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.enclave.testutil; + +public enum EnclaveEncryptorType { + NACL, + EC, + NOOP; + + public String toTesseraEncryptorConfigJSON() { + switch (this) { + case NACL: + return " \"encryptor\":{\n" + + " \"type\":\"NACL\",\n" + + " \"properties\":{\n" + + " }\n" + + " },\n"; + case EC: + return " \"encryptor\":{\n" + + " \"type\":\"EC\",\n" + + " \"properties\":{\n" + + " \"symmetricCipher\": \"AES/GCM/NoPadding\",\n" + + " \"ellipticCurve\": \"secp256r1\",\n" + + " \"nonceLength\": \"24\",\n" + + " \"sharedKeyLength\": \"32\"\n" + + " }\n" + + " },\n"; + default: + return ""; + } + } +} diff --git a/testutil/src/main/java/org/hyperledger/enclave/testutil/EnclaveKeyConfiguration.java b/testutil/src/main/java/org/hyperledger/enclave/testutil/EnclaveKeyConfiguration.java index cb739ac44cc..929f2ac489e 100644 --- a/testutil/src/main/java/org/hyperledger/enclave/testutil/EnclaveKeyConfiguration.java +++ b/testutil/src/main/java/org/hyperledger/enclave/testutil/EnclaveKeyConfiguration.java @@ -17,15 +17,24 @@ public class EnclaveKeyConfiguration { private final String[] pubKeyPaths; private final String[] privKeyPaths; + private EnclaveEncryptorType enclaveEncryptorType; public EnclaveKeyConfiguration(final String pubKeyPath, final String privKeyPath) { this.pubKeyPaths = new String[] {pubKeyPath}; this.privKeyPaths = new String[] {privKeyPath}; } - public EnclaveKeyConfiguration(final String[] pubKeyPaths, final String[] privKeyPaths) { + public EnclaveKeyConfiguration( + final String[] pubKeyPaths, + final String[] privKeyPaths, + final EnclaveEncryptorType enclaveEncryptorType) { this.pubKeyPaths = pubKeyPaths; this.privKeyPaths = privKeyPaths; + this.enclaveEncryptorType = enclaveEncryptorType; + } + + public EnclaveKeyConfiguration(final String[] pubKeyPaths, final String[] privKeyPaths) { + this(pubKeyPaths, privKeyPaths, EnclaveEncryptorType.NACL); } public String[] getPubKeyPaths() { @@ -35,4 +44,8 @@ public String[] getPubKeyPaths() { public String[] getPrivKeyPaths() { return privKeyPaths; } + + public EnclaveEncryptorType getEnclaveEncryptorType() { + return enclaveEncryptorType; + } } diff --git a/testutil/src/main/java/org/hyperledger/enclave/testutil/TesseraTestHarness.java b/testutil/src/main/java/org/hyperledger/enclave/testutil/TesseraTestHarness.java index 4d50f285ebb..e8117e60f0a 100644 --- a/testutil/src/main/java/org/hyperledger/enclave/testutil/TesseraTestHarness.java +++ b/testutil/src/main/java/org/hyperledger/enclave/testutil/TesseraTestHarness.java @@ -163,11 +163,7 @@ private String createConfigFile(final String nodeName) { String confString = "{\n" + " \"mode\" : \"orion\",\n" - + " \"encryptor\":{\n" - + " \"type\":\"NACL\",\n" - + " \"properties\":{\n" - + " }\n" - + " },\n" + + enclaveConfiguration.getEnclaveEncryptorType().toTesseraEncryptorConfigJSON() + " \"useWhiteList\": false,\n" + " \"jdbc\": {\n" + " \"username\": \"sa\",\n" diff --git a/testutil/src/main/java/org/hyperledger/enclave/testutil/TesseraTestHarnessFactory.java b/testutil/src/main/java/org/hyperledger/enclave/testutil/TesseraTestHarnessFactory.java index e5c7100e91e..fb76533c0fd 100644 --- a/testutil/src/main/java/org/hyperledger/enclave/testutil/TesseraTestHarnessFactory.java +++ b/testutil/src/main/java/org/hyperledger/enclave/testutil/TesseraTestHarnessFactory.java @@ -39,6 +39,7 @@ public static TesseraTestHarness create( tempDir, enclaveConfig.getPubKeyPaths(), enclaveConfig.getPrivKeyPaths(), + enclaveConfig.getEnclaveEncryptorType(), Collections.emptyList(), containerNetwork); } @@ -48,12 +49,14 @@ public static TesseraTestHarness create( final Path tempDir, final String[] pubKeyPaths, final String[] privKeyPaths, + final EnclaveEncryptorType enclaveEncryptorType, final List othernodes, final Optional containerNetwork) { final Path[] pubKeys = stringArrayToPathArray(tempDir, pubKeyPaths); final Path[] privKeys = stringArrayToPathArray(tempDir, privKeyPaths); - return create(name, tempDir, pubKeys, privKeys, othernodes, containerNetwork); + return create( + name, tempDir, pubKeys, privKeys, enclaveEncryptorType, othernodes, containerNetwork); } public static TesseraTestHarness create( @@ -61,10 +64,12 @@ public static TesseraTestHarness create( final Path tempDir, final Path[] key1pubs, final Path[] key1keys, + final EnclaveEncryptorType enclaveEncryptorType, final List othernodes, final Optional containerNetwork) { return new TesseraTestHarness( - new EnclaveConfiguration(name, key1pubs, key1keys, tempDir, othernodes, false, storage), + new EnclaveConfiguration( + name, key1pubs, key1keys, enclaveEncryptorType, tempDir, othernodes, false, storage), containerNetwork); } diff --git a/testutil/src/main/resources/enclave_ec_key_0.key b/testutil/src/main/resources/enclave_ec_key_0.key new file mode 100644 index 00000000000..65bfc50034b --- /dev/null +++ b/testutil/src/main/resources/enclave_ec_key_0.key @@ -0,0 +1 @@ +{"data":{"bytes":"MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCA3i4I2sXNvZ/oP+faqfqFVKhc3lIthuqa5nczOMMmjVg=="},"type":"unlocked"} \ No newline at end of file diff --git a/testutil/src/main/resources/enclave_ec_key_0.pub b/testutil/src/main/resources/enclave_ec_key_0.pub new file mode 100644 index 00000000000..aeb0cc0c4af --- /dev/null +++ b/testutil/src/main/resources/enclave_ec_key_0.pub @@ -0,0 +1 @@ +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAES8nC4qT/KdoAoTSF3qs/47DUsDihyVbWiRjZAiyvqp9eSDkqV1RzlM+58oOwnpFRwvWNZM+AxMVxT+MvxdsqMA== \ No newline at end of file diff --git a/testutil/src/main/resources/enclave_ec_key_1.key b/testutil/src/main/resources/enclave_ec_key_1.key new file mode 100644 index 00000000000..56cc7cc0d8c --- /dev/null +++ b/testutil/src/main/resources/enclave_ec_key_1.key @@ -0,0 +1 @@ +{"data":{"bytes":"MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCA/80gy3GG2gCdmCk3Xp4hcO06c3OomIf+aH3oZGVSYfQ=="},"type":"unlocked"} \ No newline at end of file diff --git a/testutil/src/main/resources/enclave_ec_key_1.pub b/testutil/src/main/resources/enclave_ec_key_1.pub new file mode 100644 index 00000000000..3c565ec7de5 --- /dev/null +++ b/testutil/src/main/resources/enclave_ec_key_1.pub @@ -0,0 +1 @@ +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXIgZqRA25V+3nN+Do6b5r0jiUunub6ubjPhqwHpPxP44uUYh9RKCQNRnsqCJ9PjeTnC8R3ieJk7HWAlycU1bug== \ No newline at end of file diff --git a/testutil/src/main/resources/enclave_ec_key_2.key b/testutil/src/main/resources/enclave_ec_key_2.key new file mode 100644 index 00000000000..a6f675e7e7f --- /dev/null +++ b/testutil/src/main/resources/enclave_ec_key_2.key @@ -0,0 +1 @@ +{"data":{"bytes":"MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCC64DUSx9FrS2wHVOa1CWMStiq1jo2u7Oef0hzpgOK+8w=="},"type":"unlocked"} \ No newline at end of file diff --git a/testutil/src/main/resources/enclave_ec_key_2.pub b/testutil/src/main/resources/enclave_ec_key_2.pub new file mode 100644 index 00000000000..5700cbd07e7 --- /dev/null +++ b/testutil/src/main/resources/enclave_ec_key_2.pub @@ -0,0 +1 @@ +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFl85WnNPyzSEX+evc774xoqUQdjSnQMTE1uIyMOve+iVwjs6dUEUwz5teiKuUUf63a/qYe4n6SGnQ7HnmtDViQ== \ No newline at end of file From 37e0e0478e594286cd5bc4c39f3b9fa10f5261e8 Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Tue, 9 Aug 2022 14:17:17 +1000 Subject: [PATCH 074/109] lower bound peer limit (#4200) * introducing a lower bound on number of peers * added lower bound CLI option Signed-off-by: Sally MacFarlane Signed-off-by: Roman Vaseev <4833306+Filter94@users.noreply.github.com> Co-authored-by: Roman Vaseev <4833306+Filter94@users.noreply.github.com> Co-authored-by: Justin Florentine --- CHANGELOG.md | 1 + .../dsl/node/ThreadBesuNodeRunner.java | 2 + .../org/hyperledger/besu/RunnerBuilder.java | 13 +++- .../org/hyperledger/besu/cli/BesuCommand.java | 23 ++++++- .../besu/cli/DefaultCommandValues.java | 1 + .../options/unstable/NetworkingOptions.java | 10 +++ .../hyperledger/besu/cli/BesuCommandTest.java | 41 ++++++++++++ .../besu/cli/CommandTestAbstract.java | 1 + .../cli/options/NetworkingOptionsTest.java | 27 ++++++++ .../eth/manager/EthProtocolManager.java | 2 + .../p2p/config/RlpxConfiguration.java | 24 +++++-- .../p2p/network/DefaultP2PNetwork.java | 6 +- .../besu/ethereum/p2p/rlpx/RlpxAgent.java | 52 ++++++++------ .../p2p/config/RlpxConfigurationTest.java | 8 +-- .../ethereum/p2p/network/P2PNetworkTest.java | 2 +- .../p2p/network/P2PPlainNetworkTest.java | 2 +- .../besu/ethereum/p2p/rlpx/RlpxAgentTest.java | 67 ++++++++++++------- 17 files changed, 223 insertions(+), 59 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e55536c6bde..364d6168a6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 22.7.1 ### Additions and Improvements +- Add experimental CLI option for `--Xp2p-peer-lower-bound` [#4200](https://github.com/hyperledger/besu/pull/4200) ### Bug Fixes - Fixes off-by-one error for mainnet TTD fallback [#4223](https://github.com/hyperledger/besu/pull/4223) diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java index 35c1a69c381..b0ca91315ad 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java @@ -161,6 +161,7 @@ public void startNode(final BesuNode node) { .build(); final int maxPeers = 25; + final int minPeers = 25; builder .synchronizerConfiguration(new SynchronizerConfiguration.Builder().build()) @@ -198,6 +199,7 @@ public void startNode(final BesuNode node) { .p2pAdvertisedHost(node.getHostName()) .p2pListenPort(0) .maxPeers(maxPeers) + .minPeers(minPeers) .networkingConfiguration(node.getNetworkingConfiguration()) .jsonRpcConfiguration(node.jsonRpcConfiguration()) .webSocketConfiguration(node.webSocketConfiguration()) diff --git a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java index d8b1a38fc20..f50f64a7e7e 100644 --- a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java @@ -165,6 +165,7 @@ public class RunnerBuilder { private String natManagerServiceName; private boolean natMethodFallbackEnabled; private int maxPeers; + private int minPeers; private boolean limitRemoteWireConnectionsEnabled = false; private float fractionRemoteConnectionsAllowed; private EthNetworkConfig ethNetworkConfig; @@ -444,7 +445,8 @@ public Runner build() { RlpxConfiguration.create() .setBindHost(p2pListenInterface) .setBindPort(p2pListenPort) - .setMaxPeers(maxPeers) + .setPeerUpperBound(maxPeers) + .setPeerLowerBound(minPeers) .setSupportedProtocols(subProtocols) .setClientId(BesuInfo.nodeName(identityString)) .setLimitRemoteWireConnectionsEnabled(limitRemoteWireConnectionsEnabled) @@ -1157,4 +1159,13 @@ private Optional createMetricsService( final Vertx vertx, final MetricsConfiguration configuration) { return MetricsService.create(vertx, configuration, metricsSystem); } + + public int getMinPeers() { + return minPeers; + } + + public RunnerBuilder minPeers(final int minPeers) { + this.minPeers = minPeers; + return this; + } } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index a6a5b5b2657..d1ec8d28b15 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -424,11 +424,13 @@ static class P2PDiscoveryOptionGroup { private final Integer p2pPort = EnodeURLImpl.DEFAULT_LISTENING_PORT; @Option( - names = {"--max-peers"}, + names = {"--max-peers", "--p2p-peer-upper-bound"}, paramLabel = MANDATORY_INTEGER_FORMAT_HELP, description = "Maximum P2P connections that can be established (default: ${DEFAULT-VALUE})") private final Integer maxPeers = DEFAULT_MAX_PEERS; + private int minPeers; + @Option( names = {"--remote-connections-limit-enabled"}, description = @@ -1602,6 +1604,7 @@ private Runner buildRunner() { p2PDiscoveryOptionGroup.peerDiscoveryEnabled, ethNetworkConfig, p2PDiscoveryOptionGroup.maxPeers, + p2PDiscoveryOptionGroup.minPeers, p2PDiscoveryOptionGroup.p2pHost, p2PDiscoveryOptionGroup.p2pInterface, p2PDiscoveryOptionGroup.p2pPort, @@ -1724,6 +1727,7 @@ private void validateOptions() { validateNatParams(); validateNetStatsParams(); validateDnsOptionsParams(); + ensureValidPeerBoundParams(); validateRpcOptionsParams(); p2pTLSConfigOptions.checkP2PTLSOptionsDependencies(logger, commandLine); pkiBlockCreationOptions.checkPkiBlockCreationOptionsDependencies(logger, commandLine); @@ -1796,6 +1800,21 @@ private void validateDnsOptionsParams() { } } + private void ensureValidPeerBoundParams() { + final int min = unstableNetworkingOptions.toDomainObject().getRlpx().getPeerLowerBound(); + final int max = p2PDiscoveryOptionGroup.maxPeers; + if (min > max) { + logger.warn("`--Xp2p-peer-lower-bound` " + min + " must not exceed --max-peers " + max); + // modify the --X lower-bound value if it's not valid, we don't want unstable defaults + // breaking things + logger.warn("setting --Xp2p-peer-lower-bound=" + max); + unstableNetworkingOptions.toDomainObject().getRlpx().setPeerLowerBound(max); + p2PDiscoveryOptionGroup.minPeers = max; + } else { + p2PDiscoveryOptionGroup.minPeers = min; + } + } + public void validateRpcOptionsParams() { Predicate configuredApis = apiName -> @@ -2770,6 +2789,7 @@ private Runner synchronize( final boolean peerDiscoveryEnabled, final EthNetworkConfig ethNetworkConfig, final int maxPeers, + final int minPeers, final String p2pAdvertisedHost, final String p2pListenInterface, final int p2pListenPort, @@ -2804,6 +2824,7 @@ private Runner synchronize( .p2pListenInterface(p2pListenInterface) .p2pListenPort(p2pListenPort) .maxPeers(maxPeers) + .minPeers(minPeers) .limitRemoteWireConnectionsEnabled( p2PDiscoveryOptionGroup.isLimitRemoteWireConnectionsEnabled) .fractionRemoteConnectionsAllowed( diff --git a/besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java b/besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java index 3b439180a99..2ca3b5d7ab1 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java @@ -58,6 +58,7 @@ public interface DefaultCommandValues { JwtAlgorithm DEFAULT_JWT_ALGORITHM = JwtAlgorithm.RS256; int FAST_SYNC_MIN_PEER_COUNT = 5; int DEFAULT_MAX_PEERS = 25; + int DEFAULT_P2P_PEER_LOWER_BOUND = 25; int DEFAULT_HTTP_MAX_CONNECTIONS = 80; int DEFAULT_WS_MAX_CONNECTIONS = 80; int DEFAULT_WS_MAX_FRAME_SIZE = 1024 * 1024; diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/NetworkingOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/NetworkingOptions.java index a737883f74b..88e899cac88 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/NetworkingOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/NetworkingOptions.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.cli.options.unstable; +import org.hyperledger.besu.cli.DefaultCommandValues; import org.hyperledger.besu.cli.options.CLIOptions; import org.hyperledger.besu.cli.options.OptionParser; import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration; @@ -31,6 +32,7 @@ public class NetworkingOptions implements CLIOptions { "--Xp2p-check-maintained-connections-frequency"; private final String DNS_DISCOVERY_SERVER_OVERRIDE_FLAG = "--Xp2p-dns-discovery-server"; private final String DISCOVERY_PROTOCOL_V5_ENABLED = "--Xv5-discovery-enabled"; + private final String P2P_PEER_LOWER_BOUND_FLAG = "--Xp2p-peer-lower-bound"; @CommandLine.Option( names = INITIATE_CONNECTIONS_FREQUENCY_FLAG, @@ -66,6 +68,13 @@ public class NetworkingOptions implements CLIOptions { description = "Whether to enable P2P Discovery Protocol v5 (default: ${DEFAULT-VALUE})") private final Boolean isPeerDiscoveryV5Enabled = false; + @CommandLine.Option( + hidden = true, + names = {P2P_PEER_LOWER_BOUND_FLAG}, + description = + "Lower bound on the target number of P2P connections (default: ${DEFAULT-VALUE})") + private final Integer peerLowerBound = DefaultCommandValues.DEFAULT_P2P_PEER_LOWER_BOUND; + private NetworkingOptions() {} public static NetworkingOptions create() { @@ -90,6 +99,7 @@ public NetworkingConfiguration toDomainObject() { config.setInitiateConnectionsFrequency(initiateConnectionsFrequencySec); config.setDnsDiscoveryServerOverride(dnsDiscoveryServerOverride); config.getDiscovery().setDiscoveryV5Enabled(isPeerDiscoveryV5Enabled); + config.getRlpx().setPeerLowerBound(peerLowerBound); return config; } diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index 1e040e39adf..984b412354e 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -1542,6 +1542,47 @@ public void maxpeersOptionMustBeUsed() { assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); } + @Test + public void p2pPeerUpperBound_without_p2pPeerLowerBound_shouldSetLowerBoundEqualToUpperBound() { + + final int maxPeers = 23; + parseCommand("--p2p-peer-upper-bound", String.valueOf(maxPeers)); + + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + + verify(mockRunnerBuilder).maxPeers(intArgumentCaptor.capture()); + assertThat(intArgumentCaptor.getValue()).isEqualTo(maxPeers); + + verify(mockRunnerBuilder).minPeers(intArgumentCaptor.capture()); + assertThat(intArgumentCaptor.getValue()).isEqualTo(maxPeers); + + verify(mockRunnerBuilder).build(); + } + + @Test + public void maxpeersSet_p2pPeerLowerBoundSet() { + + final int maxPeers = 123; + final int minPeers = 66; + parseCommand( + "--max-peers", + String.valueOf(maxPeers), + "--Xp2p-peer-lower-bound", + String.valueOf(minPeers)); + + verify(mockRunnerBuilder).maxPeers(intArgumentCaptor.capture()); + assertThat(intArgumentCaptor.getValue()).isEqualTo(maxPeers); + + verify(mockRunnerBuilder).minPeers(intArgumentCaptor.capture()); + assertThat(intArgumentCaptor.getValue()).isEqualTo(minPeers); + + verify(mockRunnerBuilder).build(); + + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + } + @Test public void remoteConnectionsPercentageOptionMustBeUsed() { diff --git a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java index 14fd6dae6a0..649d54efaf6 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java @@ -254,6 +254,7 @@ public void initMocks() throws Exception { when(mockRunnerBuilder.p2pListenInterface(anyString())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.permissioningConfiguration(any())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.maxPeers(anyInt())).thenReturn(mockRunnerBuilder); + when(mockRunnerBuilder.minPeers(anyInt())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.limitRemoteWireConnectionsEnabled(anyBoolean())) .thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.fractionRemoteConnectionsAllowed(anyFloat())) diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/NetworkingOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/NetworkingOptionsTest.java index 330bbc524a1..5c7c5d4a079 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/NetworkingOptionsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/NetworkingOptionsTest.java @@ -16,6 +16,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.cli.DefaultCommandValues.DEFAULT_P2P_PEER_LOWER_BOUND; import org.hyperledger.besu.cli.options.unstable.NetworkingOptions; import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration; @@ -125,6 +126,32 @@ public void checkDiscoveryV5Enabled_isNotSet() { assertThat(commandOutput.toString(UTF_8)).isEmpty(); } + @Test + public void checkP2pPeerLowerBound_isSet() { + final int lowerBound = 13; + final TestBesuCommand cmd = parseCommand("--Xp2p-peer-lower-bound", String.valueOf(lowerBound)); + + final NetworkingOptions options = cmd.getNetworkingOptions(); + final NetworkingConfiguration networkingConfig = options.toDomainObject(); + assertThat(networkingConfig.getRlpx().getPeerLowerBound()).isEqualTo(lowerBound); + + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + } + + @Test + public void checkP2pPeerLowerBound_isNotSet() { + final TestBesuCommand cmd = parseCommand(); + + final NetworkingOptions options = cmd.getNetworkingOptions(); + final NetworkingConfiguration networkingConfig = options.toDomainObject(); + assertThat(networkingConfig.getRlpx().getPeerLowerBound()) + .isEqualTo(DEFAULT_P2P_PEER_LOWER_BOUND); + + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + } + @Override NetworkingConfiguration createDefaultDomainObject() { return NetworkingConfiguration.create(); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java index f065e0b1416..3956ce1cf29 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java @@ -268,6 +268,7 @@ public void processMessage(final Capability cap, final Message message) { if (this.mergePeerFilter.isPresent()) { if (this.mergePeerFilter.get().disconnectIfGossipingBlocks(message, ethPeer)) { + LOG.debug("Post-merge disconnect: peer still gossiping blocks {}", ethPeer); handleDisconnect(ethPeer.getConnection(), DisconnectReason.SUBPROTOCOL_TRIGGERED, false); return; } @@ -389,6 +390,7 @@ private void handleStatusMessage(final EthPeer peer, final MessageData data) { peer.disconnect(DisconnectReason.SUBPROTOCOL_TRIGGERED); } else if (mergePeerFilter.isPresent() && mergePeerFilter.get().disconnectIfPoW(status, peer)) { + LOG.debug("Post-merge disconnect: peer still PoW {}", peer); handleDisconnect(peer.getConnection(), DisconnectReason.SUBPROTOCOL_TRIGGERED, false); } else { LOG.debug("Received status message from {}: {}", peer, status); diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/config/RlpxConfiguration.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/config/RlpxConfiguration.java index 62e7ca96a75..facf2771170 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/config/RlpxConfiguration.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/config/RlpxConfiguration.java @@ -29,7 +29,8 @@ public class RlpxConfiguration { private String clientId = "TestClient/1.0.0"; private String bindHost = NetworkUtility.INADDR_ANY; private int bindPort = 30303; - private int maxPeers = 25; + private int peerUpperBound = 100; + private int peerLowerBound = 64; private boolean limitRemoteWireConnectionsEnabled = false; private float fractionRemoteWireConnectionsAllowed = DEFAULT_FRACTION_REMOTE_CONNECTIONS_ALLOWED; private List supportedProtocols = Collections.emptyList(); @@ -70,13 +71,13 @@ public RlpxConfiguration setBindPort(final int bindPort) { return this; } - public RlpxConfiguration setMaxPeers(final int peers) { - maxPeers = peers; + public RlpxConfiguration setPeerUpperBound(final int peers) { + peerUpperBound = peers; return this; } - public int getMaxPeers() { - return maxPeers; + public int getPeerUpperBound() { + return peerUpperBound; } public String getClientId() { @@ -105,10 +106,10 @@ public RlpxConfiguration setFractionRemoteWireConnectionsAllowed( public int getMaxRemotelyInitiatedConnections() { if (!limitRemoteWireConnectionsEnabled) { - return maxPeers; + return peerUpperBound; } - return (int) Math.floor(maxPeers * fractionRemoteWireConnectionsAllowed); + return (int) Math.floor(peerUpperBound * fractionRemoteWireConnectionsAllowed); } @Override @@ -136,4 +137,13 @@ public String toString() { sb.append('}'); return sb.toString(); } + + public RlpxConfiguration setPeerLowerBound(final int peers) { + peerLowerBound = peers; + return this; + } + + public int getPeerLowerBound() { + return peerLowerBound; + } } diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java index 2efdb8cbc0d..35b29c89b43 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java @@ -185,8 +185,10 @@ public class DefaultP2PNetwork implements P2PNetwork { this.nodeId = nodeKey.getPublicKey().getEncodedBytes(); this.peerPermissions = peerPermissions; - final int maxPeers = config.getRlpx().getMaxPeers(); - peerDiscoveryAgent.addPeerRequirement(() -> rlpxAgent.getConnectionCount() >= maxPeers); + // set the requirement here that the number of peers be greater than the lower bound + final int peerLowerBound = config.getRlpx().getPeerLowerBound(); + LOG.debug("setting peerLowerBound {}", peerLowerBound); + peerDiscoveryAgent.addPeerRequirement(() -> rlpxAgent.getConnectionCount() >= peerLowerBound); subscribeDisconnect(reputationManager); } diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgent.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgent.java index 38c85dbffb8..b9db0cbf0df 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgent.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgent.java @@ -69,7 +69,8 @@ public class RlpxAgent { private final PeerRlpxPermissions peerPermissions; private final PeerPrivileges peerPrivileges; - private final int maxConnections; + private final int upperBoundConnections; + private final int lowerBoundConnections; private final boolean randomPeerPriority; private final int maxRemotelyInitiatedConnections; // xor'ing with this mask will allow us to randomly let new peers connect @@ -89,7 +90,8 @@ private RlpxAgent( final ConnectionInitializer connectionInitializer, final PeerRlpxPermissions peerPermissions, final PeerPrivileges peerPrivileges, - final int maxConnections, + final int upperBoundConnections, + final int lowerBoundConnections, final int maxRemotelyInitiatedConnections, final boolean randomPeerPriority, final MetricsSystem metricsSystem) { @@ -98,10 +100,11 @@ private RlpxAgent( this.connectionInitializer = connectionInitializer; this.peerPermissions = peerPermissions; this.peerPrivileges = peerPrivileges; - this.maxConnections = maxConnections; + this.upperBoundConnections = upperBoundConnections; + this.lowerBoundConnections = lowerBoundConnections; this.randomPeerPriority = randomPeerPriority; this.maxRemotelyInitiatedConnections = - Math.min(maxConnections, maxRemotelyInitiatedConnections); + Math.min(upperBoundConnections, maxRemotelyInitiatedConnections); // Setup metrics connectedPeersCounter = @@ -117,7 +120,7 @@ private RlpxAgent( BesuMetricCategory.ETHEREUM, "peer_limit", "The maximum number of peers this node allows to connect", - () -> maxConnections); + () -> upperBoundConnections); } public static Builder builder() { @@ -174,7 +177,7 @@ public void connect(final Stream peerStream) { return; } peerStream - .takeWhile(peer -> Math.max(0, maxConnections - getConnectionCount()) > 0) + .takeWhile(peer -> Math.max(0, lowerBoundConnections - getConnectionCount()) > 0) .filter(peer -> !connectionsById.containsKey(peer.getId())) .filter(peer -> peer.getEnodeURL().isListening()) .filter(peerPermissions::allowNewOutboundConnectionTo) @@ -233,10 +236,11 @@ public CompletableFuture connect(final Peer peer) { return peerConnection.get(); } // Check max peers - if (!peerPrivileges.canExceedConnectionLimits(peer) && getConnectionCount() >= maxConnections) { + if (!peerPrivileges.canExceedConnectionLimits(peer) + && getConnectionCount() >= upperBoundConnections) { final String errorMsg = "Max peer connections established (" - + maxConnections + + upperBoundConnections + "). Cannot connect to peer: " + peer; return CompletableFuture.failedFuture(new IllegalStateException(errorMsg)); @@ -360,16 +364,21 @@ private void handleIncomingConnection(final PeerConnection peerConnection) { if (!randomPeerPriority) { // Disconnect if too many peers if (!peerPrivileges.canExceedConnectionLimits(peer) - && getConnectionCount() >= maxConnections) { - LOG.debug("Too many peers. Disconnect incoming connection: {}", peerConnection); + && getConnectionCount() >= upperBoundConnections) { + LOG.debug( + "Too many peers. Disconnect incoming connection: {} currentCount {}, max {}", + peerConnection, + getConnectionCount(), + upperBoundConnections); peerConnection.disconnect(DisconnectReason.TOO_MANY_PEERS); return; } // Disconnect if too many remotely-initiated connections if (!peerPrivileges.canExceedConnectionLimits(peer) && remoteConnectionLimitReached()) { LOG.debug( - "Too many remotely-initiated connections. Disconnect incoming connection: {}", - peerConnection); + "Too many remotely-initiated connections. Disconnect incoming connection: {}, maxRemote={}", + peerConnection, + maxRemotelyInitiatedConnections); peerConnection.disconnect(DisconnectReason.TOO_MANY_PEERS); return; } @@ -431,7 +440,7 @@ && getConnectionCount() >= maxConnections) { } private boolean shouldLimitRemoteConnections() { - return maxRemotelyInitiatedConnections < maxConnections; + return maxRemotelyInitiatedConnections < upperBoundConnections; } private boolean remoteConnectionLimitReached() { @@ -461,24 +470,28 @@ private void enforceRemoteConnectionLimits() { .forEach( conn -> { LOG.debug( - "Too many remotely initiated connections. Disconnect low-priority connection: {}", - conn); + "Too many remotely initiated connections. Disconnect low-priority connection: {}, maxRemote={}", + conn, + maxRemotelyInitiatedConnections); conn.disconnect(DisconnectReason.TOO_MANY_PEERS); }); } private void enforceConnectionLimits() { - if (connectionsById.size() < maxConnections) { + if (connectionsById.size() < upperBoundConnections) { // Nothing to do - we're under our limits return; } getActivePrioritizedConnections() - .skip(maxConnections) + .skip(upperBoundConnections) .filter(c -> !peerPrivileges.canExceedConnectionLimits(c.getPeer())) .forEach( conn -> { - LOG.debug("Too many connections. Disconnect low-priority connection: {}", conn); + LOG.debug( + "Too many connections. Disconnect low-priority connection: {}, maxConnections={}", + conn, + upperBoundConnections); conn.disconnect(DisconnectReason.TOO_MANY_PEERS); }); } @@ -609,7 +622,8 @@ public RlpxAgent build() { connectionInitializer, rlpxPermissions, peerPrivileges, - config.getMaxPeers(), + config.getPeerUpperBound(), + config.getPeerLowerBound(), config.getMaxRemotelyInitiatedConnections(), randomPeerPriority, metricsSystem); diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/config/RlpxConfigurationTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/config/RlpxConfigurationTest.java index f0a8106ff4a..5cfe0bab7d7 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/config/RlpxConfigurationTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/config/RlpxConfigurationTest.java @@ -26,7 +26,7 @@ public void getMaxRemotelyInitiatedConnections_remoteLimitsDisabled() { RlpxConfiguration.create() .setFractionRemoteWireConnectionsAllowed(.5f) .setLimitRemoteWireConnectionsEnabled(false) - .setMaxPeers(20); + .setPeerUpperBound(20); assertThat(config.getMaxRemotelyInitiatedConnections()).isEqualTo(20); } @@ -37,7 +37,7 @@ public void getMaxRemotelyInitiatedConnections_remoteLimitsEnabled() { RlpxConfiguration.create() .setFractionRemoteWireConnectionsAllowed(.5f) .setLimitRemoteWireConnectionsEnabled(true) - .setMaxPeers(20); + .setPeerUpperBound(20); assertThat(config.getMaxRemotelyInitiatedConnections()).isEqualTo(10); } @@ -48,7 +48,7 @@ public void getMaxRemotelyInitiatedConnections_remoteLimitsEnabledWithNonInteger RlpxConfiguration.create() .setFractionRemoteWireConnectionsAllowed(.5f) .setLimitRemoteWireConnectionsEnabled(true) - .setMaxPeers(25); + .setPeerUpperBound(25); assertThat(config.getMaxRemotelyInitiatedConnections()).isEqualTo(12); } @@ -59,7 +59,7 @@ public void getMaxRemotelyInitiatedConnections_remoteLimitsEnabledRoundsToZero() RlpxConfiguration.create() .setFractionRemoteWireConnectionsAllowed(.5f) .setLimitRemoteWireConnectionsEnabled(true) - .setMaxPeers(1); + .setPeerUpperBound(1); assertThat(config.getMaxRemotelyInitiatedConnections()).isEqualTo(0); } diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/P2PNetworkTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/P2PNetworkTest.java index c5aa0193840..55d6ddb7d60 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/P2PNetworkTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/P2PNetworkTest.java @@ -132,7 +132,7 @@ public void limitMaxPeers() throws Exception { .setRlpx( RlpxConfiguration.create() .setBindPort(0) - .setMaxPeers(maxPeers) + .setPeerUpperBound(maxPeers) .setSupportedProtocols(subProtocol())); try (final P2PNetwork listener = builder().nodeKey(nodeKey).config(listenerConfig).build(); final P2PNetwork connector1 = builder().build(); diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/P2PPlainNetworkTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/P2PPlainNetworkTest.java index 3390bc1d3f7..378b5241aac 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/P2PPlainNetworkTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/P2PPlainNetworkTest.java @@ -143,7 +143,7 @@ public void limitMaxPeers() throws Exception { .setRlpx( RlpxConfiguration.create() .setBindPort(0) - .setMaxPeers(maxPeers) + .setPeerUpperBound(maxPeers) .setSupportedProtocols(subProtocol())); try (final P2PNetwork listener = builder("partner1client1").nodeKey(nodeKey).config(listenerConfig).build(); diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgentTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgentTest.java index 8adc5cc3505..07590bf794c 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgentTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgentTest.java @@ -85,7 +85,7 @@ public class RlpxAgentTest { public void setup() { // Set basic defaults when(peerPrivileges.canExceedConnectionLimits(any())).thenReturn(false); - config.setMaxPeers(5); + config.setPeerUpperBound(5); } @Test @@ -283,7 +283,7 @@ public void incomingConnection_deduplicatedWhenAlreadyConnected_peerWithLowerVal @Test public void connect_failsWhenMaxPeersConnected() { // Saturate connections - startAgentWithMaxPeers(1); + startAgentWithLowerBoundPeers(1); agent.connect(createPeer()); final Peer peer = createPeer(); @@ -303,7 +303,7 @@ public void connect_failsWhenMaxPeersConnected() { public void incomingConnection_maxPeersExceeded() throws ExecutionException, InterruptedException { // Saturate connections - startAgentWithMaxPeers(1); + startAgentWithLowerBoundPeers(1); final Peer existingPeer = createPeer(); final PeerConnection existingConnection = agent.connect(existingPeer).get(); // Sanity check @@ -329,7 +329,8 @@ public void incomingConnection_maxPeersExceeded() public void incomingConnection_succeedsEventuallyWithRandomPeerPrioritization() { // Saturate connections with one local and one remote final int maxPeers = 25; - startAgentWithMaxPeers( + startAgentWithLowerBoundPeers( + maxPeers, maxPeers, builder -> builder.randomPeerPriority(true), rlpxConfiguration -> rlpxConfiguration.setLimitRemoteWireConnectionsEnabled(false)); @@ -374,7 +375,7 @@ public void incomingConnection_afterMaxRemotelyInitiatedConnectionsHaveBeenEstab final float maxRemotePeersFraction = (float) maxRemotePeers / (float) maxPeers; config.setLimitRemoteWireConnectionsEnabled(true); config.setFractionRemoteWireConnectionsAllowed(maxRemotePeersFraction); - startAgentWithMaxPeers(maxPeers); + startAgentWithLowerBoundPeers(maxPeers); // Connect max remote peers for (int i = 0; i < maxRemotePeers; i++) { @@ -398,7 +399,7 @@ public void connect_afterMaxRemotelyInitiatedConnectionsHaveBeenEstablished() { final float maxRemotePeersFraction = (float) maxRemotePeers / (float) maxPeers; config.setLimitRemoteWireConnectionsEnabled(true); config.setFractionRemoteWireConnectionsAllowed(maxRemotePeersFraction); - startAgentWithMaxPeers(maxPeers); + startAgentWithLowerBoundPeers(maxPeers); // Connect max remote peers for (int i = 0; i < maxRemotePeers; i++) { @@ -424,7 +425,7 @@ public void incomingConnection_withMaxRemotelyInitiatedConnectionsAt100Percent() final float maxRemotePeersFraction = 1.0f; config.setLimitRemoteWireConnectionsEnabled(true); config.setFractionRemoteWireConnectionsAllowed(maxRemotePeersFraction); - startAgentWithMaxPeers(maxPeers); + startAgentWithLowerBoundPeers(maxPeers); // Connect max remote peers for (int i = 0; i < maxPeers; i++) { @@ -441,7 +442,7 @@ public void connect_withMaxRemotelyInitiatedConnectionsAt100Percent() { final float maxRemotePeersFraction = 1.0f; config.setLimitRemoteWireConnectionsEnabled(true); config.setFractionRemoteWireConnectionsAllowed(maxRemotePeersFraction); - startAgentWithMaxPeers(maxPeers); + startAgentWithLowerBoundPeers(maxPeers); // Connect max peers locally for (int i = 0; i < maxPeers; i++) { @@ -459,7 +460,7 @@ public void incomingConnection_withMaxRemotelyInitiatedConnectionsAtZeroPercent( final float maxRemotePeersFraction = 0.0f; config.setLimitRemoteWireConnectionsEnabled(true); config.setFractionRemoteWireConnectionsAllowed(maxRemotePeersFraction); - startAgentWithMaxPeers(maxPeers); + startAgentWithLowerBoundPeers(maxPeers); // First remote connection should be rejected final Peer remotelyInitiatedPeer = createPeer(); @@ -474,7 +475,7 @@ public void connect_withMaxRemotelyInitiatedConnectionsAtZeroPercent() { final float maxRemotePeersFraction = 0.0f; config.setLimitRemoteWireConnectionsEnabled(true); config.setFractionRemoteWireConnectionsAllowed(maxRemotePeersFraction); - startAgentWithMaxPeers(maxPeers); + startAgentWithLowerBoundPeers(maxPeers); // Connect max local peers for (int i = 0; i < maxPeers; i++) { @@ -493,7 +494,7 @@ public void incomingConnection_succeedsForPrivilegedPeerWhenMaxRemoteConnections final float maxRemotePeersFraction = (float) maxRemotePeers / (float) maxPeers; config.setLimitRemoteWireConnectionsEnabled(true); config.setFractionRemoteWireConnectionsAllowed(maxRemotePeersFraction); - startAgentWithMaxPeers(maxPeers); + startAgentWithLowerBoundPeers(maxPeers); // Connect max remote peers for (int i = 0; i < maxRemotePeers; i++) { @@ -530,7 +531,7 @@ public void connect_succeedsForExemptPeerWhenMaxPeersConnected() connectionInitializer.setAutocompleteConnections(false); // Saturate connections - startAgentWithMaxPeers(1); + startAgentWithLowerBoundPeers(1); final CompletableFuture existingConnectionFuture = agent.connect(createPeer()); connectionInitializer.completePendingFutures(); final MockPeerConnection existingConnection = @@ -557,7 +558,7 @@ public void connect_succeedsForExemptPeerWhenMaxExemptPeersConnected() { // successfully added to the internal connections set. This mimics async production behavior. connectionInitializer.setAutocompleteConnections(false); - startAgentWithMaxPeers(1); + startAgentWithLowerBoundPeers(1); final Peer peerA = createPeer(); final Peer peerB = createPeer(); when(peerPrivileges.canExceedConnectionLimits(peerA)).thenReturn(true); @@ -588,7 +589,7 @@ public void incomingConnection_maxPeersExceeded_incomingConnectionExemptFromLimi when(peerPrivileges.canExceedConnectionLimits(peerB)).thenReturn(true); // Saturate connections - startAgentWithMaxPeers(1); + startAgentWithLowerBoundPeers(1); // Add existing peer final MockPeerConnection existingConnection = (MockPeerConnection) agent.connect(peerA).get(); @@ -615,7 +616,7 @@ public void incomingConnection_maxPeersExceeded_existingConnectionExemptFromLimi when(peerPrivileges.canExceedConnectionLimits(peerA)).thenReturn(true); // Saturate connections - startAgentWithMaxPeers(1); + startAgentWithLowerBoundPeers(1); // Add existing peer final PeerConnection existingConnection = agent.connect(peerA).get(); @@ -643,7 +644,7 @@ public void incomingConnection_maxPeersExceeded_allConnectionsExemptFromLimits() when(peerPrivileges.canExceedConnectionLimits(peerB)).thenReturn(true); // Saturate connections - startAgentWithMaxPeers(1); + startAgentWithLowerBoundPeers(1); // Add existing peer final CompletableFuture existingConnection = agent.connect(peerA); @@ -702,7 +703,7 @@ public void connect_largeStreamOfPeers() { final int maxPeers = 5; final Stream peerStream = Stream.generate(PeerTestHelper::createPeer).limit(20); - startAgentWithMaxPeers(maxPeers); + startAgentWithLowerBoundPeers(maxPeers); agent = spy(agent); agent.connect(peerStream); @@ -711,6 +712,20 @@ public void connect_largeStreamOfPeers() { verify(agent, times(maxPeers)).connect(any(Peer.class)); } + @Test + public void connect_largeStreamOfPeersWithMinAndMaxPeers() { + final int minPeers = 5; + final Stream peerStream = Stream.generate(PeerTestHelper::createPeer).limit(20); + + startAgentWithLowerBoundPeers(minPeers, minPeers + 5); + agent = spy(agent); + agent.connect(peerStream); + + assertThat(agent.getConnectionCount()).isEqualTo(minPeers); + // Check that stream was not fully iterated + verify(agent, times(minPeers)).connect(any(Peer.class)); + } + @Test public void connect_largeStreamOfPeersFirstFewImpostors() { final int maxPeers = 5; @@ -718,7 +733,7 @@ public void connect_largeStreamOfPeersFirstFewImpostors() { connectionInitializer.setAutoDisconnectCounter(impostorsCount); final Stream peerStream = Stream.generate(PeerTestHelper::createPeer).limit(20); - startAgentWithMaxPeers(maxPeers); + startAgentWithLowerBoundPeers(maxPeers); agent = spy(agent); agent.connect(peerStream); @@ -1020,15 +1035,21 @@ private void startAgent() { startAgent(Peer.randomId()); } - private void startAgentWithMaxPeers(final int maxPeers) { - startAgentWithMaxPeers(maxPeers, Function.identity(), __ -> {}); + private void startAgentWithLowerBoundPeers(final int lowerBound, final int upperBound) { + startAgentWithLowerBoundPeers(lowerBound, upperBound, Function.identity(), __ -> {}); + } + + private void startAgentWithLowerBoundPeers(final int lowerBound) { + startAgentWithLowerBoundPeers(lowerBound, lowerBound, Function.identity(), __ -> {}); } - private void startAgentWithMaxPeers( - final int maxPeers, + private void startAgentWithLowerBoundPeers( + final int lowerBound, + final int upperBound, final Function buildCustomization, final Consumer rlpxConfigurationModifier) { - config.setMaxPeers(maxPeers); + config.setPeerLowerBound(lowerBound); + config.setPeerUpperBound(upperBound); agent = agent(buildCustomization, rlpxConfigurationModifier); startAgent(); } From f43b9ade7e5d939cf6861c35d115d8459a724552 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Tue, 9 Aug 2022 12:02:23 -0700 Subject: [PATCH 075/109] remove MergeUnfinalizedRule since consensus layer should be allowed to execute a reorg around an already finalized block. (#4240) Signed-off-by: garyschulte --- .../merge/MergeValidationRulesetFactory.java | 2 - .../MergeUnfinalizedValidationRule.java | 50 -------------- .../MergeUnfinalizedValidationRuleTest.java | 67 ------------------- 3 files changed, 119 deletions(-) delete mode 100644 consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/headervalidationrules/MergeUnfinalizedValidationRule.java delete mode 100644 consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/headervalidationrules/MergeUnfinalizedValidationRuleTest.java diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeValidationRulesetFactory.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeValidationRulesetFactory.java index e5f4f6b82f4..b39b1491191 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeValidationRulesetFactory.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeValidationRulesetFactory.java @@ -19,7 +19,6 @@ import org.hyperledger.besu.consensus.merge.headervalidationrules.ConstantOmmersHashRule; import org.hyperledger.besu.consensus.merge.headervalidationrules.IncrementalTimestampRule; -import org.hyperledger.besu.consensus.merge.headervalidationrules.MergeUnfinalizedValidationRule; import org.hyperledger.besu.consensus.merge.headervalidationrules.NoDifficultyRule; import org.hyperledger.besu.consensus.merge.headervalidationrules.NoNonceRule; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -70,7 +69,6 @@ public static BlockHeaderValidator.Builder mergeBlockHeaderValidator(final FeeMa .addRule(new TimestampBoundedByFutureParameter(TIMESTAMP_TOLERANCE_S)) .addRule(new ExtraDataMaxLengthValidationRule(BlockHeader.MAX_EXTRA_DATA_BYTES)) .addRule((new BaseFeeMarketBlockHeaderGasPriceValidationRule(baseFeeMarket))) - .addRule(new MergeUnfinalizedValidationRule()) .addRule(new ConstantOmmersHashRule()) .addRule(new NoNonceRule()) .addRule(new NoDifficultyRule()) diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/headervalidationrules/MergeUnfinalizedValidationRule.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/headervalidationrules/MergeUnfinalizedValidationRule.java deleted file mode 100644 index a0c6712332b..00000000000 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/headervalidationrules/MergeUnfinalizedValidationRule.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright Hyperledger Besu Contributors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.consensus.merge.headervalidationrules; - -import org.hyperledger.besu.consensus.merge.MergeContext; -import org.hyperledger.besu.ethereum.ProtocolContext; -import org.hyperledger.besu.ethereum.core.BlockHeader; -import org.hyperledger.besu.ethereum.mainnet.AttachedBlockHeaderValidationRule; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class MergeUnfinalizedValidationRule implements AttachedBlockHeaderValidationRule { - private static final Logger LOG = LoggerFactory.getLogger(MergeUnfinalizedValidationRule.class); - - @Override - public boolean validate( - final BlockHeader header, final BlockHeader parent, final ProtocolContext protocolContext) { - - MergeContext mergeContext = protocolContext.getConsensusContext(MergeContext.class); - // if we have a finalized blockheader, fail this rule if - // the block number is lower than finalized - // or block number is the same but hash is different - if (mergeContext - .getFinalized() - .filter(finalized -> header.getNumber() <= finalized.getNumber()) - .filter(finalized -> !header.getHash().equals(finalized.getHash())) - .isPresent()) { - LOG.warn( - "BlockHeader {} failed validation due to block {} already finalized", - header.toLogString(), - mergeContext.getFinalized().map(BlockHeader::toLogString).orElse("{}")); - return false; - } - - return true; - } -} diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/headervalidationrules/MergeUnfinalizedValidationRuleTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/headervalidationrules/MergeUnfinalizedValidationRuleTest.java deleted file mode 100644 index a1f45700764..00000000000 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/headervalidationrules/MergeUnfinalizedValidationRuleTest.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright Hyperledger Besu Contributors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.hyperledger.besu.consensus.merge.headervalidationrules; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import org.hyperledger.besu.consensus.merge.MergeContext; -import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.ethereum.ProtocolContext; -import org.hyperledger.besu.ethereum.core.BlockHeader; - -import java.util.Optional; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) -public class MergeUnfinalizedValidationRuleTest { - - @Mock private ProtocolContext protocolContext; - @Mock private MergeContext mergeContext; - @Mock private BlockHeader finalizedHeader; - final MergeUnfinalizedValidationRule rule = new MergeUnfinalizedValidationRule(); - - @Before - public void setUp() { - when(protocolContext.getConsensusContext(MergeContext.class)).thenReturn(mergeContext); - when(finalizedHeader.getNumber()).thenReturn(50L); - when(finalizedHeader.getHash()).thenReturn(Hash.ZERO); - when(mergeContext.getFinalized()).thenReturn(Optional.of(finalizedHeader)); - } - - @Test - public void shouldFailBlocksPriorToFinalized() { - final BlockHeader invalidHeader = mock(BlockHeader.class); - when(invalidHeader.getHash()).thenReturn(Hash.fromHexStringLenient("0x1337")); - when(invalidHeader.getNumber()).thenReturn(1L); - assertThat(rule.validate(invalidHeader, mock(BlockHeader.class), protocolContext)).isFalse(); - } - - @Test - public void shouldPassBlocksWithSameHashAsFinalized() { - final BlockHeader duplicateOfFinalized = mock(BlockHeader.class); - when(duplicateOfFinalized.getHash()).thenReturn(Hash.ZERO); - when(duplicateOfFinalized.getNumber()).thenReturn(50L); - assertThat(rule.validate(duplicateOfFinalized, mock(BlockHeader.class), protocolContext)) - .isTrue(); - } -} From bd9b98c002db02a8e0edc033effe8e801759090f Mon Sep 17 00:00:00 2001 From: garyschulte Date: Tue, 9 Aug 2022 16:31:48 -0700 Subject: [PATCH 076/109] fix for fast sync regression on post-merge networks (#4224) * use attached/detached rule difference to prevent PoW rules from influencing fast sync around TTD Signed-off-by: garyschulte --- .../mainnet/MainnetBlockHeaderValidator.java | 47 ++++++++++++------- .../AttachedProofOfWorkValidationRule.java | 46 ++++++++++++++++++ .../CalculatedDifficultyValidationRule.java | 5 +- .../ProofOfWorkValidationRule.java | 7 --- .../TimestampMoreRecentThanParent.java | 4 -- 5 files changed, 78 insertions(+), 31 deletions(-) create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/AttachedProofOfWorkValidationRule.java diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java index 84b9357d317..04c1e6562af 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java @@ -14,9 +14,11 @@ */ package org.hyperledger.besu.ethereum.mainnet; +import org.hyperledger.besu.config.MergeConfigOptions; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.AncestryValidationRule; +import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.AttachedProofOfWorkValidationRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.BaseFeeMarketBlockHeaderGasPriceValidationRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.CalculatedDifficultyValidationRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.ConstantFieldValidationRule; @@ -122,22 +124,35 @@ public static BlockHeaderValidator.Builder createPgaBlockHeaderValidator( public static BlockHeaderValidator.Builder createBaseFeeMarketValidator( final BaseFeeMarket baseFeeMarket) { - return new BlockHeaderValidator.Builder() - .addRule(CalculatedDifficultyValidationRule::new) - .addRule(new AncestryValidationRule()) - .addRule(new GasUsageValidationRule()) - .addRule( - new GasLimitRangeAndDeltaValidationRule( - MIN_GAS_LIMIT, Long.MAX_VALUE, Optional.of(baseFeeMarket))) - .addRule(new TimestampMoreRecentThanParent(MINIMUM_SECONDS_SINCE_PARENT)) - .addRule(new TimestampBoundedByFutureParameter(TIMESTAMP_TOLERANCE_S)) - .addRule(new ExtraDataMaxLengthValidationRule(BlockHeader.MAX_EXTRA_DATA_BYTES)) - .addRule( - new ProofOfWorkValidationRule( - new EpochCalculator.DefaultEpochCalculator(), - PoWHasher.ETHASH_LIGHT, - Optional.of(baseFeeMarket))) - .addRule((new BaseFeeMarketBlockHeaderGasPriceValidationRule(baseFeeMarket))); + var builder = + new BlockHeaderValidator.Builder() + .addRule(CalculatedDifficultyValidationRule::new) + .addRule(new AncestryValidationRule()) + .addRule(new GasUsageValidationRule()) + .addRule( + new GasLimitRangeAndDeltaValidationRule( + MIN_GAS_LIMIT, Long.MAX_VALUE, Optional.of(baseFeeMarket))) + .addRule(new TimestampMoreRecentThanParent(MINIMUM_SECONDS_SINCE_PARENT)) + .addRule(new TimestampBoundedByFutureParameter(TIMESTAMP_TOLERANCE_S)) + .addRule(new ExtraDataMaxLengthValidationRule(BlockHeader.MAX_EXTRA_DATA_BYTES)) + .addRule((new BaseFeeMarketBlockHeaderGasPriceValidationRule(baseFeeMarket))); + + // if merge is enabled, use the attached version of the proof of work validation rule + if (MergeConfigOptions.isMergeEnabled()) { + builder.addRule( + new AttachedProofOfWorkValidationRule( + new EpochCalculator.DefaultEpochCalculator(), + PoWHasher.ETHASH_LIGHT, + Optional.of(baseFeeMarket))); + + } else { + builder.addRule( + new ProofOfWorkValidationRule( + new EpochCalculator.DefaultEpochCalculator(), + PoWHasher.ETHASH_LIGHT, + Optional.of(baseFeeMarket))); + } + return builder; } static BlockHeaderValidator.Builder createBaseFeeMarketOmmerValidator( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/AttachedProofOfWorkValidationRule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/AttachedProofOfWorkValidationRule.java new file mode 100644 index 00000000000..59cd5b3b3ad --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/AttachedProofOfWorkValidationRule.java @@ -0,0 +1,46 @@ +/* + * Copyright Hyperledger Besu Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.mainnet.headervalidationrules; + +import org.hyperledger.besu.ethereum.ProtocolContext; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.mainnet.AttachedBlockHeaderValidationRule; +import org.hyperledger.besu.ethereum.mainnet.EpochCalculator; +import org.hyperledger.besu.ethereum.mainnet.PoWHasher; +import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; + +import java.util.Optional; + +/** + * An attached proof of work validation rule that wraps the detached version of the same. Suitable + * for use in block validator stacks supporting the merge. + */ +public class AttachedProofOfWorkValidationRule implements AttachedBlockHeaderValidationRule { + + private final ProofOfWorkValidationRule detachedRule; + + public AttachedProofOfWorkValidationRule( + final EpochCalculator epochCalculator, + final PoWHasher hasher, + final Optional feeMarket) { + this.detachedRule = new ProofOfWorkValidationRule(epochCalculator, hasher, feeMarket); + } + + @Override + public boolean validate( + final BlockHeader header, final BlockHeader parent, final ProtocolContext protocolContext) { + return detachedRule.validate(header, parent); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/CalculatedDifficultyValidationRule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/CalculatedDifficultyValidationRule.java index 2bffde67cc5..bcc4e213586 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/CalculatedDifficultyValidationRule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/CalculatedDifficultyValidationRule.java @@ -14,7 +14,6 @@ */ package org.hyperledger.besu.ethereum.mainnet.headervalidationrules; -import org.hyperledger.besu.config.MergeConfigOptions; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.mainnet.AttachedBlockHeaderValidationRule; @@ -37,9 +36,7 @@ public CalculatedDifficultyValidationRule(final DifficultyCalculator difficultyC @Override public boolean validate( final BlockHeader header, final BlockHeader parent, final ProtocolContext context) { - if (MergeConfigOptions.isMergeEnabled()) { - return true; - } + final BigInteger actualDifficulty = new BigInteger(1, header.getDifficulty().toArray()); final BigInteger expectedDifficulty = difficultyCalculator.nextDifficulty(header.getTimestamp(), parent, context); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ProofOfWorkValidationRule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ProofOfWorkValidationRule.java index 2c98f311b24..6f1612f1c89 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ProofOfWorkValidationRule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/ProofOfWorkValidationRule.java @@ -16,7 +16,6 @@ import static java.lang.Boolean.FALSE; -import org.hyperledger.besu.config.MergeConfigOptions; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.mainnet.DetachedBlockHeaderValidationRule; @@ -70,12 +69,6 @@ public boolean validate(final BlockHeader header, final BlockHeader parent) { return false; } - // TODO: remove this rule bypass, use post-merge headervalidation rules - // https://github.com/hyperledger/besu/issues/2898 - if (MergeConfigOptions.isMergeEnabled()) { - return true; - } - final Hash headerHash = hashHeader(header); PoWSolution solution = hasher.hash(header.getNonce(), header.getNumber(), epochCalculator, headerHash); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/TimestampMoreRecentThanParent.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/TimestampMoreRecentThanParent.java index 2af6d23d87b..6aa7e5479ef 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/TimestampMoreRecentThanParent.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/TimestampMoreRecentThanParent.java @@ -16,7 +16,6 @@ import static com.google.common.base.Preconditions.checkArgument; -import org.hyperledger.besu.config.MergeConfigOptions; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.mainnet.DetachedBlockHeaderValidationRule; @@ -36,9 +35,6 @@ public TimestampMoreRecentThanParent(final long minimumSecondsSinceParent) { @Override public boolean validate(final BlockHeader header, final BlockHeader parent) { - if (MergeConfigOptions.isMergeEnabled()) { - return true; - } return validateTimestamp(header.getTimestamp(), parent.getTimestamp()); } From 1f5c312672f6e81ad42fe17c314f385ffa036295 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Tue, 9 Aug 2022 18:36:15 -0700 Subject: [PATCH 077/109] quieten DynamicPivotBlockManager (#4241) * quieten DynamicPivotBlockManager. Only change pivot block if it is different than existing. move logging to debug Signed-off-by: garyschulte --- .../eth/sync/snapsync/DynamicPivotBlockManager.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/DynamicPivotBlockManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/DynamicPivotBlockManager.java index 0c11573bd98..845d341378c 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/DynamicPivotBlockManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/DynamicPivotBlockManager.java @@ -90,10 +90,14 @@ public void check(final BiConsumer onNewPivotBlock) { public void switchToNewPivotBlock(final BiConsumer onSwitchDone) { lastPivotBlockFound.ifPresentOrElse( blockHeader -> { - LOG.info( - "Select new pivot block {} {}", blockHeader.getNumber(), blockHeader.getStateRoot()); - syncState.setCurrentHeader(blockHeader); - lastPivotBlockFound = Optional.empty(); + if (syncState.getPivotBlockHeader().filter(blockHeader::equals).isEmpty()) { + LOG.debug( + "Select new pivot block {} {}", + blockHeader.getNumber(), + blockHeader.getStateRoot()); + syncState.setCurrentHeader(blockHeader); + lastPivotBlockFound = Optional.empty(); + } onSwitchDone.accept(blockHeader, true); }, () -> onSwitchDone.accept(syncState.getPivotBlockHeader().orElseThrow(), false)); From 9d476ea1f8f97428dc1e69f24f913654dd38a4df Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Wed, 10 Aug 2022 14:04:45 +0200 Subject: [PATCH 078/109] Introduce a cap to reputation score increase (#4230) Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 1 + .../ethereum/eth/manager/PeerReputation.java | 33 +++++++++++++++---- .../ethereum/eth/manager/EthPeerTest.java | 2 ++ .../eth/manager/PeerReputationTest.java | 19 +++++++++-- 4 files changed, 47 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 364d6168a6b..dfe6dda112b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 22.7.1 ### Additions and Improvements +- Introduce a cap to reputation score increase [#4230](https://github.com/hyperledger/besu/pull/4230) - Add experimental CLI option for `--Xp2p-peer-lower-bound` [#4200](https://github.com/hyperledger/besu/pull/4200) ### Bug Fixes diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputation.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputation.java index d0010b0fcf3..0c2edf226ed 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputation.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputation.java @@ -14,6 +14,8 @@ */ package org.hyperledger.besu.ethereum.eth.manager; +import static com.google.common.base.Preconditions.checkArgument; + import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage.DisconnectReason; import java.util.Map; @@ -30,21 +32,34 @@ import org.slf4j.LoggerFactory; public class PeerReputation implements Comparable { + static final long USELESS_RESPONSE_WINDOW_IN_MILLIS = + TimeUnit.MILLISECONDS.convert(1, TimeUnit.MINUTES); + static final int DEFAULT_MAX_SCORE = 150; + static final int DEFAULT_INITIAL_SCORE = 100; private static final Logger LOG = LoggerFactory.getLogger(PeerReputation.class); private static final int TIMEOUT_THRESHOLD = 3; private static final int USELESS_RESPONSE_THRESHOLD = 5; - static final long USELESS_RESPONSE_WINDOW_IN_MILLIS = - TimeUnit.MILLISECONDS.convert(1, TimeUnit.MINUTES); private final ConcurrentMap timeoutCountByRequestType = new ConcurrentHashMap<>(); private final Queue uselessResponseTimes = new ConcurrentLinkedQueue<>(); - private static final int DEFAULT_SCORE = 100; private static final int SMALL_ADJUSTMENT = 1; private static final int LARGE_ADJUSTMENT = 10; - private long score = DEFAULT_SCORE; + private int score; + + private final int maxScore; + + public PeerReputation() { + this(DEFAULT_INITIAL_SCORE, DEFAULT_MAX_SCORE); + } + + public PeerReputation(final int initialScore, final int maxScore) { + checkArgument(initialScore <= maxScore, "Inital score must be less than or equal to max score"); + this.maxScore = maxScore; + this.score = initialScore; + } public Optional recordRequestTimeout(final int requestCode) { final int newTimeoutCount = getOrCreateTimeoutCount(requestCode).incrementAndGet(); @@ -86,7 +101,9 @@ public Optional recordUselessResponse(final long timestamp) { } public void recordUsefulResponse() { - score += SMALL_ADJUSTMENT; + if (score < maxScore) { + score = Math.min(maxScore, score + SMALL_ADJUSTMENT); + } } private boolean shouldRemove(final Long timestamp, final long currentTimestamp) { @@ -100,6 +117,10 @@ public String toString() { @Override public int compareTo(final @Nonnull PeerReputation otherReputation) { - return Long.compare(this.score, otherReputation.score); + return Integer.compare(this.score, otherReputation.score); + } + + public int getScore() { + return score; } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeerTest.java index 1da115f6920..c3e612ed185 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthPeerTest.java @@ -365,7 +365,9 @@ public void compareTo_withDifferentNodeId() { @Test public void recordUsefullResponse() { final EthPeer peer = createPeer(); + peer.recordUselessResponse("bodies"); final EthPeer peer2 = createPeer(); + peer2.recordUselessResponse("bodies"); peer.recordUsefulResponse(); assertThat(peer.getReputation().compareTo(peer2.getReputation())).isGreaterThan(0); } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputationTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputationTest.java index 5d7cb5962fc..1fa5b47b96f 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputationTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/PeerReputationTest.java @@ -24,7 +24,14 @@ public class PeerReputationTest { - private final PeerReputation reputation = new PeerReputation(); + private static final int INITIAL_SCORE = 25; + private static final int MAX_SCORE = 50; + private final PeerReputation reputation = new PeerReputation(INITIAL_SCORE, MAX_SCORE); + + @Test(expected = java.lang.IllegalArgumentException.class) + public void shouldThrowOnInvalidInitialScore() { + new PeerReputation(2, 1); + } @Test public void shouldOnlyDisconnectWhenTimeoutLimitReached() { @@ -84,6 +91,14 @@ public void shouldDiscardEmptyResponseRecordsAfterTimeWindowElapses() { @Test public void shouldIncreaseScore() { reputation.recordUsefulResponse(); - assertThat(reputation.compareTo(new PeerReputation())).isGreaterThan(0); + assertThat(reputation.getScore()).isGreaterThan(INITIAL_SCORE); + } + + @Test + public void shouldNotIncreaseScoreOverMax() { + for (int i = 0; i <= MAX_SCORE + 1; i++) { + reputation.recordUsefulResponse(); + } + assertThat(reputation.getScore()).isEqualTo(MAX_SCORE); } } From f847ead5c78b214bed53ea3646c87390a92d964a Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Fri, 12 Aug 2022 15:58:24 +1000 Subject: [PATCH 079/109] Improve pending blocks retrieval mechanism (#4227) * Add more log to retrieve parent method * Request the lowest pending ancestor when saving a block * Replace recursive implementation with iterative when getting pending ancestors of Block * Decrease scope of synchronized block to reflect only the event of adding pending block to the list * Add fork to the chain so test is more representative Signed-off-by: Gabriel Trintinalia Signed-off-by: Gabriel Trintinalia Co-authored-by: Gabriel Trintinalia --- CHANGELOG.md | 1 + .../eth/sync/BlockPropagationManager.java | 131 ++++++++++++------ .../eth/sync/state/PendingBlocksManager.java | 20 +++ .../AbstractBlockPropagationManagerTest.java | 30 ++++ .../sync/state/PendingBlocksManagerTest.java | 47 ++++++- 5 files changed, 185 insertions(+), 44 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfe6dda112b..0c1f16fd519 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Additions and Improvements - Introduce a cap to reputation score increase [#4230](https://github.com/hyperledger/besu/pull/4230) - Add experimental CLI option for `--Xp2p-peer-lower-bound` [#4200](https://github.com/hyperledger/besu/pull/4200) +- Improve pending blocks retrieval mechanism [#4227](https://github.com/hyperledger/besu/pull/4227) ### Bug Fixes - Fixes off-by-one error for mainnet TTD fallback [#4223](https://github.com/hyperledger/besu/pull/4223) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java index d97c6b110d8..f57a4486952 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java @@ -155,29 +155,49 @@ private void clearListeners() { private void onBlockAdded(final BlockAddedEvent blockAddedEvent) { // Check to see if any of our pending blocks are now ready for import final Block newBlock = blockAddedEvent.getBlock(); + traceLambda( + LOG, + "Block added event type {} for block {}. Current status {}", + blockAddedEvent::getEventType, + newBlock::toLogString, + () -> this); + + // If there is no children to process, maybe try non announced blocks + if (!maybeProcessPendingChildrenBlocks(newBlock)) { + traceLambda( + LOG, "There are no pending blocks ready to import for block {}", newBlock::toLogString); + maybeProcessNonAnnouncedBlocks(newBlock); + } + + if (blockAddedEvent.getEventType().equals(EventType.HEAD_ADVANCED)) { + final long head = protocolContext.getBlockchain().getChainHeadBlockNumber(); + final long cutoff = head + config.getBlockPropagationRange().lowerEndpoint(); + pendingBlocksManager.purgeBlocksOlderThan(cutoff); + } + } + /** + * Process pending Children if any + * + * @param block the block to process the children + * @return true if block has any pending child + */ + private boolean maybeProcessPendingChildrenBlocks(final Block block) { final List readyForImport; synchronized (pendingBlocksManager) { // Remove block from pendingBlocks list - pendingBlocksManager.deregisterPendingBlock(newBlock); + pendingBlocksManager.deregisterPendingBlock(block); // Import any pending blocks that are children of the newly added block - readyForImport = pendingBlocksManager.childrenOf(newBlock.getHash()); + readyForImport = pendingBlocksManager.childrenOf(block.getHash()); } - traceLambda( - LOG, - "Block added event type {} for block {}. Current status {}", - blockAddedEvent::getEventType, - newBlock::toLogString, - () -> this); - if (!readyForImport.isEmpty()) { traceLambda( LOG, "Ready to import pending blocks found [{}] for block {}", () -> readyForImport.stream().map(Block::toLogString).collect(Collectors.joining(", ")), - newBlock::toLogString); + block::toLogString); final Supplier>> importBlocksTask = PersistBlockTask.forUnorderedBlocks( @@ -193,25 +213,17 @@ private void onBlockAdded(final BlockAddedEvent blockAddedEvent) { .whenComplete( (r, t) -> { if (r != null) { - LOG.info("Imported {} pending blocks", r.size()); + LOG.info( + "Imported {} pending blocks: {}", + r.size(), + r.stream().map(b -> b.getHeader().getNumber()).collect(Collectors.toList())); } if (t != null) { LOG.error("Error importing pending blocks", t); } }); - } else { - - traceLambda( - LOG, "There are no pending blocks ready to import for block {}", newBlock::toLogString); - - maybeProcessNonAnnouncedBlocks(newBlock); - } - - if (blockAddedEvent.getEventType().equals(EventType.HEAD_ADVANCED)) { - final long head = protocolContext.getBlockchain().getChainHeadBlockNumber(); - final long cutoff = head + config.getBlockPropagationRange().lowerEndpoint(); - pendingBlocksManager.purgeBlocksOlderThan(cutoff); } + return !readyForImport.isEmpty(); } private void maybeProcessNonAnnouncedBlocks(final Block newBlock) { @@ -223,13 +235,13 @@ private void maybeProcessNonAnnouncedBlocks(final Block newBlock) { .map(ProcessableBlockHeader::getNumber) .ifPresent( minAnnouncedBlockNumber -> { - long distance = minAnnouncedBlockNumber - localHeadBlockNumber; + final long distance = minAnnouncedBlockNumber - localHeadBlockNumber; LOG.trace( "Found lowest announced block {} with distance {}", minAnnouncedBlockNumber, distance); - long firstNonAnnouncedBlockNumber = newBlock.getHeader().getNumber() + 1; + final long firstNonAnnouncedBlockNumber = newBlock.getHeader().getNumber() + 1; if (distance < config.getBlockPropagationRange().upperEndpoint() && minAnnouncedBlockNumber > firstNonAnnouncedBlockNumber) { @@ -364,21 +376,19 @@ private CompletableFuture processAnnouncedBlock( return getBlockFromPeers(Optional.of(peer), blockHash.number(), Optional.of(blockHash.hash())); } - private void requestParentBlock(final BlockHeader blockHeader) { + private void requestParentBlock(final Block block) { + final BlockHeader blockHeader = block.getHeader(); if (requestedBlocks.add(blockHeader.getParentHash())) { retrieveParentBlock(blockHeader); } else { - LOG.trace("Parent block with hash {} was already requested", blockHeader.getParentHash()); + LOG.debug("Parent block with hash {} is already requested", blockHeader.getParentHash()); } } private CompletableFuture retrieveParentBlock(final BlockHeader blockHeader) { final long targetParentBlockNumber = blockHeader.getNumber() - 1L; final Hash targetParentBlockHash = blockHeader.getParentHash(); - LOG.info( - "Retrieving parent {} of block #{} from peers", - targetParentBlockHash, - blockHeader.getNumber()); + LOG.info("Retrieving parent {} of block {}", targetParentBlockHash, blockHeader.toLogString()); return getBlockFromPeers( Optional.empty(), targetParentBlockNumber, Optional.of(targetParentBlockHash)); } @@ -434,18 +444,13 @@ CompletableFuture importOrSavePendingBlock(final Block block, final Bytes // invoked for the parent of this block before we are able to register it. traceLambda(LOG, "Import or save pending block {}", block::toLogString); - synchronized (pendingBlocksManager) { - if (!protocolContext.getBlockchain().contains(block.getHeader().getParentHash())) { - // Block isn't connected to local chain, save it to pending blocks collection - if (pendingBlocksManager.registerPendingBlock(block, nodeId)) { - LOG.info("Saving announced block {} for future import", block.toLogString()); - } - - // Request parent of the lowest announced block - pendingBlocksManager.lowestAnnouncedBlock().ifPresent(this::requestParentBlock); - - return CompletableFuture.completedFuture(block); + if (!protocolContext.getBlockchain().contains(block.getHeader().getParentHash())) { + // Block isn't connected to local chain, save it to pending blocks collection + if (savePendingBlock(block, nodeId)) { + // if block is saved as pending, try to resolve it + maybeProcessPendingBlocks(block); } + return CompletableFuture.completedFuture(block); } if (!importingBlocks.add(block.getHash())) { @@ -480,6 +485,48 @@ CompletableFuture importOrSavePendingBlock(final Block block, final Bytes blockHeaderValidator, block, parent, badBlockManager)); } + /** + * Save the given block. + * + * @param block the block to track + * @param nodeId node that sent the block + * @return true if the block was added (was not previously present) + */ + private boolean savePendingBlock(final Block block, final Bytes nodeId) { + synchronized (pendingBlocksManager) { + if (pendingBlocksManager.registerPendingBlock(block, nodeId)) { + LOG.info( + "Saved announced block for future import {} - {} saved block(s)", + block.toLogString(), + pendingBlocksManager.size()); + return true; + } + return false; + } + } + + /** + * Try to request the lowest ancestor for the given pending block or process the descendants if + * the ancestor is already in the chain + */ + private void maybeProcessPendingBlocks(final Block block) { + // Try to get the lowest ancestor pending for this block, so we can import it + final Optional lowestPending = pendingBlocksManager.pendingAncestorBlockOf(block); + if (lowestPending.isPresent()) { + final Block lowestPendingBlock = lowestPending.get(); + // If the parent of the lowest ancestor is not in the chain, request it. + if (!protocolContext + .getBlockchain() + .contains(lowestPendingBlock.getHeader().getParentHash())) { + requestParentBlock(lowestPendingBlock); + } else { + LOG.trace("Parent block is already in the chain"); + // if the parent is already imported, process its children + maybeProcessPendingChildrenBlocks(lowestPendingBlock); + } + } + } + private CompletableFuture validateAndProcessPendingBlock( final BlockHeaderValidator blockHeaderValidator, final Block block, diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/state/PendingBlocksManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/state/PendingBlocksManager.java index f4a969ee0e3..cb0584ea029 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/state/PendingBlocksManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/state/PendingBlocksManager.java @@ -108,6 +108,10 @@ public boolean contains(final Hash blockHash) { return pendingBlocks.containsKey(blockHash); } + public int size() { + return pendingBlocks.size(); + } + public List childrenOf(final Hash parentBlock) { final Set blocksByParent = pendingBlocksByParentHash.get(parentBlock); if (blocksByParent == null || blocksByParent.size() == 0) { @@ -127,6 +131,22 @@ public Optional lowestAnnouncedBlock() { .min(Comparator.comparing(BlockHeader::getNumber)); } + /** + * Get the lowest pending ancestor block saved for a block + * + * @param block target block + * @return An optional with the lowest ancestor pending block + */ + public Optional pendingAncestorBlockOf(final Block block) { + Block ancestor = block; + int ancestorLevel = 0; + while (pendingBlocks.containsKey(ancestor.getHeader().getParentHash()) + && ancestorLevel++ < pendingBlocks.size()) { + ancestor = pendingBlocks.get(ancestor.getHeader().getParentHash()).block(); + } + return Optional.of(ancestor); + } + @Override public String toString() { return "PendingBlocksManager{" diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java index d2ae85662f1..2aec4c302b5 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java @@ -667,6 +667,36 @@ public void shouldRequestLowestAnnouncedPendingBlockParent() { }); } + @Test + public void shouldRequestLowestAnnouncedPendingBlockParent_twoMissingBlocks() { + // test if block propagation manager can recover if one block is missed + blockchainUtil.importFirstBlocks(2); + final List blocks = blockchainUtil.getBlocks().subList(2, 6); + + blockPropagationManager.start(); + + // Create peer and responder + final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 0); + final Responder responder = RespondingEthPeer.blockchainResponder(getFullBlockchain()); + + // skip two block then create messages from blocklist + blocks.stream() + .skip(2) + .map(this::createNewBlockHashMessage) + .forEach( + message -> { // Broadcast new block hash message + EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, peer, message); + }); + + peer.respondWhile(responder, peer::hasOutstandingRequests); + + // assert all blocks were imported + blocks.forEach( + block -> { + assertThat(blockchain.contains(block.getHash())).isTrue(); + }); + } + private NewBlockHashesMessage createNewBlockHashMessage(final Block block) { return NewBlockHashesMessage.create( Collections.singletonList( diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/PendingBlocksManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/PendingBlocksManagerTest.java index 8c867c7d254..be61c8fa338 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/PendingBlocksManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/PendingBlocksManagerTest.java @@ -25,6 +25,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Optional; import org.apache.tuweni.bytes.Bytes; import org.junit.Before; @@ -163,7 +164,8 @@ public void shouldPreventNodeFromFillingCache() { pendingBlocksManager.registerPendingBlock(childBlockFromNodeTwo, NODE_ID_2); // check blocks from node 1 in the cache (node 1 should replace the lowest priority block) - List pendingBlocksForParent = pendingBlocksManager.childrenOf(parentBlock.getHash()); + final List pendingBlocksForParent = + pendingBlocksManager.childrenOf(parentBlock.getHash()); for (int i = 0; i < nbBlocks; i++) { final Block foundBlock = childBlockFromNodeOne.poll(); if (i != 0) { @@ -236,7 +238,7 @@ public void shouldReplaceLowestPriorityBlockWhenCacheIsFull() { // check blocks in the cache // and verify remove the block with the lowest priority (BLOCK-2) - for (Block block : childBlockFromNodeOne) { + for (final Block block : childBlockFromNodeOne) { if (block.getHeader().getNumber() == 2) { assertThat(pendingBlocksManager.contains(block.getHash())).isFalse(); } else { @@ -259,4 +261,45 @@ public void shouldReturnLowestBlockByNumber() { assertThat(pendingBlocksManager.lowestAnnouncedBlock()).contains(parentBlock.getHeader()); } + + @Test + public void shouldReturnLowestAncestorPendingBlock() { + final BlockDataGenerator gen = new BlockDataGenerator(); + final Block parentBlock = gen.block(); + + final Block block = gen.nextBlock(parentBlock); + final Block child = gen.nextBlock(block); + + final Block forkBlock = gen.nextBlock(parentBlock); + final Block forkChild = gen.nextBlock(forkBlock); + + // register chain with one missing block + pendingBlocksManager.registerPendingBlock(block, NODE_ID_1); + pendingBlocksManager.registerPendingBlock(child, NODE_ID_1); + + // Register fork with one missing parent + pendingBlocksManager.registerPendingBlock(forkBlock, NODE_ID_1); + pendingBlocksManager.registerPendingBlock(forkChild, NODE_ID_1); + + // assert it is able to follow the chain + final Optional blockAncestor = pendingBlocksManager.pendingAncestorBlockOf(child); + assertThat(blockAncestor.get().getHeader().getHash()).isEqualTo(block.getHeader().getHash()); + + // assert it is able to follow the fork + final Optional forkAncestor = pendingBlocksManager.pendingAncestorBlockOf(forkChild); + assertThat(forkAncestor.get().getHeader().getHash()).isEqualTo(forkBlock.getHeader().getHash()); + + // Both forks result in the same parent + assertThat(forkAncestor.get().getHeader().getParentHash()) + .isEqualTo(blockAncestor.get().getHeader().getParentHash()); + } + + @Test + public void shouldReturnLowestAncestorPendingBlock_sameBlock() { + final BlockDataGenerator gen = new BlockDataGenerator(); + final Block block = gen.block(); + pendingBlocksManager.registerPendingBlock(block, NODE_ID_1); + final Optional b = pendingBlocksManager.pendingAncestorBlockOf(block); + assertThat(b).contains(block); + } } From d2968509ba6d69732b3e8897902d705d68cf62f2 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Mon, 15 Aug 2022 21:24:09 -0600 Subject: [PATCH 080/109] Simplify Trie Dependencies (#4259) Make the ethereum/trie and services/kvstore modules as slim as possible by dropping dependencies. * The ':util' api dependency is removed from kvstore and added to eth module * Move tries's kvstore dependency to test * Other dependencies are removed as unused from trie and kvstore Signed-off-by: Danno Ferrin --- ethereum/eth/build.gradle | 1 + ethereum/trie/build.gradle | 4 ++-- plugins/rocksdb/build.gradle | 1 + services/kvstore/build.gradle | 12 ------------ 4 files changed, 4 insertions(+), 14 deletions(-) diff --git a/ethereum/eth/build.gradle b/ethereum/eth/build.gradle index 1033df5a4da..89544c43918 100644 --- a/ethereum/eth/build.gradle +++ b/ethereum/eth/build.gradle @@ -35,6 +35,7 @@ task testJar(type: Jar) { dependencies { api 'org.slf4j:slf4j-api' + api project(':util') annotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess' implementation project(':config') diff --git a/ethereum/trie/build.gradle b/ethereum/trie/build.gradle index 5bf23f0e422..e3e232edbc4 100644 --- a/ethereum/trie/build.gradle +++ b/ethereum/trie/build.gradle @@ -30,16 +30,16 @@ jar { dependencies { implementation project(':crypto') implementation project(':ethereum:rlp') - implementation project(':services:kvstore') + implementation "org.immutables:value-annotations" implementation 'com.google.guava:guava' implementation 'io.opentelemetry:opentelemetry-api' implementation 'org.apache.tuweni:tuweni-bytes' implementation 'org.bouncycastle:bcprov-jdk15on' annotationProcessor "org.immutables:value" - implementation "org.immutables:value-annotations" + testImplementation project(':services:kvstore') testImplementation project(':testutil') testImplementation 'com.fasterxml.jackson.core:jackson-databind' diff --git a/plugins/rocksdb/build.gradle b/plugins/rocksdb/build.gradle index 70c28080ec8..3e94af4bfb7 100644 --- a/plugins/rocksdb/build.gradle +++ b/plugins/rocksdb/build.gradle @@ -38,6 +38,7 @@ dependencies { implementation project(':metrics:core') implementation project(':metrics:rocksdb') implementation project(':services:kvstore') + implementation project(':util') implementation 'com.fasterxml.jackson.core:jackson-databind' implementation 'com.google.guava:guava' diff --git a/services/kvstore/build.gradle b/services/kvstore/build.gradle index 294d5cc6dfa..d68f72680db 100644 --- a/services/kvstore/build.gradle +++ b/services/kvstore/build.gradle @@ -29,23 +29,11 @@ jar { dependencies { api project(':plugin-api') - api project(':util') api 'org.slf4j:slf4j-api' - implementation project(':metrics:core') - implementation project(':metrics:rocksdb') - - implementation 'com.google.guava:guava' - implementation 'io.prometheus:simpleclient' - implementation 'org.apache.tuweni:tuweni-bytes' - implementation 'org.rocksdb:rocksdbjni' - testImplementation project(':testutil') - testImplementation 'junit:junit' testImplementation 'org.assertj:assertj-core' - testImplementation 'org.junit.jupiter:junit-jupiter' - testImplementation 'org.mockito:mockito-core' testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' } From e0d4da2917e23448de93c420c0cce884742f319e Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 16 Aug 2022 11:17:00 +0200 Subject: [PATCH 081/109] Fix off-by-one error in AbstractRetryingPeerTask (#4254) Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 2 +- .../RetryingGetAccountRangeFromPeerTask.java | 2 +- .../snap/RetryingGetBytecodeFromPeerTask.java | 2 +- .../RetryingGetStorageRangeFromPeerTask.java | 2 +- .../snap/RetryingGetTrieNodeFromPeerTask.java | 2 +- .../task/AbstractRetryingPeerTask.java | 2 +- ...gGetHeadersEndingAtFromPeerByHashTask.java | 2 +- .../task/RetryingGetNodeDataFromPeerTask.java | 2 +- .../sync/fastsync/PivotBlockRetriever.java | 2 +- .../eth/sync/tasks/CompleteBlocksTask.java | 2 +- .../tasks/DownloadHeaderSequenceTask.java | 2 +- .../sync/tasks/GetReceiptsForHeadersTask.java | 2 +- .../RetryingGetHeaderFromPeerByHashTask.java | 2 +- .../ethtaskutils/RetryingMessageTaskTest.java | 10 +- .../task/AbstractRetryingPeerTaskTest.java | 99 +++++++++++++++++++ .../fastsync/PivotBlockConfirmerTest.java | 14 +-- 16 files changed, 124 insertions(+), 25 deletions(-) create mode 100644 ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTaskTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c1f16fd519..c66b1501fdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ ### Bug Fixes - Fixes off-by-one error for mainnet TTD fallback [#4223](https://github.com/hyperledger/besu/pull/4223) - +- Fix off-by-one error in AbstractRetryingPeerTask [#4254](https://github.com/hyperledger/besu/pull/4254) ## 22.7.0 diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/RetryingGetAccountRangeFromPeerTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/RetryingGetAccountRangeFromPeerTask.java index 33254cf1b88..7512bdd03a9 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/RetryingGetAccountRangeFromPeerTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/RetryingGetAccountRangeFromPeerTask.java @@ -43,7 +43,7 @@ private RetryingGetAccountRangeFromPeerTask( final BlockHeader blockHeader, final MetricsSystem metricsSystem) { super( - ethContext, 3, data -> data.accounts().isEmpty() && data.proofs().isEmpty(), metricsSystem); + ethContext, 4, data -> data.accounts().isEmpty() && data.proofs().isEmpty(), metricsSystem); this.ethContext = ethContext; this.startKeyHash = startKeyHash; this.endKeyHash = endKeyHash; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/RetryingGetBytecodeFromPeerTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/RetryingGetBytecodeFromPeerTask.java index cd5dc699592..7d23ec944d3 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/RetryingGetBytecodeFromPeerTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/RetryingGetBytecodeFromPeerTask.java @@ -41,7 +41,7 @@ private RetryingGetBytecodeFromPeerTask( final List codeHashes, final BlockHeader blockHeader, final MetricsSystem metricsSystem) { - super(ethContext, 3, Map::isEmpty, metricsSystem); + super(ethContext, 4, Map::isEmpty, metricsSystem); this.ethContext = ethContext; this.codeHashes = codeHashes; this.blockHeader = blockHeader; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/RetryingGetStorageRangeFromPeerTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/RetryingGetStorageRangeFromPeerTask.java index d7bc8a14ec1..7a095de9292 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/RetryingGetStorageRangeFromPeerTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/RetryingGetStorageRangeFromPeerTask.java @@ -45,7 +45,7 @@ private RetryingGetStorageRangeFromPeerTask( final Bytes32 endKeyHash, final BlockHeader blockHeader, final MetricsSystem metricsSystem) { - super(ethContext, 3, data -> data.proofs().isEmpty() && data.slots().isEmpty(), metricsSystem); + super(ethContext, 4, data -> data.proofs().isEmpty() && data.slots().isEmpty(), metricsSystem); this.ethContext = ethContext; this.accountHashes = accountHashes; this.startKeyHash = startKeyHash; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/RetryingGetTrieNodeFromPeerTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/RetryingGetTrieNodeFromPeerTask.java index 9b162c8951f..ebfd8856898 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/RetryingGetTrieNodeFromPeerTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/RetryingGetTrieNodeFromPeerTask.java @@ -40,7 +40,7 @@ private RetryingGetTrieNodeFromPeerTask( final Map> paths, final BlockHeader blockHeader, final MetricsSystem metricsSystem) { - super(ethContext, 3, Map::isEmpty, metricsSystem); + super(ethContext, 4, Map::isEmpty, metricsSystem); this.ethContext = ethContext; this.paths = paths; this.blockHeader = blockHeader; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTask.java index 5822ee367d8..148c5282511 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTask.java @@ -81,7 +81,7 @@ protected void executeTask() { // Return if task is done return; } - if (retryCount > maxRetries) { + if (retryCount >= maxRetries) { result.completeExceptionally(new MaxRetriesReachedException()); return; } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetHeadersEndingAtFromPeerByHashTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetHeadersEndingAtFromPeerByHashTask.java index ac9200fcff2..bc758e6b177 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetHeadersEndingAtFromPeerByHashTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetHeadersEndingAtFromPeerByHashTask.java @@ -44,7 +44,7 @@ public class RetryingGetHeadersEndingAtFromPeerByHashTask final Hash referenceHash, final int count, final MetricsSystem metricsSystem) { - super(ethContext, 3, List::isEmpty, metricsSystem); + super(ethContext, 4, List::isEmpty, metricsSystem); this.protocolSchedule = protocolSchedule; this.count = count; checkNotNull(referenceHash); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetNodeDataFromPeerTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetNodeDataFromPeerTask.java index 5c3c29d8318..16040e963ae 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetNodeDataFromPeerTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetNodeDataFromPeerTask.java @@ -40,7 +40,7 @@ private RetryingGetNodeDataFromPeerTask( final Collection hashes, final long pivotBlockNumber, final MetricsSystem metricsSystem) { - super(ethContext, 3, data -> false, metricsSystem); + super(ethContext, 4, data -> false, metricsSystem); this.ethContext = ethContext; this.hashes = new HashSet<>(hashes); this.pivotBlockNumber = pivotBlockNumber; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockRetriever.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockRetriever.java index 7bddc2ea469..e20bb16799c 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockRetriever.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockRetriever.java @@ -39,7 +39,7 @@ public class PivotBlockRetriever { private static final Logger LOG = LoggerFactory.getLogger(PivotBlockRetriever.class); - public static final int MAX_QUERY_RETRIES_PER_PEER = 3; + public static final int MAX_QUERY_RETRIES_PER_PEER = 4; private static final int DEFAULT_MAX_PIVOT_BLOCK_RESETS = 250; private static final int SUSPICIOUS_NUMBER_OF_RETRIES = 5; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/CompleteBlocksTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/CompleteBlocksTask.java index f9d5ed65321..43cfeadf89c 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/CompleteBlocksTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/CompleteBlocksTask.java @@ -49,7 +49,7 @@ public class CompleteBlocksTask extends AbstractRetryingPeerTask> { private static final Logger LOG = LoggerFactory.getLogger(CompleteBlocksTask.class); private static final int MIN_SIZE_INCOMPLETE_LIST = 1; - private static final int DEFAULT_RETRIES = 3; + private static final int DEFAULT_RETRIES = 4; private final EthContext ethContext; private final ProtocolSchedule protocolSchedule; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTask.java index 3433ab2bdf7..2923605ca4f 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTask.java @@ -54,7 +54,7 @@ */ public class DownloadHeaderSequenceTask extends AbstractRetryingPeerTask> { private static final Logger LOG = LoggerFactory.getLogger(DownloadHeaderSequenceTask.class); - private static final int DEFAULT_RETRIES = 3; + private static final int DEFAULT_RETRIES = 4; private final EthContext ethContext; private final ProtocolContext protocolContext; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/GetReceiptsForHeadersTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/GetReceiptsForHeadersTask.java index a44b6495f4b..699bf9c4b17 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/GetReceiptsForHeadersTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/GetReceiptsForHeadersTask.java @@ -42,7 +42,7 @@ public class GetReceiptsForHeadersTask extends AbstractRetryingPeerTask>> { private static final Logger LOG = LoggerFactory.getLogger(GetReceiptsForHeadersTask.class); - private static final int DEFAULT_RETRIES = 3; + private static final int DEFAULT_RETRIES = 4; private final EthContext ethContext; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/RetryingGetHeaderFromPeerByHashTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/RetryingGetHeaderFromPeerByHashTask.java index 9b30326b0f2..ff733ca8059 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/RetryingGetHeaderFromPeerByHashTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/RetryingGetHeaderFromPeerByHashTask.java @@ -44,7 +44,7 @@ public class RetryingGetHeaderFromPeerByHashTask final EthContext ethContext, final Hash referenceHash, final MetricsSystem metricsSystem) { - super(ethContext, 3, List::isEmpty, metricsSystem); + super(ethContext, 4, List::isEmpty, metricsSystem); this.protocolSchedule = protocolSchedule; checkNotNull(referenceHash); this.referenceHash = referenceHash; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/RetryingMessageTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/RetryingMessageTaskTest.java index 61584d77992..5f383d66fd8 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/RetryingMessageTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/RetryingMessageTaskTest.java @@ -38,7 +38,7 @@ public abstract class RetryingMessageTaskTest extends AbstractMessageTaskTest protected final int maxRetries; protected RetryingMessageTaskTest() { - this.maxRetries = 3; + this.maxRetries = 4; } @Override @@ -76,8 +76,8 @@ public void failsWhenPeerReturnsPartialResultThenStops() { respondingPeer.respond(partialResponder); assertThat(future.isDone()).isFalse(); - // Respond max times with no data - respondingPeer.respondTimes(emptyResponder, maxRetries); + // Respond max times - 1 with no data + respondingPeer.respondTimes(emptyResponder, maxRetries - 1); assertThat(future).isNotDone(); // Next retry should fail @@ -205,8 +205,8 @@ public void failsWhenPeersSendEmptyResponses() { assertThat(future.isDone()).isFalse(); - // Respond max times - respondingPeer.respondTimes(responder, maxRetries); + // Respond max times - 1 + respondingPeer.respondTimes(responder, maxRetries - 1); assertThat(future).isNotDone(); // Next retry should fail diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTaskTest.java new file mode 100644 index 00000000000..90b407f2fce --- /dev/null +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTaskTest.java @@ -0,0 +1,99 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.eth.manager.task; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; + +import org.hyperledger.besu.ethereum.eth.manager.EthContext; +import org.hyperledger.besu.ethereum.eth.manager.EthPeer; +import org.hyperledger.besu.ethereum.eth.manager.exceptions.MaxRetriesReachedException; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; +import org.hyperledger.besu.plugin.services.MetricsSystem; + +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class AbstractRetryingPeerTaskTest { + + @Mock EthContext ethContext; + MetricsSystem metricsSystem = new NoOpMetricsSystem(); + + @Test + public void shouldSuccessAtFirstTryIfNoTaskFailures() + throws InterruptedException, ExecutionException { + final int maxRetries = 2; + TaskThatFailsSometimes task = new TaskThatFailsSometimes(0, maxRetries); + CompletableFuture result = task.run(); + assertThat(result.get()).isTrue(); + assertThat(task.executions).isEqualTo(1); + } + + @Test + public void shouldSuccessIfTaskFailOnlyOnce() throws InterruptedException, ExecutionException { + final int maxRetries = 2; + TaskThatFailsSometimes task = new TaskThatFailsSometimes(1, maxRetries); + CompletableFuture result = task.run(); + assertThat(result.get()).isTrue(); + assertThat(task.executions).isEqualTo(2); + } + + @Test + public void shouldFailAfterMaxRetriesExecutions() throws InterruptedException { + final int maxRetries = 2; + TaskThatFailsSometimes task = new TaskThatFailsSometimes(maxRetries, maxRetries); + CompletableFuture result = task.run(); + assertThat(result.isCompletedExceptionally()).isTrue(); + assertThat(task.executions).isEqualTo(maxRetries); + try { + result.get(); + } catch (ExecutionException ee) { + assertThat(ee).hasCauseExactlyInstanceOf(MaxRetriesReachedException.class); + return; + } + failBecauseExceptionWasNotThrown(MaxRetriesReachedException.class); + } + + private class TaskThatFailsSometimes extends AbstractRetryingPeerTask { + final int initialFailures; + int executions = 0; + int failures = 0; + + protected TaskThatFailsSometimes(final int initialFailures, final int maxRetries) { + super(ethContext, maxRetries, Objects::isNull, metricsSystem); + this.initialFailures = initialFailures; + } + + @Override + protected CompletableFuture executePeerTask(final Optional assignedPeer) { + executions++; + if (failures < initialFailures) { + failures++; + return CompletableFuture.completedFuture(null); + } else { + result.complete(Boolean.TRUE); + return CompletableFuture.completedFuture(Boolean.TRUE); + } + } + } +} diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockConfirmerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockConfirmerTest.java index 4f2fc7ca082..11b4e1d249b 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockConfirmerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotBlockConfirmerTest.java @@ -90,7 +90,7 @@ public void setUp() { blockchainSetupUtil.getWorldArchive(), transactionPool, EthProtocolConfiguration.defaultConfig()); - pivotBlockConfirmer = createPivotBlockConfirmer(3, 1); + pivotBlockConfirmer = createPivotBlockConfirmer(3, 2); } private PivotBlockConfirmer createPivotBlockConfirmer( @@ -108,7 +108,7 @@ private PivotBlockConfirmer createPivotBlockConfirmer( @Test public void completeSuccessfully() { - pivotBlockConfirmer = createPivotBlockConfirmer(2, 1); + pivotBlockConfirmer = createPivotBlockConfirmer(2, 2); final Responder responder = RespondingEthPeer.blockchainResponder( @@ -137,7 +137,7 @@ public void completeSuccessfully() { @Test public void delayedResponse() { - pivotBlockConfirmer = createPivotBlockConfirmer(2, 1); + pivotBlockConfirmer = createPivotBlockConfirmer(2, 2); final Responder responder = RespondingEthPeer.blockchainResponder( @@ -170,7 +170,7 @@ public void delayedResponse() { @Test public void peerTimesOutThenIsUnresponsive() { - pivotBlockConfirmer = createPivotBlockConfirmer(2, 1); + pivotBlockConfirmer = createPivotBlockConfirmer(2, 2); final Responder responder = RespondingEthPeer.blockchainResponder( @@ -210,7 +210,7 @@ public void peerTimesOutThenIsUnresponsive() { @Test public void peerTimesOut() { - pivotBlockConfirmer = createPivotBlockConfirmer(2, 1); + pivotBlockConfirmer = createPivotBlockConfirmer(2, 2); final Responder responder = RespondingEthPeer.blockchainResponder( @@ -250,7 +250,7 @@ public void peerTimesOut() { @Test public void peerUnresponsive() { - pivotBlockConfirmer = createPivotBlockConfirmer(2, 1); + pivotBlockConfirmer = createPivotBlockConfirmer(2, 2); final Responder responder = RespondingEthPeer.blockchainResponder( @@ -292,7 +292,7 @@ public void peerUnresponsive() { @Test public void headerMismatch() { - pivotBlockConfirmer = createPivotBlockConfirmer(3, 1); + pivotBlockConfirmer = createPivotBlockConfirmer(3, 2); final Responder responderA = RespondingEthPeer.blockchainResponder( From 18078337b27e53a92b7eca693293f302b27a6ea6 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Tue, 16 Aug 2022 11:35:07 -0700 Subject: [PATCH 082/109] getProof encoding fix for 4249 (#4261) * getProof encoding fix for 4249 Signed-off-by: garyschulte --- CHANGELOG.md | 1 + .../api/jsonrpc/internal/results/proof/StorageEntryProof.java | 2 +- .../ethereum/api/jsonrpc/internal/methods/EthGetProofTest.java | 2 ++ .../besu/ethereum/api/jsonrpc/eth/eth_getProof_blockHash.json | 2 +- .../ethereum/api/jsonrpc/eth/eth_getProof_blockHashObject.json | 2 +- .../api/jsonrpc/eth/eth_getProof_blockHashObjectCanonical.json | 2 +- .../jsonrpc/eth/eth_getProof_blockHashObjectCanonicalFalse.json | 2 +- .../besu/ethereum/api/jsonrpc/eth/eth_getProof_blockNumber.json | 2 +- .../api/jsonrpc/eth/eth_getProof_blockNumberObject.json | 2 +- .../besu/ethereum/api/jsonrpc/eth/eth_getProof_latest.json | 2 +- .../besu/ethereum/api/jsonrpc/eth/eth_getProof_pending.json | 2 +- 11 files changed, 12 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c66b1501fdb..1d136811258 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ ### Bug Fixes - Fixes off-by-one error for mainnet TTD fallback [#4223](https://github.com/hyperledger/besu/pull/4223) - Fix off-by-one error in AbstractRetryingPeerTask [#4254](https://github.com/hyperledger/besu/pull/4254) +- Fix encoding of key (short hex) in eth_getProof [#4261](https://github.com/hyperledger/besu/pull/4261) ## 22.7.0 diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/proof/StorageEntryProof.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/proof/StorageEntryProof.java index 08ceba3f96d..b01e83485fe 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/proof/StorageEntryProof.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/proof/StorageEntryProof.java @@ -39,7 +39,7 @@ public StorageEntryProof(final UInt256 key, final UInt256 value, final List Date: Wed, 17 Aug 2022 15:48:53 -0400 Subject: [PATCH 083/109] Block prop on first final (#4265) * start filtering peers after 1 finalized instead of 2 * stops counting finalized, and starts filtering on first finalized * DefaultSynchronizer now listens to Forkhoice messages so it can stop block propagation at finalization, as opposed to TTD (previous behavior) Signed-off-by: Justin Florentine --- .../controller/BesuControllerBuilder.java | 49 ++++++++++++++++--- .../ethereum/eth/manager/MergePeerFilter.java | 17 ++++--- .../eth/sync/BlockPropagationManager.java | 16 ++++-- .../eth/sync/DefaultSynchronizer.java | 16 +++++- .../AbstractBlockPropagationManagerTest.java | 23 +++++---- 5 files changed, 92 insertions(+), 29 deletions(-) diff --git a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java index ae7490b6132..c9da9fe9f22 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java @@ -411,19 +411,14 @@ public BesuController build() { final PivotBlockSelector pivotBlockSelector = createPivotSelector(protocolContext); final Synchronizer synchronizer = - new DefaultSynchronizer( - syncConfig, + createSynchronizer( protocolSchedule, - protocolContext, worldStateStorage, - ethProtocolManager.getBlockBroadcaster(), + protocolContext, maybePruner, ethContext, syncState, - dataDirectory, - clock, - metricsSystem, - getFullSyncTerminationCondition(protocolContext.getBlockchain()), + ethProtocolManager, pivotBlockSelector); final MiningCoordinator miningCoordinator = @@ -469,6 +464,44 @@ public BesuController build() { additionalPluginServices); } + private Synchronizer createSynchronizer( + final ProtocolSchedule protocolSchedule, + final WorldStateStorage worldStateStorage, + final ProtocolContext protocolContext, + final Optional maybePruner, + final EthContext ethContext, + final SyncState syncState, + final EthProtocolManager ethProtocolManager, + final PivotBlockSelector pivotBlockSelector) { + + final GenesisConfigOptions maybeForTTD = configOptionsSupplier.get(); + + DefaultSynchronizer toUse = + new DefaultSynchronizer( + syncConfig, + protocolSchedule, + protocolContext, + worldStateStorage, + ethProtocolManager.getBlockBroadcaster(), + maybePruner, + ethContext, + syncState, + dataDirectory, + clock, + metricsSystem, + getFullSyncTerminationCondition(protocolContext.getBlockchain()), + pivotBlockSelector); + if (maybeForTTD.getTerminalTotalDifficulty().isPresent()) { + LOG.info( + "TTD present, creating DefaultSynchronizer that stops propagating after finalization"); + protocolContext + .getConsensusContext(MergeContext.class) + .addNewForkchoiceMessageListener(toUse); + } + + return toUse; + } + private PivotBlockSelector createPivotSelector(final ProtocolContext protocolContext) { final PivotSelectorFromPeers pivotSelectorFromPeers = new PivotSelectorFromPeers(syncConfig); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/MergePeerFilter.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/MergePeerFilter.java index a807785f948..bedf48aeaf5 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/MergePeerFilter.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/MergePeerFilter.java @@ -26,7 +26,7 @@ import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage.DisconnectReason; import java.util.Optional; -import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.StampedLock; import org.slf4j.Logger; @@ -36,8 +36,7 @@ public class MergePeerFilter implements MergeStateHandler, ForkchoiceMessageList private Optional powTerminalDifficulty = Optional.of(Difficulty.MAX_VALUE); private final StampedLock powTerminalDifficultyLock = new StampedLock(); - private Hash lastFinalized = Hash.ZERO; - private final AtomicLong numFinalizedSeen = new AtomicLong(0); + private final AtomicBoolean finalized = new AtomicBoolean(false); private static final Logger LOG = LoggerFactory.getLogger(MergePeerFilter.class); public boolean disconnectIfPoW(final StatusMessage status, final EthPeer peer) { @@ -70,7 +69,7 @@ public boolean disconnectIfGossipingBlocks(final Message message, final EthPeer } private boolean isFinalized() { - return this.numFinalizedSeen.get() > 1; + return this.finalized.get(); } @Override @@ -79,10 +78,12 @@ public void onNewForkchoiceMessage( final Optional maybeFinalizedBlockHash, final Hash safeBlockHash) { if (maybeFinalizedBlockHash.isPresent() - && !maybeFinalizedBlockHash.get().equals(this.lastFinalized)) { - this.lastFinalized = maybeFinalizedBlockHash.get(); - this.numFinalizedSeen.getAndIncrement(); - LOG.debug("have seen {} finalized blocks", this.numFinalizedSeen); + && !maybeFinalizedBlockHash + .get() + .equals( + Hash.ZERO)) { // forkchoices send finalized as 0 after ttd, but before an epoch is + // finalized + this.finalized.set(true); } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java index f57a4486952..eec2c4b45a2 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java @@ -16,6 +16,7 @@ import static org.hyperledger.besu.util.Slf4jLambdaHelper.traceLambda; +import org.hyperledger.besu.consensus.merge.ForkchoiceMessageListener; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.BadBlockManager; @@ -64,7 +65,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class BlockPropagationManager { +public class BlockPropagationManager implements ForkchoiceMessageListener { private static final Logger LOG = LoggerFactory.getLogger(BlockPropagationManager.class); private final SynchronizerConfiguration config; private final ProtocolSchedule protocolSchedule; @@ -582,8 +583,7 @@ private String toLogString(final Collection newBlockHashs) { private void reactToTTDReachedEvent(final boolean ttdReached) { if (started.get() && ttdReached) { - LOG.info("Block propagation was running, then ttd reached, stopping"); - stop(); + LOG.info("Block propagation was running, then ttd reached"); } else if (!started.get()) { start(); } @@ -602,4 +602,14 @@ public String toString() { + pendingBlocksManager + '}'; } + + @Override + public void onNewForkchoiceMessage( + final Hash headBlockHash, + final Optional maybeFinalizedBlockHash, + final Hash safeBlockHash) { + if (maybeFinalizedBlockHash.isPresent() && !maybeFinalizedBlockHash.get().equals(Hash.ZERO)) { + stop(); + } + } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java index 34d31764bc4..091feca3d52 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java @@ -16,6 +16,8 @@ import static com.google.common.base.Preconditions.checkNotNull; +import org.hyperledger.besu.consensus.merge.ForkchoiceMessageListener; +import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.Synchronizer; import org.hyperledger.besu.ethereum.eth.manager.EthContext; @@ -45,7 +47,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class DefaultSynchronizer implements Synchronizer { +public class DefaultSynchronizer implements Synchronizer, ForkchoiceMessageListener { private static final Logger LOG = LoggerFactory.getLogger(DefaultSynchronizer.class); @@ -302,4 +304,16 @@ private Void finalizeSync(final Void unused) { running.set(false); return null; } + + @Override + public void onNewForkchoiceMessage( + final Hash headBlockHash, + final Optional maybeFinalizedBlockHash, + final Hash safeBlockHash) { + if (this.blockPropagationManager.isPresent()) { + this.blockPropagationManager + .get() + .onNewForkchoiceMessage(headBlockHash, maybeFinalizedBlockHash, safeBlockHash); + } + } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java index 2aec4c302b5..ac6aa6550ad 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; +import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.ConsensusContext; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.BadBlockManager; @@ -61,6 +62,7 @@ import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.function.Supplier; @@ -87,6 +89,7 @@ public abstract class AbstractBlockPropagationManagerTest { SynchronizerConfiguration.builder().blockPropagationRange(-10, 30).build())); protected SyncState syncState; protected final MetricsSystem metricsSystem = new NoOpMetricsSystem(); + private final Hash finalizedHash = Hash.fromHexStringLenient("0x1337"); protected void setup(final DataStorageFormat dataStorageFormat) { blockchainUtil = BlockchainSetupUtil.forTesting(dataStorageFormat); @@ -842,25 +845,27 @@ public void shouldThrowErrorWhenNoValidPeerAvailable() { } @Test - public void shouldStopWhenTTDReached() { + public void shouldStopWhenFinalized() { blockPropagationManager.start(); - syncState.setReachedTerminalDifficulty(true); + // syncState.setReachedTerminalDifficulty(true); + blockPropagationManager.onNewForkchoiceMessage(null, Optional.of(this.finalizedHash), null); assertThat(blockPropagationManager.isRunning()).isFalse(); assertThat(ethProtocolManager.ethContext().getEthMessages().messageCodesHandled()) .doesNotContain(EthPV62.NEW_BLOCK_HASHES, EthPV62.NEW_BLOCK); } @Test - public void shouldRestartWhenTTDReachedReturnsFalse() { + public void shouldRestartWhenTTDReachedReturnsFalseAfterFinalizing() { blockPropagationManager.start(); syncState.setReachedTerminalDifficulty(true); + blockPropagationManager.onNewForkchoiceMessage(null, Optional.of(this.finalizedHash), null); assertThat(blockPropagationManager.isRunning()).isFalse(); syncState.setReachedTerminalDifficulty(false); assertThat(blockPropagationManager.isRunning()).isTrue(); } @Test - public void shouldNotListenToNewBlockHashesAnnouncementsWhenTTDReached() { + public void shouldNotListenToNewBlockHashesAnnouncementsWhenTTDReachedAndFinal() { blockchainUtil.importFirstBlocks(2); final Block nextBlock = blockchainUtil.getBlock(2); @@ -878,7 +883,7 @@ public void shouldNotListenToNewBlockHashesAnnouncementsWhenTTDReached() { final Responder responder = RespondingEthPeer.blockchainResponder(getFullBlockchain()); syncState.setReachedTerminalDifficulty(true); - + blockPropagationManager.onNewForkchoiceMessage(null, Optional.of(this.finalizedHash), null); // Broadcast message EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, peer, nextAnnouncement); peer.respondWhile(responder, peer::hasOutstandingRequests); @@ -888,7 +893,7 @@ public void shouldNotListenToNewBlockHashesAnnouncementsWhenTTDReached() { } @Test - public void shouldNotListenToNewBlockAnnouncementsWhenTTDReached() { + public void shouldNotListenToNewBlockAnnouncementsWhenTTDReachedAndFinal() { blockchainUtil.importFirstBlocks(2); final Block nextBlock = blockchainUtil.getBlock(2); @@ -904,7 +909,7 @@ public void shouldNotListenToNewBlockAnnouncementsWhenTTDReached() { final Responder responder = RespondingEthPeer.blockchainResponder(getFullBlockchain()); syncState.setReachedTerminalDifficulty(true); - + blockPropagationManager.onNewForkchoiceMessage(null, Optional.of(this.finalizedHash), null); // Broadcast message EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, peer, nextAnnouncement); peer.respondWhile(responder, peer::hasOutstandingRequests); @@ -914,13 +919,13 @@ public void shouldNotListenToNewBlockAnnouncementsWhenTTDReached() { } @Test - public void shouldNotListenToBlockAddedEventsWhenTTDReached() { + public void shouldNotListenToBlockAddedEventsWhenTTDReachedAndFinal() { blockchainUtil.importFirstBlocks(2); blockPropagationManager.start(); syncState.setReachedTerminalDifficulty(true); - + blockPropagationManager.onNewForkchoiceMessage(null, Optional.of(this.finalizedHash), null); blockchainUtil.importBlockAtIndex(2); assertThat(blockPropagationManager.isRunning()).isFalse(); From 113bd54c6b0ff748a3ed23f2e89fa31a4cb73795 Mon Sep 17 00:00:00 2001 From: Stefan Pingel <16143240+pinges@users.noreply.github.com> Date: Thu, 18 Aug 2022 11:49:09 +1000 Subject: [PATCH 084/109] make obvious when a breach of protocol is logged, add peer in some places (#4268) Signed-off-by: Stefan Co-authored-by: Sally MacFarlane --- .../besu/ethereum/eth/manager/EthProtocolManager.java | 11 ++++++++--- .../besu/ethereum/eth/manager/RequestManager.java | 10 +++++++++- .../manager/task/AbstractGetHeadersFromPeerTask.java | 3 ++- .../ethereum/eth/sync/BlockPropagationManager.java | 4 ++-- .../ethereum/eth/sync/PipelineChainDownloader.java | 2 +- .../eth/sync/tasks/DownloadHeaderSequenceTask.java | 4 ++-- .../NewPooledTransactionHashesMessageProcessor.java | 4 +++- .../transactions/TransactionsMessageProcessor.java | 5 ++++- .../ethereum/p2p/rlpx/connections/netty/DeFramer.java | 4 ++-- 9 files changed, 33 insertions(+), 14 deletions(-) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java index 3956ce1cf29..1dc80b10230 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java @@ -257,7 +257,7 @@ public void processMessage(final Capability cap, final Message message) { } else if (!ethPeer.statusHasBeenReceived()) { // Peers are required to send status messages before any other message type LOG.debug( - "{} requires a Status ({}) message to be sent first. Instead, received message {}. Disconnecting from {}.", + "{} requires a Status ({}) message to be sent first. Instead, received message {} (BREACH_OF_PROTOCOL). Disconnecting from {}.", this.getClass().getSimpleName(), EthPV62.STATUS, code, @@ -277,7 +277,9 @@ public void processMessage(final Capability cap, final Message message) { final EthMessage ethMessage = new EthMessage(ethPeer, messageData); if (!ethPeer.validateReceivedMessage(ethMessage, getSupportedProtocol())) { - LOG.debug("Unsolicited message received, disconnecting from EthPeer: {}", ethPeer); + LOG.debug( + "Unsolicited message received (BREACH_OF_PROTOCOL), disconnecting from EthPeer: {}", + ethPeer); ethPeer.disconnect(DisconnectReason.BREACH_OF_PROTOCOL); return; } @@ -308,7 +310,10 @@ public void processMessage(final Capability cap, final Message message) { } } catch (final RLPException e) { LOG.debug( - "Received malformed message {} , disconnecting: {}", messageData.getData(), ethPeer, e); + "Received malformed message {} (BREACH_OF_PROTOCOL), disconnecting: {}", + messageData.getData(), + ethPeer, + e); ethPeer.disconnect(DisconnectMessage.DisconnectReason.BREACH_OF_PROTOCOL); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/RequestManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/RequestManager.java index 800836df9a8..989af18781f 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/RequestManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/RequestManager.java @@ -29,7 +29,12 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class RequestManager { + + private static final Logger LOG = LoggerFactory.getLogger(RequestManager.class); private final AtomicLong requestIdCounter = new AtomicLong(0); private final Map responseStreams = new ConcurrentHashMap<>(); private final EthPeer peer; @@ -73,7 +78,10 @@ public void dispatchResponse(final EthMessage ethMessage) { .ifPresentOrElse( responseStream -> responseStream.processMessage(requestIdAndEthMessage.getValue()), // disconnect on incorrect requestIds - () -> peer.disconnect(DisconnectMessage.DisconnectReason.BREACH_OF_PROTOCOL)); + () -> { + LOG.debug("Request ID incorrect (BREACH_OF_PROTOCOL), disconnecting peer {}", peer); + peer.disconnect(DisconnectMessage.DisconnectReason.BREACH_OF_PROTOCOL); + }); } else { // otherwise iterate through all of them streams.forEach(stream -> stream.processMessage(ethMessage.getData())); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractGetHeadersFromPeerTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractGetHeadersFromPeerTask.java index 0fec6bf9806..58d5800f11d 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractGetHeadersFromPeerTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractGetHeadersFromPeerTask.java @@ -109,7 +109,8 @@ protected Optional> processResponse( final BlockHeader child = reverse ? prevBlockHeader : header; if (!parent.getHash().equals(child.getParentHash())) { LOG.debug( - "Sequential headers must form a chain through hashes, disconnecting peer: {}", peer); + "Sequential headers must form a chain through hashes (BREACH_OF_PROTOCOL), disconnecting peer: {}", + peer); peer.disconnect(DisconnectMessage.DisconnectReason.BREACH_OF_PROTOCOL); return Optional.empty(); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java index eec2c4b45a2..1370b80589f 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java @@ -296,7 +296,7 @@ private void handleNewBlockFromNetwork(final EthMessage message) { importOrSavePendingBlock(block, message.getPeer().nodeId()); } catch (final RLPException e) { LOG.debug( - "Malformed NEW_BLOCK message received from peer, disconnecting: {}", + "Malformed NEW_BLOCK message received from peer (BREACH_OF_PROTOCOL), disconnecting: {}", message.getPeer(), e); message.getPeer().disconnect(DisconnectReason.BREACH_OF_PROTOCOL); @@ -359,7 +359,7 @@ private void handleNewBlockHashesFromNetwork(final EthMessage message) { } } catch (final RLPException e) { LOG.debug( - "Malformed NEW_BLOCK_HASHES message received from peer, disconnecting: {}", + "Malformed NEW_BLOCK_HASHES message received from peer (BREACH_OF_PROTOCOL), disconnecting: {}", message.getPeer(), e); message.getPeer().disconnect(DisconnectReason.BREACH_OF_PROTOCOL); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/PipelineChainDownloader.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/PipelineChainDownloader.java index bedf5ea2ceb..6d3abe3d5bc 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/PipelineChainDownloader.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/PipelineChainDownloader.java @@ -119,7 +119,7 @@ private CompletionStage handleFailedDownload(final Throwable error) { pipelineErrorCounter.inc(); if (ExceptionUtils.rootCause(error) instanceof InvalidBlockException) { LOG.warn( - "Invalid block detected. Disconnecting from sync target. {}", + "Invalid block detected (BREACH_OF_PROTOCOL). Disconnecting from sync target. {}", ExceptionUtils.rootCause(error).getMessage()); syncState.disconnectSyncTarget(DisconnectReason.BREACH_OF_PROTOCOL); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTask.java index 2923605ca4f..066e4898593 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DownloadHeaderSequenceTask.java @@ -219,10 +219,10 @@ private CompletableFuture> processHeaders( if (error == null && blockPeerTaskResult.getResult() != null) { badBlockManager.addBadBlock(blockPeerTaskResult.getResult()); } - headersResult.getPeer().disconnect(DisconnectReason.BREACH_OF_PROTOCOL); LOG.debug( - "Received invalid headers from peer, disconnecting from: {}", + "Received invalid headers from peer (BREACH_OF_PROTOCOL), disconnecting from: {}", headersResult.getPeer()); + headersResult.getPeer().disconnect(DisconnectReason.BREACH_OF_PROTOCOL); future.completeExceptionally( new InvalidBlockException( "Header failed validation.", diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageProcessor.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageProcessor.java index e69dbcf8943..e0e00dd4aae 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageProcessor.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageProcessor.java @@ -133,7 +133,9 @@ private void processNewPooledTransactionHashesMessage( } catch (final RLPException ex) { if (peer != null) { LOG.debug( - "Malformed pooled transaction hashes message received, disconnecting: {}", peer, ex); + "Malformed pooled transaction hashes message received (BREACH_OF_PROTOCOL), disconnecting: {}", + peer, + ex); peer.disconnect(DisconnectReason.BREACH_OF_PROTOCOL); } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageProcessor.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageProcessor.java index 6bd55f58495..f0ba391874a 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageProcessor.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageProcessor.java @@ -112,7 +112,10 @@ private void processTransactionsMessage( } catch (final RLPException ex) { if (peer != null) { - LOG.debug("Malformed transaction message received, disconnecting: {}", peer, ex); + LOG.debug( + "Malformed transaction message received (BREACH_OF_PROTOCOL), disconnecting: {}", + peer, + ex); peer.disconnect(DisconnectReason.BREACH_OF_PROTOCOL); } } diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramer.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramer.java index 44d325d7329..5c78124b98f 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramer.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/connections/netty/DeFramer.java @@ -184,7 +184,7 @@ protected void decode(final ChannelHandlerContext ctx, final ByteBuf in, final L } else { // Unexpected message - disconnect LOG.debug( - "Message received before HELLO's exchanged, disconnecting. Peer: {}, Code: {}, Data: {}", + "Message received before HELLO's exchanged (BREACH_OF_PROTOCOL), disconnecting. Peer: {}, Code: {}, Data: {}", expectedPeer.map(Peer::getEnodeURLString).orElse("unknown"), message.getCode(), message.getData().toString()); @@ -227,7 +227,7 @@ public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable thr if (cause instanceof FramingException || cause instanceof RLPException || cause instanceof IllegalArgumentException) { - LOG.debug("Invalid incoming message", throwable); + LOG.debug("Invalid incoming message (BREACH_OF_PROTOCOL)", throwable); if (connectFuture.isDone() && !connectFuture.isCompletedExceptionally()) { connectFuture.get().disconnect(DisconnectMessage.DisconnectReason.BREACH_OF_PROTOCOL); return; From 60b806cc5f5af1f71184f8b59ef0b9ea5b81269f Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 17 Aug 2022 22:40:26 -0600 Subject: [PATCH 085/109] Gradle repository maintenance (#4273) Cleanup repository references and limit scope of non-mavenCentral repositories. Signed-off-by: Danno Ferrin --- build.gradle | 22 +++++++++++++++++----- settings.gradle | 10 ++++++++-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index 356a7290114..a4e5651b89f 100644 --- a/build.gradle +++ b/build.gradle @@ -103,14 +103,26 @@ allprojects { targetCompatibility = 11 repositories { + maven { + url 'https://hyperledger.jfrog.io/hyperledger/besu-maven' + content { includeGroupByRegex('org\\.hyperledger\\..*') } + } + maven { + url 'https://artifacts.consensys.net/public/maven/maven/' + content { includeGroupByRegex('tech\\.pegasys\\..*') } + } + maven { + url 'https://dl.cloudsmith.io/public/consensys/quorum-mainnet-launcher/maven/' + content { includeGroupByRegex('net\\.consensys\\..*') } + } + maven { + url 'https://splunk.jfrog.io/splunk/ext-releases-local' + content { includeGroupByRegex('com\\.splunk\\..*') } + } mavenCentral() - maven { url "https://hyperledger.jfrog.io/hyperledger/besu-maven" } - maven { url "https://artifacts.consensys.net/public/maven/maven/" } - maven { url "https://splunk.jfrog.io/splunk/ext-releases-local" } - maven { url "https://dl.cloudsmith.io/public/consensys/quorum-mainnet-launcher/maven/"} } - dependencies { errorprone "com.google.errorprone:error_prone_core" } + dependencies { errorprone 'com.google.errorprone:error_prone_core' } apply plugin: 'com.diffplug.spotless' spotless { diff --git a/settings.gradle b/settings.gradle index 86346e03959..68ad95f90dd 100644 --- a/settings.gradle +++ b/settings.gradle @@ -16,13 +16,19 @@ pluginManagement { repositories { - gradlePluginPortal() /* * Temporary repository to host the improved version of the * com.github.hierynomus.license plugin. Can be removed when an * official version with the fix is release upstream */ - maven { url = uri("https://raw.githubusercontent.com/ConsenSys/license-gradle-plugin-fix-artifacts/main/") } + maven { + url = uri('https://raw.githubusercontent.com/ConsenSys/license-gradle-plugin-fix-artifacts/main/') + content { + includeGroup('com.github.hierynomus.license') + includeGroup('com.hierynomus.gradle.plugins') + } + } + gradlePluginPortal() } } From cdeecf36fd1ba1b7b4cb6d083efcb5eb13fbde53 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Thu, 18 Aug 2022 10:52:50 -0700 Subject: [PATCH 086/109] Bugfix/clique post merge fast sync (#4276) * if merge enabled, wrap two clique rules in composed Attached rule to enable fast-sync to proceed normally for post-merge networks * move BlockPropagationManager warning to debug until #4274 Signed-off-by: garyschulte --- CHANGELOG.md | 1 + .../TransitionControllerBuilderTest.java | 57 +++++++++++++++++++ .../BlockHeaderValidationRulesetFactory.java | 32 +++++++++-- .../mainnet/MainnetBlockHeaderValidator.java | 30 +++++----- ... => AttachedComposedFromDetachedRule.java} | 17 ++---- .../eth/sync/BlockPropagationManager.java | 2 +- 6 files changed, 109 insertions(+), 30 deletions(-) rename ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/{AttachedProofOfWorkValidationRule.java => AttachedComposedFromDetachedRule.java} (67%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d136811258..fa99e9abd5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - Fixes off-by-one error for mainnet TTD fallback [#4223](https://github.com/hyperledger/besu/pull/4223) - Fix off-by-one error in AbstractRetryingPeerTask [#4254](https://github.com/hyperledger/besu/pull/4254) - Fix encoding of key (short hex) in eth_getProof [#4261](https://github.com/hyperledger/besu/pull/4261) +- Fix for post-merge networks fast-sync [#4224](https://github.com/hyperledger/besu/pull/4224), [#4276](https://github.com/hyperledger/besu/pull/4276) ## 22.7.0 diff --git a/besu/src/test/java/org/hyperledger/besu/controller/TransitionControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/TransitionControllerBuilderTest.java index b49a0eeb855..207c1a9f934 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/TransitionControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/TransitionControllerBuilderTest.java @@ -21,12 +21,15 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +import org.hyperledger.besu.consensus.clique.BlockHeaderValidationRulesetFactory; import org.hyperledger.besu.consensus.clique.CliqueContext; +import org.hyperledger.besu.consensus.common.EpochManager; import org.hyperledger.besu.consensus.merge.MergeContext; import org.hyperledger.besu.consensus.merge.PostMergeContext; import org.hyperledger.besu.consensus.merge.TransitionProtocolSchedule; import org.hyperledger.besu.consensus.merge.blockcreation.TransitionCoordinator; import org.hyperledger.besu.crypto.NodeKeyUtils; +import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; @@ -36,8 +39,12 @@ import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import org.hyperledger.besu.ethereum.mainnet.BlockHeaderValidator; +import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; +import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderValidator; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; +import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.storage.StorageProvider; import java.util.Optional; @@ -178,6 +185,56 @@ public void assertPostMergeScheduleForPostMergeExactlyAtTerminalDifficultyIfNotF .isEqualTo(postMergeProtocolSpec); } + @Test + public void assertCliqueDetachedHeaderValidationPreMerge() { + BlockHeaderValidator cliqueValidator = + BlockHeaderValidationRulesetFactory.cliqueBlockHeaderValidator( + 5L, new EpochManager(5L), Optional.of(FeeMarket.london(1L)), true) + .build(); + assertDetachedRulesForPostMergeBlocks(cliqueValidator); + } + + @Test + public void assertPoWDetachedHeaderValidationPreMerge() { + BlockHeaderValidator powValidator = + MainnetBlockHeaderValidator.createBaseFeeMarketValidator(FeeMarket.london(1L), true) + .build(); + assertDetachedRulesForPostMergeBlocks(powValidator); + } + + void assertDetachedRulesForPostMergeBlocks(final BlockHeaderValidator validator) { + var preMergeProtocolSpec = mock(ProtocolSpec.class); + when(preMergeProtocolSpec.getBlockHeaderValidator()).thenReturn(validator); + + when(preMergeProtocolSchedule.getByBlockNumber(anyLong())).thenReturn(preMergeProtocolSpec); + + var mockParentBlock = + new BlockHeaderTestFixture() + .number(100L) + .baseFeePerGas(Wei.of(7L)) + .gasLimit(5000L) + .buildHeader(); + + var mockBlock = + new BlockHeaderTestFixture() + .number(101L) + .timestamp(1000L) + .baseFeePerGas(Wei.of(7L)) + .gasLimit(5000L) + .difficulty(Difficulty.of(0L)) + .parentHash(mockParentBlock.getHash()) + .buildHeader(); + + var mergeFriendlyValidation = + transitionProtocolSchedule + .getPreMergeSchedule() + .getByBlockNumber(1L) + .getBlockHeaderValidator() + .validateHeader( + mockBlock, mockParentBlock, protocolContext, HeaderValidationMode.DETACHED_ONLY); + assertThat(mergeFriendlyValidation).isTrue(); + } + TransitionCoordinator buildTransitionCoordinator( final BesuControllerBuilder preMerge, final MergeBesuControllerBuilder postMerge) { var builder = new TransitionBesuControllerBuilder(preMerge, postMerge); diff --git a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/BlockHeaderValidationRulesetFactory.java b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/BlockHeaderValidationRulesetFactory.java index 15ab95bf0ad..3a2698a6cc1 100644 --- a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/BlockHeaderValidationRulesetFactory.java +++ b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/BlockHeaderValidationRulesetFactory.java @@ -17,6 +17,7 @@ import static org.hyperledger.besu.ethereum.mainnet.AbstractGasLimitSpecification.DEFAULT_MAX_GAS_LIMIT; import static org.hyperledger.besu.ethereum.mainnet.AbstractGasLimitSpecification.DEFAULT_MIN_GAS_LIMIT; +import org.hyperledger.besu.config.MergeConfigOptions; import org.hyperledger.besu.consensus.clique.headervalidationrules.CliqueDifficultyValidationRule; import org.hyperledger.besu.consensus.clique.headervalidationrules.CliqueExtraDataValidationRule; import org.hyperledger.besu.consensus.clique.headervalidationrules.CoinbaseHeaderValidationRule; @@ -28,6 +29,7 @@ import org.hyperledger.besu.ethereum.mainnet.BlockHeaderValidator; import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.AncestryValidationRule; +import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.AttachedComposedFromDetachedRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.BaseFeeMarketBlockHeaderGasPriceValidationRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.ConstantFieldValidationRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.GasLimitRangeAndDeltaValidationRule; @@ -37,6 +39,8 @@ import java.util.Optional; +import com.google.common.annotations.VisibleForTesting; + public class BlockHeaderValidationRulesetFactory { /** @@ -54,22 +58,28 @@ public static BlockHeaderValidator.Builder cliqueBlockHeaderValidator( final long secondsBetweenBlocks, final EpochManager epochManager, final Optional baseFeeMarket) { + return cliqueBlockHeaderValidator( + secondsBetweenBlocks, epochManager, baseFeeMarket, MergeConfigOptions.isMergeEnabled()); + } + + @VisibleForTesting + public static BlockHeaderValidator.Builder cliqueBlockHeaderValidator( + final long secondsBetweenBlocks, + final EpochManager epochManager, + final Optional baseFeeMarket, + final boolean isMergeEnabled) { final BlockHeaderValidator.Builder builder = new BlockHeaderValidator.Builder() .addRule(new AncestryValidationRule()) .addRule(new TimestampBoundedByFutureParameter(10)) - .addRule(new TimestampMoreRecentThanParent(secondsBetweenBlocks)) .addRule( new GasLimitRangeAndDeltaValidationRule( DEFAULT_MIN_GAS_LIMIT, DEFAULT_MAX_GAS_LIMIT, baseFeeMarket)) - .addRule( - new ConstantFieldValidationRule<>("MixHash", BlockHeader::getMixHash, Hash.ZERO)) .addRule( new ConstantFieldValidationRule<>( "OmmersHash", BlockHeader::getOmmersHash, Hash.EMPTY_LIST_HASH)) .addRule(new CliqueExtraDataValidationRule(epochManager)) - .addRule(new VoteValidationRule()) .addRule(new CliqueDifficultyValidationRule()) .addRule(new SignerRateLimitValidationRule()) .addRule(new CoinbaseHeaderValidationRule(epochManager)) @@ -79,6 +89,20 @@ public static BlockHeaderValidator.Builder cliqueBlockHeaderValidator( builder.addRule(new BaseFeeMarketBlockHeaderGasPriceValidationRule(baseFeeMarket.get())); } + var mixHashRule = + new ConstantFieldValidationRule<>("MixHash", BlockHeader::getMixHash, Hash.ZERO); + var voteValidationRule = new VoteValidationRule(); + var cliqueTimestampRule = new TimestampMoreRecentThanParent(secondsBetweenBlocks); + + if (isMergeEnabled) { + builder + .addRule(new AttachedComposedFromDetachedRule(mixHashRule)) + .addRule(new AttachedComposedFromDetachedRule(voteValidationRule)) + .addRule(new AttachedComposedFromDetachedRule(cliqueTimestampRule)); + } else { + builder.addRule(mixHashRule).addRule(voteValidationRule).addRule(cliqueTimestampRule); + } + return builder; } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java index 04c1e6562af..bd2bfd68be9 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java @@ -18,7 +18,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.AncestryValidationRule; -import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.AttachedProofOfWorkValidationRule; +import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.AttachedComposedFromDetachedRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.BaseFeeMarketBlockHeaderGasPriceValidationRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.CalculatedDifficultyValidationRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.ConstantFieldValidationRule; @@ -31,6 +31,7 @@ import java.util.Optional; +import com.google.common.annotations.VisibleForTesting; import org.apache.tuweni.bytes.Bytes; public final class MainnetBlockHeaderValidator { @@ -124,6 +125,12 @@ public static BlockHeaderValidator.Builder createPgaBlockHeaderValidator( public static BlockHeaderValidator.Builder createBaseFeeMarketValidator( final BaseFeeMarket baseFeeMarket) { + return createBaseFeeMarketValidator(baseFeeMarket, MergeConfigOptions.isMergeEnabled()); + } + + @VisibleForTesting + public static BlockHeaderValidator.Builder createBaseFeeMarketValidator( + final BaseFeeMarket baseFeeMarket, final boolean isMergeEnabled) { var builder = new BlockHeaderValidator.Builder() .addRule(CalculatedDifficultyValidationRule::new) @@ -138,19 +145,16 @@ public static BlockHeaderValidator.Builder createBaseFeeMarketValidator( .addRule((new BaseFeeMarketBlockHeaderGasPriceValidationRule(baseFeeMarket))); // if merge is enabled, use the attached version of the proof of work validation rule - if (MergeConfigOptions.isMergeEnabled()) { - builder.addRule( - new AttachedProofOfWorkValidationRule( - new EpochCalculator.DefaultEpochCalculator(), - PoWHasher.ETHASH_LIGHT, - Optional.of(baseFeeMarket))); - + var powValidationRule = + new ProofOfWorkValidationRule( + new EpochCalculator.DefaultEpochCalculator(), + PoWHasher.ETHASH_LIGHT, + Optional.of(baseFeeMarket)); + + if (isMergeEnabled) { + builder.addRule(new AttachedComposedFromDetachedRule(powValidationRule)); } else { - builder.addRule( - new ProofOfWorkValidationRule( - new EpochCalculator.DefaultEpochCalculator(), - PoWHasher.ETHASH_LIGHT, - Optional.of(baseFeeMarket))); + builder.addRule(powValidationRule); } return builder; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/AttachedProofOfWorkValidationRule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/AttachedComposedFromDetachedRule.java similarity index 67% rename from ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/AttachedProofOfWorkValidationRule.java rename to ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/AttachedComposedFromDetachedRule.java index 59cd5b3b3ad..362cfba0e67 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/AttachedProofOfWorkValidationRule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/AttachedComposedFromDetachedRule.java @@ -17,25 +17,18 @@ import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.mainnet.AttachedBlockHeaderValidationRule; -import org.hyperledger.besu.ethereum.mainnet.EpochCalculator; -import org.hyperledger.besu.ethereum.mainnet.PoWHasher; -import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; - -import java.util.Optional; +import org.hyperledger.besu.ethereum.mainnet.DetachedBlockHeaderValidationRule; /** * An attached proof of work validation rule that wraps the detached version of the same. Suitable * for use in block validator stacks supporting the merge. */ -public class AttachedProofOfWorkValidationRule implements AttachedBlockHeaderValidationRule { +public class AttachedComposedFromDetachedRule implements AttachedBlockHeaderValidationRule { - private final ProofOfWorkValidationRule detachedRule; + private final DetachedBlockHeaderValidationRule detachedRule; - public AttachedProofOfWorkValidationRule( - final EpochCalculator epochCalculator, - final PoWHasher hasher, - final Optional feeMarket) { - this.detachedRule = new ProofOfWorkValidationRule(epochCalculator, hasher, feeMarket); + public AttachedComposedFromDetachedRule(final DetachedBlockHeaderValidationRule detachedRule) { + this.detachedRule = detachedRule; } @Override diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java index 1370b80589f..e76b710f9d7 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java @@ -120,7 +120,7 @@ public void stop() { clearListeners(); started.set(false); } else { - LOG.warn("Attempted to stop when we are not even running..."); + LOG.debug("Attempted to stop when we are not even running..."); } } From 1d508bab42df53dba54899b5cc4980100234d0bd Mon Sep 17 00:00:00 2001 From: Justin Florentine Date: Thu, 18 Aug 2022 14:51:37 -0400 Subject: [PATCH 087/109] Panda prove ments (#4267) * breaks pandas up, test coverage Signed-off-by: Justin Florentine --- .../controller/BesuControllerBuilder.java | 3 + .../TransitionBesuControllerBuilder.java | 1 + .../besu/consensus/merge/PandaPrinter.java | 90 ++++++-- .../src/main/resources/ProofOfPanda3.txt | 196 ------------------ .../src/main/resources/finalizedPanda.txt | 58 ++++++ .../merge/src/main/resources/readyPanda.txt | 57 +++++ .../merge/src/main/resources/ttdPanda.txt | 57 +++++ .../consensus/merge/PandaPrinterTest.java | 52 ++++- 8 files changed, 298 insertions(+), 216 deletions(-) delete mode 100644 consensus/merge/src/main/resources/ProofOfPanda3.txt create mode 100644 consensus/merge/src/main/resources/finalizedPanda.txt create mode 100644 consensus/merge/src/main/resources/readyPanda.txt create mode 100644 consensus/merge/src/main/resources/ttdPanda.txt diff --git a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java index c9da9fe9f22..71c912efc06 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java @@ -21,6 +21,7 @@ import org.hyperledger.besu.config.GenesisConfigOptions; import org.hyperledger.besu.consensus.merge.FinalizedBlockHashSupplier; import org.hyperledger.besu.consensus.merge.MergeContext; +import org.hyperledger.besu.consensus.merge.PandaPrinter; import org.hyperledger.besu.consensus.qbft.pki.PkiBlockCreationConfiguration; import org.hyperledger.besu.crypto.NodeKey; import org.hyperledger.besu.datatypes.Hash; @@ -421,6 +422,8 @@ public BesuController build() { ethProtocolManager, pivotBlockSelector); + synchronizer.subscribeInSync(new PandaPrinter()); + final MiningCoordinator miningCoordinator = createMiningCoordinator( protocolSchedule, diff --git a/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java index 3f83c2250c4..4106949c091 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java @@ -219,6 +219,7 @@ public BesuControllerBuilder storageProvider(final StorageProvider storageProvid @Override public BesuController build() { BesuController controller = super.build(); + PandaPrinter.hasTTD(); PostMergeContext.get().setSyncState(controller.getSyncState()); return controller; } diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PandaPrinter.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PandaPrinter.java index 5ec89fabcf4..b5340c70b5a 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PandaPrinter.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PandaPrinter.java @@ -16,25 +16,37 @@ package org.hyperledger.besu.consensus.merge; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.Synchronizer.InSyncListener; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; +import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class PandaPrinter { +public class PandaPrinter implements InSyncListener, ForkchoiceMessageListener, MergeStateHandler { private static final Logger LOG = LoggerFactory.getLogger(PandaPrinter.class); - private static final String pandaBanner = PandaPrinter.loadBanner(); - private static final AtomicBoolean beenDisplayed = new AtomicBoolean(); + private static final String readyBanner = PandaPrinter.loadBanner("/readyPanda.txt"); + private static final String ttdBanner = PandaPrinter.loadBanner("/ttdPanda.txt"); + private static final String finalizedBanner = PandaPrinter.loadBanner("/finalizedPanda.txt"); + + private static final AtomicBoolean hasTTD = new AtomicBoolean(false); + private static final AtomicBoolean inSync = new AtomicBoolean(false); + public static final AtomicBoolean readyBeenDisplayed = new AtomicBoolean(); + public static final AtomicBoolean ttdBeenDisplayed = new AtomicBoolean(); + public static final AtomicBoolean finalizedBeenDisplayed = new AtomicBoolean(); - private static String loadBanner() { + private static String loadBanner(final String filename) { Class c = PandaPrinter.class; - InputStream is = c.getResourceAsStream("/ProofOfPanda3.txt"); + InputStream is = c.getResourceAsStream(filename); StringBuilder resultStringBuilder = new StringBuilder(); try (BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { @@ -48,19 +60,71 @@ private static String loadBanner() { return resultStringBuilder.toString(); } - public static boolean printOnFirstCrossing() { - boolean shouldPrint = beenDisplayed.compareAndSet(false, true); - if (shouldPrint) { - LOG.info("\n" + pandaBanner); + public static void hasTTD() { + PandaPrinter.hasTTD.getAndSet(true); + if (hasTTD.get() && inSync.get()) { + printReadyToMerge(); + } + } + + public static void inSync() { + PandaPrinter.inSync.getAndSet(true); + if (inSync.get() && hasTTD.get()) { + printReadyToMerge(); } - return shouldPrint; } - static boolean hasDisplayed() { - return beenDisplayed.get(); + public static void printOnFirstCrossing() { + if (!ttdBeenDisplayed.get()) { + LOG.info("\n" + ttdBanner); + } + ttdBeenDisplayed.compareAndSet(false, true); } static void resetForTesting() { - beenDisplayed.set(false); + ttdBeenDisplayed.set(false); + readyBeenDisplayed.set(false); + finalizedBeenDisplayed.set(false); + } + + public static void printReadyToMerge() { + if (!readyBeenDisplayed.get()) { + LOG.info("\n" + readyBanner); + } + readyBeenDisplayed.compareAndSet(false, true); + } + + public static void printFinalized() { + if (!finalizedBeenDisplayed.get()) { + LOG.info("\n" + finalizedBanner); + } + finalizedBeenDisplayed.compareAndSet(false, true); + } + + @Override + public void onInSyncStatusChange(final boolean newSyncStatus) { + if (newSyncStatus && hasTTD.get()) { + printReadyToMerge(); + } + } + + @Override + public void onNewForkchoiceMessage( + final Hash headBlockHash, + final Optional maybeFinalizedBlockHash, + final Hash safeBlockHash) { + if (maybeFinalizedBlockHash.isPresent() && !maybeFinalizedBlockHash.get().equals(Hash.ZERO)) { + printFinalized(); + } + } + + @Override + public void mergeStateChanged( + final boolean isPoS, + final Optional priorState, + final Optional difficultyStoppedAt) { + if (isPoS && priorState.isPresent() && !priorState.get()) { // just crossed from PoW to PoS + printOnFirstCrossing(); + } } } diff --git a/consensus/merge/src/main/resources/ProofOfPanda3.txt b/consensus/merge/src/main/resources/ProofOfPanda3.txt deleted file mode 100644 index 7855719bf68..00000000000 --- a/consensus/merge/src/main/resources/ProofOfPanda3.txt +++ /dev/null @@ -1,196 +0,0 @@ - - - - - - - - :. :. - #%% %#%= - =%*%% +%++#. =. - %%#*@#++==*##*%+*##= .:+ - -#%%@%#%%@@%%*@%##%= .- - =@@%%#%#@#@*%%@*++ - -@@@@@#*@@@%#%@%@#*. - .%@@%*%@#%%@#@#%%%@*# :: -+. - -#@%+-**#%%*@%+=*%%*%. -%#--..-%#: - :%#%*=%-#*+##%=#==%@%%= -: =. - -%+%*:**@%*####==##%%%#= .. . : - .#@#%###%%#-+*%**%#@@%@## :.. = :*#* .: - -%%%%%+%%%+-+%@%*#%%@%%*%- ..-. .. -#@#. - - *%%@@%*@**-%***@%#%%%@#*@@: . - .. %. - - %%%@@%+@%**@*=%@@#%%%%+*### ...- .. * .- . . : - :. :. .#%#@#%+%%%*%*@%@%*#%@*=%##%. : :. ..:-=*#:...+ - -*.=:=. - %#%%-+%# =-*@%%%#=*%@%%%@@@#++@%+##*%%+ .::+. .:.:=*+#+::....-. .=*= - =+##%#%..: :##:#%##@%*#%#**+*%*##%+%*=-.-% . .-:::.= ** . :: . ++.+... - #%*###%*%%**=+**%##+#**%@*#*#**+**##*+#-+*-+-*- . .:+:. ==-+:.. .%+=:*: - -%%*++##%%#%#%%%#@%#*#%+**+##%%##%*-+#+--*%%#+* . .-===--. .:-=- . #===.. - -###=+%@%%%%%%@@#@%##*=--++-+#***=--=-=**#*@### .:- . .#++==. - -+%++@@@@@@%@@@+@@%=+#*%--::-*+=:-=**#%%#%#@%@. .= .. .#+-:. - -%+*#@@@@@@@@@@+@@%=+%%@%%#+#%#+*###%%%@%%%%%%. . .- . .. ....:. - -*@@@@@@@@%@+%@%#-:#@@@@#%@%#%%%%%%@@@%@%@#% . . .* .... .. - %@@@@@@%*@**@%%#-#@@@@@@@@#%#%@%@%@%%@%@#%: .... .....-: ...... - =%@@@@@#%##@@%%==@@@@@@@@@@@%@@@%@@@@@%#%. . ...... ....*= .... - +@@@@%**%%@%%#=-%%@@@@@@@@@@@@@@@@%%#@@- . -...... .:+++=. . - =#@@%*@%%@%%##--%@@@@@@@@@@@@@@%@*%@%* .::=...:.::-+++=. . - --@@#@%%%#*=.-@@@@@@@@@@@%%@*#%@@% .. ...*..*=. . - =@@@%@@@%#*++-=%@@%@@@@@#+**%@@@* . --.. .. - -@@@%@@%%##**##+==:+-+**=+#%@%%@+ ... - -@@@@%@@#%%%%@@%#+#%%%@#+#%@@@#%= . .. - -%@@@@@@@@@%%%@+%@%@%%##%%#@@@%@- .. . ... - :%@@@%@@@@@%@@#%@%%#=-*++**+@%#@= -+=-.:=: .. - .@@@@@@@@@@@@%@@%*++*%%#%@%#*%%#- .. .= := . .... - #@@@@@@@@@@*@%*+@%@@#@%@@@%*%@. . + . .... - :#@@@@@@@%%%#=*@@%%@@@#%@@##*@:: .. ... :=... ..... - -%@@@@@@@@@%=@@%@%@%@@@@@%#+@# .. .... =.......... - ++%@@@@@@%@*%@%%@@@@@@@@%#**@+ ..: ... .==...... . - #*%@@@@%*+=%##@@@@@%@%%%###+. . :.... ..=+:..:= - *#*#@@@%=*==*##=+*#%@%##+#@+ .. ...+. -=+:--.=-.. - .*#=*%@%*%##@@#%%+#*%@*+#@+ .... . ...+.:.+:::. - *%*+##+#%%%%%%%#%%%%##%- : ... .-=+.:-=*.... - -@@%%%*-%%%%@%%@%@%*%% ....=..:*:.=.... - #@@%***+%+++*++@%%+- ..::=:**+#... - %%%%%%%=%%*+*%@%. .::**=+=:... - :%@@%%%%=##%%*= .:+=-+.... - *@@@@@@%#++ :=+::. - :*%@@@%@@+ :..... - #%@@@@%%# ....... - .#@@@@@@@#= ... .... - #%@%%@%%@@@. ..:..:.. - -###%%%%@@%- . .. . - #*#%#%@@*: - :+- - - - - - - :.-- - .-*+#=---:-*:::-: .-.-== . - -%%@%%%%@%#%@*+*+#* . ...*==+# . - -%%#%%@@@@%@%@%%+=**@:: .-*.*++= - .#%%@@@@@@%@%%@@##***##+ ...=:++%.. - :%%%%@@@@%%*=-+%@###++*%= --*+*:+*... .+=. - :%%@@@@@@%%@*%#*%-@@%*##+*## ...-.*-. .. .-. .- - .:.#@@@@@@@@@@#+%*#@=@@%%%%##%= . .-: ... . .:-=++- - #=@@@@%@%#*#**%@##%-@@++#*.- ......: --: - #%#@@@@@%#*@%%%%@@@%-:: : ..:-. +... - :::@%%@@@@@@=%@*#@%*@@%%. :. ..=: - :%=#@@@@%@%%%%%##*+#%%%+%= :.. - -%%*%%@@@%@#%@%%%%*-=+##=%%- :. :*. - =#%@%@%%@@%%#@@@%@**-#.**%%%@. .#* ..- - -%@@%#@@@@#%%%%%@#=##*-:*%%@@@%. *=. .-:. - -#@@@@%%@%@#@@%@@#*%%%%%##*%###%@: .:- .-. ::.. - ##@@@%#%@@@%@%@@###@%%#%%##%+#*##@@@= .. . +- .:.. - +#@@@@@%%@@@%@#%%%%@@#=:-%%-##*%#%*##%= :- - +% :: -... - :%%@@@@%%@@%@%%%#%%@@@%:%#-#*+-+#%%#+*%= = -=. +@* = .. - %%@@@@@@%%%@@#%*%%#*#%#=*#:%@=%+:%%%+=%= . .*#. %**: = + . - =%@@@@@@@@@%@@%#@#%%#%*+#*:+%@%:--@@%#%# .#:. .#@. = .. - .%@@@@@@@@@@%%@##@@@@%@*=###*%@%*##@@%=. = .+#. : - +@@@@@@@@@%%%*@@+%@@@%%%#+@%%%@*@%@%@% .= +=- .. - %%@@@@@@@@@@%*@%##@@@@%%%=%%%%#@%%@%%= ...:. .. - *@@@@@@@@@@@@%%#%%=%#@@@@@%+%@##%@##%: =.=.. - %@@@@@@@@@@@@@%#@%#*%@@@@%%#*%#@%@*=%* := :-. - +%@@@@@@%@@@@@@@%#%@%%%@@@%*%%##%%#**%. . -:::.: - -##@@@@@@@@@@@@@@@#%%@@%%###%##%@@@#*%- . - - *+#@@@@@@@@@%@@@%@#@@@%#%#%%%%#@##*#@+ . . - -%#%@@@@@@@@@@@@@@%%@@@@@@@@@@@#*%@%@%-+@+.+ . ... . - %@+%@@@@@@@@@@@@@@%@@@@@@@@@@#@%@%##+*##%==@%+. ... . = - -%%=#@@@@@@@@@@@@@@@@@@@@@@@%#@%**%#=%%#=#*#%%%. .. .. : - @@@+#@@@@@@@@@@@@@@@@@@@@@%%@@#:#%=#@@%*++#%### ... . - -@%%#*@@@@@@@@@@@@@@@@@@@%@@%@%-#@#%@@@@===%@@@= .... . :.. - *%%%#*@%@@@@@@@@@@@@@@@@@@@@%@*+@@+%@%%@+++#*=%- . . .. - :@@#%%*%@@@@@@@@@%@@@@@%@@@@@@@**@@*@@%@##+*%%%% .. .-. . ::. - *@%#@%=@@@@@@@@@@@@@@@@@@@@@@%%:%@@#@@@@%=+*+%%* :. . ...- :.. - %@@%%@#%@@@@@@@@@@@@@@@@@@@@@%#-@@@@@%%%%%##*-- .... .....::. . ...-: - -@%#@%@*#@@@@@@@@@@@@@@@@@@@@@%*:%@@@@@@@@%#*: ............ ... . .=. - %@%@@@%%%%@%@@@@@@@@@@@@@@@@@%###*@@@@@@@@@# . .... .:.. . . . .= - .@%%%@@%@#*@#@@@@@@@@@@@@@@@@@@*@-=%@@@@@@@#. .:=:. .. .:. - .@%%%@@@@@%#%@@@@@@@@@@@@@@@@@#***@*==#@%#: ::. ....... - -@@@@@@@@@@#%%@@@@@@@@@@@@@%%#%%%%@%#+.. .... .. ........ - *@@@@@@@@@@@##@@@@@@@@@@%@%*%@@@%%%%%*#% ..................... - :*@@@@@@@@@@@@%%@@@@@@@@@*+%@@@@@@@@#%%%+ .............:....... - .#@@@@%@@@@@@@-=:*#*+== =@%@@@@@@%%%@%@% ...-....... ... ...... . - .%@@@@@@@@@@@. -#@@@@@@@@@@%@% .... .... ......... .. - #@@@@@@@@@@- *@%@@@@@@@@# . . . ... .......... - #%@@@@@@@*: +**%%@@@@@@+ .......... ....... . - :#*#%@@@@= .%@@%@@%@@%=. ......... ........ - :+#+*#+#@# %@@@@@@@%=%= ........ .... . - :@%@*#+@%- @@@@@%%-%** :....... .. - -:==+=. .--+%-: ... - - - - - - - - - - - - - - - - - .. . - %@@# . %#@# - -@@%%- ........ -*@@@= - +@@%+.. ..=#@@% - +@@-. .*@* - .=+. .-. - ..=#%+. *@%+. . - . +@@@@# .@@@@# .. - . @@@@@# @@@@@* .. - . +@#-%@# %%-%@% .. - . %@@%@@- =*@+@@@. . - . #@@@%=. . -@@@@@... - :...+#-.. +*+ .-@@@* . - :. :@@@= -:. .. - :: :%- .-. - .*.-. + .:.. - :*%*- : +*. .. :*- - =@@%+= .:=**-+. . .. -###. - .-%% #@@@%:. +++**#::.. -%#@@+ - +@@@%.#@@@@@%. =*+***-: :.@%@@@@. +%* - :@@@@@#@@@@@@%-. =++*++. :-%@%@@@@@%-#@@%- - *@@@@@#@@@@@@@%:. .#+-+# . :#@@@@@@@@@#%@@@% - +@@@@@*@@@@@@@@# :-:+ ...#@@@@@@@@@@*@@@@@. - .@@@@%@@@@@@@@@@#== . =:@@@@@@@@@@@@#@@@@@. - +@@@@@@@@@@@@@@@%*=. .*%@@@@@@@@@@@@@@#@@@@. - #@@@@@@@@@@@@@@@@@%+--+%@@@@@@%@@%@@@@@@@@@@% - *%@@@@%+%====#%@@@@@@@@@@%%#%%%%%@@@@@@@@@@. - .:. %=:: .-#@@@@@%- ..-#*%@@@@@@#. - =::.. ... ...:-#---:. - .... ..... - ... ... - .. ... - ... .. - ... .:. - ... .. - . .. .. - #+:. .:=* - .*%#:.. ..:*@= - -@@#.-.. ..:%@%. - #@@%:... ..:-@@@: - .%@@@=:..... ....*@@@= - =@@@@%...... ...=@@@@+ - *@@@@@=:... ....:+@@@@* - %@@@@@@+-. . ....::#@@@@# - %@@@@@@@+-... . ...:=%@@@@@% - @@@@@@@@@*:.... .....:=%@@@@@@% - @@@@@@@@@@*-...............:*@@@@@@@@* - .@@@@@@@@@@@*............. :@@@@@@@@@+ - *@@@@@@@@*- . ...... .%@@@@@@@: - +@@@@@@@= .%@@@@@@: - .#@@@@@@+ :@@@@@@@* - -%@@@@@@@* -@@@@@@@@#. - :%@@@@@@@@@ .@@@%@%@@#+ - #-@#@*@@@@: .%@@=@+@%. - ..-=#*@*: .: :. - - - - - diff --git a/consensus/merge/src/main/resources/finalizedPanda.txt b/consensus/merge/src/main/resources/finalizedPanda.txt new file mode 100644 index 00000000000..f932683abbc --- /dev/null +++ b/consensus/merge/src/main/resources/finalizedPanda.txt @@ -0,0 +1,58 @@ + + .. . + %@@# . %#@# + -@@%%- ........ -*@@@= + +@@%+.. ..=#@@% + +@@-. .*@* + .=+. .-. + ..=#%+. *@%+. . + . +@@@@# .@@@@# .. + . @@@@@# @@@@@* .. + . +@#-%@# %%-%@% .. + . %@@%@@- =*@+@@@. . + . #@@@%=. . -@@@@@... + :...+#-.. +*+ .-@@@* . + :. :@@@= -:. .. + :: :%- .-. + .*.-. + .:.. + :*%*- : +*. .. :*- + =@@%+= .:=**-+. . .. -###. + .-%% #@@@%:. +++**#::.. -%#@@+ + +@@@%.#@@@@@%. =*+***-: :.@%@@@@. +%* + :@@@@@#@@@@@@%-. =++*++. :-%@%@@@@@%-#@@%- + *@@@@@#@@@@@@@%:. .#+-+# . :#@@@@@@@@@#%@@@% + +@@@@@*@@@@@@@@# :-:+ ...#@@@@@@@@@@*@@@@@. + .@@@@%@@@@@@@@@@#== . =:@@@@@@@@@@@@#@@@@@. + +@@@@@@@@@@@@@@@%*=. .*%@@@@@@@@@@@@@@#@@@@. + #@@@@@@@@@@@@@@@@@%+--+%@@@@@@%@@%@@@@@@@@@@% + *%@@@@%+%====#%@@@@@@@@@@%%#%%%%%@@@@@@@@@@. + .:. %=:: .-#@@@@@%- ..-#*%@@@@@@#. + =::.. ... ...:-#---:. + .... ..... + ... ... + .. ... + ... .. + ... .:. + ... .. + . .. .. + #+:. .:=* + .*%#:.. ..:*@= + -@@#.-.. ..:%@%. + #@@%:... ..:-@@@: + .%@@@=:..... ....*@@@= + =@@@@%...... ...=@@@@+ + *@@@@@=:... ....:+@@@@* + %@@@@@@+-. . ....::#@@@@# + %@@@@@@@+-... . ...:=%@@@@@% + @@@@@@@@@*:.... .....:=%@@@@@@% + @@@@@@@@@@*-...............:*@@@@@@@@* + .@@@@@@@@@@@*............. :@@@@@@@@@+ + *@@@@@@@@*- . ...... .%@@@@@@@: + +@@@@@@@= .%@@@@@@: + .#@@@@@@+ :@@@@@@@* + -%@@@@@@@* -@@@@@@@@#. + :%@@@@@@@@@ .@@@%@%@@#+ + #-@#@*@@@@: .%@@=@+@%. + ..-=#*@*: .: :. + + \ No newline at end of file diff --git a/consensus/merge/src/main/resources/readyPanda.txt b/consensus/merge/src/main/resources/readyPanda.txt new file mode 100644 index 00000000000..5700d5d26df --- /dev/null +++ b/consensus/merge/src/main/resources/readyPanda.txt @@ -0,0 +1,57 @@ + + + :. :. + #%% %#%= + =%*%% +%++#. =. + %%#*@#++==*##*%+*##= .:+ + -#%%@%#%%@@%%*@%##%= .- + =@@%%#%#@#@*%%@*++ + -@@@@@#*@@@%#%@%@#*. + .%@@%*%@#%%@#@#%%%@*# :: -+. + -#@%+-**#%%*@%+=*%%*%. -%#--..-%#: + :%#%*=%-#*+##%=#==%@%%= -: =. + -%+%*:**@%*####==##%%%#= .. . : + .#@#%###%%#-+*%**%#@@%@## :.. = :*#* .: + -%%%%%+%%%+-+%@%*#%%@%%*%- ..-. .. -#@#. - + *%%@@%*@**-%***@%#%%%@#*@@: . - .. %. - + %%%@@%+@%**@*=%@@#%%%%+*### ...- .. * .- . . : + :. :. .#%#@#%+%%%*%*@%@%*#%@*=%##%. : :. ..:-=*#:...+ - -*.=:=. + %#%%-+%# =-*@%%%#=*%@%%%@@@#++@%+##*%%+ .::+. .:.:=*+#+::....-. .=*= + =+##%#%..: :##:#%##@%*#%#**+*%*##%+%*=-.-% . .-:::.= ** . :: . ++.+... + #%*###%*%%**=+**%##+#**%@*#*#**+**##*+#-+*-+-*- . .:+:. ==-+:.. .%+=:*: + -%%*++##%%#%#%%%#@%#*#%+**+##%%##%*-+#+--*%%#+* . .-===--. .:-=- . #===.. + -###=+%@%%%%%%@@#@%##*=--++-+#***=--=-=**#*@### .:- . .#++==. + -+%++@@@@@@%@@@+@@%=+#*%--::-*+=:-=**#%%#%#@%@. .= .. .#+-:. + -%+*#@@@@@@@@@@+@@%=+%%@%%#+#%#+*###%%%@%%%%%%. . .- . .. ....:. + -*@@@@@@@@%@+%@%#-:#@@@@#%@%#%%%%%%@@@%@%@#% . . .* .... .. + %@@@@@@%*@**@%%#-#@@@@@@@@#%#%@%@%@%%@%@#%: .... .....-: ...... + =%@@@@@#%##@@%%==@@@@@@@@@@@%@@@%@@@@@%#%. . ...... ....*= .... + +@@@@%**%%@%%#=-%%@@@@@@@@@@@@@@@@%%#@@- . -...... .:+++=. . + =#@@%*@%%@%%##--%@@@@@@@@@@@@@@%@*%@%* .::=...:.::-+++=. . + --@@#@%%%#*=.-@@@@@@@@@@@%%@*#%@@% .. ...*..*=. . + =@@@%@@@%#*++-=%@@%@@@@@#+**%@@@* . --.. .. + -@@@%@@%%##**##+==:+-+**=+#%@%%@+ ... + -@@@@%@@#%%%%@@%#+#%%%@#+#%@@@#%= . .. + -%@@@@@@@@@%%%@+%@%@%%##%%#@@@%@- .. . ... + :%@@@%@@@@@%@@#%@%%#=-*++**+@%#@= -+=-.:=: .. + .@@@@@@@@@@@@%@@%*++*%%#%@%#*%%#- .. .= := . .... + #@@@@@@@@@@*@%*+@%@@#@%@@@%*%@. . + . .... + :#@@@@@@@%%%#=*@@%%@@@#%@@##*@:: .. ... :=... ..... + -%@@@@@@@@@%=@@%@%@%@@@@@%#+@# .. .... =.......... + ++%@@@@@@%@*%@%%@@@@@@@@%#**@+ ..: ... .==...... . + #*%@@@@%*+=%##@@@@@%@%%%###+. . :.... ..=+:..:= + *#*#@@@%=*==*##=+*#%@%##+#@+ .. ...+. -=+:--.=-.. + .*#=*%@%*%##@@#%%+#*%@*+#@+ .... . ...+.:.+:::. + *%*+##+#%%%%%%%#%%%%##%- : ... .-=+.:-=*.... + -@@%%%*-%%%%@%%@%@%*%% ....=..:*:.=.... + #@@%***+%+++*++@%%+- ..::=:**+#... + %%%%%%%=%%*+*%@%. .::**=+=:... + :%@@%%%%=##%%*= .:+=-+.... + *@@@@@@%#++ :=+::. + :*%@@@%@@+ :..... + #%@@@@%%# ....... + .#@@@@@@@#= ... .... + #%@%%@%%@@@. ..:..:.. + -###%%%%@@%- . .. . + #*#%#%@@*: + :+- diff --git a/consensus/merge/src/main/resources/ttdPanda.txt b/consensus/merge/src/main/resources/ttdPanda.txt new file mode 100644 index 00000000000..9ccdfb0ba81 --- /dev/null +++ b/consensus/merge/src/main/resources/ttdPanda.txt @@ -0,0 +1,57 @@ + + :.-- + .-*+#=---:-*:::-: .-.-== . + -%%@%%%%@%#%@*+*+#* . ...*==+# . + -%%#%%@@@@%@%@%%+=**@:: .-*.*++= + .#%%@@@@@@%@%%@@##***##+ ...=:++%.. + :%%%%@@@@%%*=-+%@###++*%= --*+*:+*... .+=. + :%%@@@@@@%%@*%#*%-@@%*##+*## ...-.*-. .. .-. .- + .:.#@@@@@@@@@@#+%*#@=@@%%%%##%= . .-: ... . .:-=++- + #=@@@@%@%#*#**%@##%-@@++#*.- ......: --: + #%#@@@@@%#*@%%%%@@@%-:: : ..:-. +... + :::@%%@@@@@@=%@*#@%*@@%%. :. ..=: + :%=#@@@@%@%%%%%##*+#%%%+%= :.. + -%%*%%@@@%@#%@%%%%*-=+##=%%- :. :*. + =#%@%@%%@@%%#@@@%@**-#.**%%%@. .#* ..- + -%@@%#@@@@#%%%%%@#=##*-:*%%@@@%. *=. .-:. + -#@@@@%%@%@#@@%@@#*%%%%%##*%###%@: .:- .-. ::.. + ##@@@%#%@@@%@%@@###@%%#%%##%+#*##@@@= .. . +- .:.. + +#@@@@@%%@@@%@#%%%%@@#=:-%%-##*%#%*##%= :- - +% :: -... + :%%@@@@%%@@%@%%%#%%@@@%:%#-#*+-+#%%#+*%= = -=. +@* = .. + %%@@@@@@%%%@@#%*%%#*#%#=*#:%@=%+:%%%+=%= . .*#. %**: = + . + =%@@@@@@@@@%@@%#@#%%#%*+#*:+%@%:--@@%#%# .#:. .#@. = .. + .%@@@@@@@@@@%%@##@@@@%@*=###*%@%*##@@%=. = .+#. : + +@@@@@@@@@%%%*@@+%@@@%%%#+@%%%@*@%@%@% .= +=- .. + %%@@@@@@@@@@%*@%##@@@@%%%=%%%%#@%%@%%= ...:. .. + *@@@@@@@@@@@@%%#%%=%#@@@@@%+%@##%@##%: =.=.. + %@@@@@@@@@@@@@%#@%#*%@@@@%%#*%#@%@*=%* := :-. + +%@@@@@@%@@@@@@@%#%@%%%@@@%*%%##%%#**%. . -:::.: + -##@@@@@@@@@@@@@@@#%%@@%%###%##%@@@#*%- . - + *+#@@@@@@@@@%@@@%@#@@@%#%#%%%%#@##*#@+ . . + -%#%@@@@@@@@@@@@@@%%@@@@@@@@@@@#*%@%@%-+@+.+ . ... . + %@+%@@@@@@@@@@@@@@%@@@@@@@@@@#@%@%##+*##%==@%+. ... . = + -%%=#@@@@@@@@@@@@@@@@@@@@@@@%#@%**%#=%%#=#*#%%%. .. .. : + @@@+#@@@@@@@@@@@@@@@@@@@@@%%@@#:#%=#@@%*++#%### ... . + -@%%#*@@@@@@@@@@@@@@@@@@@%@@%@%-#@#%@@@@===%@@@= .... . :.. + *%%%#*@%@@@@@@@@@@@@@@@@@@@@%@*+@@+%@%%@+++#*=%- . . .. + :@@#%%*%@@@@@@@@@%@@@@@%@@@@@@@**@@*@@%@##+*%%%% .. .-. . ::. + *@%#@%=@@@@@@@@@@@@@@@@@@@@@@%%:%@@#@@@@%=+*+%%* :. . ...- :.. + %@@%%@#%@@@@@@@@@@@@@@@@@@@@@%#-@@@@@%%%%%##*-- .... .....::. . ...-: + -@%#@%@*#@@@@@@@@@@@@@@@@@@@@@%*:%@@@@@@@@%#*: ............ ... . .=. + %@%@@@%%%%@%@@@@@@@@@@@@@@@@@%###*@@@@@@@@@# . .... .:.. . . . .= + .@%%%@@%@#*@#@@@@@@@@@@@@@@@@@@*@-=%@@@@@@@#. .:=:. .. .:. + .@%%%@@@@@%#%@@@@@@@@@@@@@@@@@#***@*==#@%#: ::. ....... + -@@@@@@@@@@#%%@@@@@@@@@@@@@%%#%%%%@%#+.. .... .. ........ + *@@@@@@@@@@@##@@@@@@@@@@%@%*%@@@%%%%%*#% ..................... + :*@@@@@@@@@@@@%%@@@@@@@@@*+%@@@@@@@@#%%%+ .............:....... + .#@@@@%@@@@@@@-=:*#*+== =@%@@@@@@%%%@%@% ...-....... ... ...... . + .%@@@@@@@@@@@. -#@@@@@@@@@@%@% .... .... ......... .. + #@@@@@@@@@@- *@%@@@@@@@@# . . . ... .......... + #%@@@@@@@*: +**%%@@@@@@+ .......... ....... . + :#*#%@@@@= .%@@%@@%@@%=. ......... ........ + :+#+*#+#@# %@@@@@@@%=%= ........ .... . + :@%@*#+@%- @@@@@%%-%** :....... .. + -:==+=. .--+%-: ... + + + diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/PandaPrinterTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/PandaPrinterTest.java index 1f5afbc075f..d81aa50e6e3 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/PandaPrinterTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/PandaPrinterTest.java @@ -18,8 +18,11 @@ import static org.assertj.core.api.Assertions.assertThat; +import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.core.Difficulty; +import java.util.Optional; + import org.junit.Test; public class PandaPrinterTest { @@ -33,8 +36,11 @@ public class PandaPrinterTest { @Test public void printsPanda() { PandaPrinter.resetForTesting(); - assertThat(PandaPrinter.printOnFirstCrossing()).isTrue(); - assertThat(PandaPrinter.printOnFirstCrossing()).isFalse(); + assertThat(PandaPrinter.ttdBeenDisplayed).isFalse(); + PandaPrinter.printOnFirstCrossing(); + assertThat(PandaPrinter.ttdBeenDisplayed).isTrue(); + assertThat(PandaPrinter.readyBeenDisplayed).isFalse(); + assertThat(PandaPrinter.finalizedBeenDisplayed).isFalse(); } @Test @@ -43,9 +49,11 @@ public void doesNotPrintAtInit() { var mergeContext = new PostMergeContext(Difficulty.ONE); mergeContext.observeNewIsPostMergeState(fauxTransitionHandler); - assertThat(PandaPrinter.hasDisplayed()).isFalse(); + assertThat(PandaPrinter.ttdBeenDisplayed).isFalse(); mergeContext.setIsPostMerge(Difficulty.ONE); - assertThat(PandaPrinter.hasDisplayed()).isFalse(); + assertThat(PandaPrinter.ttdBeenDisplayed).isFalse(); + assertThat(PandaPrinter.readyBeenDisplayed).isFalse(); + assertThat(PandaPrinter.finalizedBeenDisplayed).isFalse(); } @Test @@ -54,10 +62,40 @@ public void printsWhenCrossingOnly() { var mergeContext = new PostMergeContext(Difficulty.ONE); mergeContext.observeNewIsPostMergeState(fauxTransitionHandler); - assertThat(PandaPrinter.hasDisplayed()).isFalse(); + assertThat(PandaPrinter.ttdBeenDisplayed).isFalse(); mergeContext.setIsPostMerge(Difficulty.ZERO); - assertThat(PandaPrinter.hasDisplayed()).isFalse(); + assertThat(PandaPrinter.ttdBeenDisplayed).isFalse(); mergeContext.setIsPostMerge(Difficulty.ONE); - assertThat(PandaPrinter.hasDisplayed()).isTrue(); + assertThat(PandaPrinter.ttdBeenDisplayed).isTrue(); + assertThat(PandaPrinter.readyBeenDisplayed).isFalse(); + assertThat(PandaPrinter.finalizedBeenDisplayed).isFalse(); + } + + @Test + public void printsReadyOnStartupInSyncWithTTD() { + PandaPrinter.resetForTesting(); + PandaPrinter.inSync(); + PandaPrinter.hasTTD(); + assertThat(PandaPrinter.readyBeenDisplayed).isTrue(); + assertThat(PandaPrinter.ttdBeenDisplayed).isFalse(); + assertThat(PandaPrinter.finalizedBeenDisplayed).isFalse(); + } + + @Test + public void printsFinalized() { + PandaPrinter.resetForTesting(); + PandaPrinter pandaPrinter = new PandaPrinter(); + MergeContext mergeContext = new PostMergeContext(Difficulty.ZERO); + mergeContext.addNewForkchoiceMessageListener(pandaPrinter); + mergeContext.fireNewUnverifiedForkchoiceMessageEvent( + Hash.ZERO, Optional.of(Hash.ZERO), Hash.ZERO); + assertThat(PandaPrinter.readyBeenDisplayed).isFalse(); + assertThat(PandaPrinter.finalizedBeenDisplayed).isFalse(); + assertThat(PandaPrinter.ttdBeenDisplayed).isFalse(); + mergeContext.fireNewUnverifiedForkchoiceMessageEvent( + Hash.ZERO, Optional.of(Hash.fromHexStringLenient("0x1337")), Hash.ZERO); + assertThat(PandaPrinter.readyBeenDisplayed).isFalse(); + assertThat(PandaPrinter.ttdBeenDisplayed).isFalse(); + assertThat(PandaPrinter.finalizedBeenDisplayed).isTrue(); } } From ded02391a739110a7c297e46a830b767a596a723 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Thu, 18 Aug 2022 12:17:56 -0700 Subject: [PATCH 088/109] implement tentative mainnet TTD (#4260) * implement tentative mainnet TTD * fix unit test breakage * add to change log Signed-off-by: garyschulte --- CHANGELOG.md | 1 + .../test/java/org/hyperledger/besu/RunnerTest.java | 2 ++ .../org/hyperledger/besu/cli/BesuCommandTest.java | 9 ++++++--- config/src/main/resources/mainnet.json | 1 + .../besu/config/GenesisConfigFileTest.java | 11 +++++++++++ 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa99e9abd5a..7a125cb2501 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Introduce a cap to reputation score increase [#4230](https://github.com/hyperledger/besu/pull/4230) - Add experimental CLI option for `--Xp2p-peer-lower-bound` [#4200](https://github.com/hyperledger/besu/pull/4200) - Improve pending blocks retrieval mechanism [#4227](https://github.com/hyperledger/besu/pull/4227) +- set mainnet terminal total difficulty [#4260](https://github.com/hyperledger/besu/pull/4260) ### Bug Fixes - Fixes off-by-one error for mainnet TTD fallback [#4223](https://github.com/hyperledger/besu/pull/4223) diff --git a/besu/src/test/java/org/hyperledger/besu/RunnerTest.java b/besu/src/test/java/org/hyperledger/besu/RunnerTest.java index d9221d0f472..5510419614f 100644 --- a/besu/src/test/java/org/hyperledger/besu/RunnerTest.java +++ b/besu/src/test/java/org/hyperledger/besu/RunnerTest.java @@ -403,6 +403,8 @@ private GenesisConfigFile getFastSyncGenesis() { (node) -> { // Clear DAO block so that inability to validate DAO block won't interfere with fast sync node.remove("daoForkBlock"); + // remove merge terminal difficulty for fast sync in the absence of a CL mock + node.remove("terminalTotalDifficulty"); }); return GenesisConfigFile.fromConfig(jsonNode); } diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index 984b412354e..1b64a1cdb65 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -3670,6 +3670,8 @@ public void blockProducingOptionsWarnsMinerShouldBeEnabled() { final Address requestedCoinbase = Address.fromHexString("0000011111222223333344444"); parseCommand( + "--network", + "dev", "--miner-coinbase", requestedCoinbase.toString(), "--min-gas-price", @@ -3692,7 +3694,8 @@ public void blockProducingOptionsWarnsMinerShouldBeEnabledToml() throws IOExcept final Path toml = createTempFile( "toml", - "miner-coinbase=\"" + "network=\"dev\"\n" + + "miner-coinbase=\"" + requestedCoinbase + "\"\n" + "min-gas-price=42\n" @@ -3735,7 +3738,7 @@ public void blockProducingOptionsDoNotWarnWhenMergeEnabled() { @Test public void minGasPriceRequiresMainOption() { - parseCommand("--min-gas-price", "0"); + parseCommand("--min-gas-price", "0", "--network", "dev"); verifyOptionsConstraintLoggerCall("--miner-enabled", "--min-gas-price"); @@ -3745,7 +3748,7 @@ public void minGasPriceRequiresMainOption() { @Test public void minGasPriceRequiresMainOptionToml() throws IOException { - final Path toml = createTempFile("toml", "min-gas-price=0\n"); + final Path toml = createTempFile("toml", "min-gas-price=0\nnetwork=\"dev\"\n"); parseCommand("--config-file", toml.toString()); diff --git a/config/src/main/resources/mainnet.json b/config/src/main/resources/mainnet.json index 805a668c762..57273c6436f 100644 --- a/config/src/main/resources/mainnet.json +++ b/config/src/main/resources/mainnet.json @@ -13,6 +13,7 @@ "londonBlock": 12965000, "arrowGlacierBlock": 13773000, "grayGlacierBlock": 15050000, + "terminalTotalDifficulty": 58750000000000000000000, "ethash": { }, "discovery": { diff --git a/config/src/test/java/org/hyperledger/besu/config/GenesisConfigFileTest.java b/config/src/test/java/org/hyperledger/besu/config/GenesisConfigFileTest.java index 3112f908377..55efdcb1635 100644 --- a/config/src/test/java/org/hyperledger/besu/config/GenesisConfigFileTest.java +++ b/config/src/test/java/org/hyperledger/besu/config/GenesisConfigFileTest.java @@ -228,6 +228,17 @@ public void assertGoerliTerminalTotalDifficulty() { .isEqualTo(UInt256.valueOf(new BigInteger("10790000"))); } + @Test + public void assertMainnetTerminalTotalDifficulty() { + GenesisConfigOptions mainnetOptions = + GenesisConfigFile.genesisFileFromResources("/mainnet.json").getConfigOptions(); + + assertThat(mainnetOptions.getTerminalTotalDifficulty()).isPresent(); + // tentative as of 2022-08-11: + assertThat(mainnetOptions.getTerminalTotalDifficulty().get()) + .isEqualTo(UInt256.valueOf(new BigInteger("58750000000000000000000"))); + } + @Test public void assertTerminalTotalDifficultyOverride() { GenesisConfigOptions ropstenOverrideOptions = From 3a2aeabcda56f879b34cca42bc84e77c04243d35 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Thu, 18 Aug 2022 21:45:07 +0200 Subject: [PATCH 089/109] Refactor and fix retrying get block switching peer (#4256) * Refactor retrying peer task switching peers at every try RetryingGetBlockFromPeersTask had a problem that prevented to complete when all the peers were tried without success, and that also had the consequence to not removing the failed requested block for the internal caches in BlockPropagationManager, that could cause a stall since that block will to be tried to be retrieved again. Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 1 + .../task/AbstractRetryingPeerTask.java | 11 +- .../AbstractRetryingSwitchingPeerTask.java | 153 +++++++++++++++++ .../task/RetryingGetBlockFromPeersTask.java | 98 ++++------- .../eth/sync/BlockPropagationManager.java | 1 - .../eth/sync/backwardsync/SyncStepStep.java | 1 - .../ethtaskutils/AbstractMessageTaskTest.java | 4 +- .../ethtaskutils/RetryingMessageTaskTest.java | 10 +- .../RetryingSwitchingPeerMessageTaskTest.java | 162 ++++++++++++++++++ .../RetryingGetBlockFromPeersTaskTest.java | 72 ++++++++ .../AbstractBlockPropagationManagerTest.java | 35 ++++ 11 files changed, 469 insertions(+), 79 deletions(-) create mode 100644 ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingSwitchingPeerTask.java create mode 100644 ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/RetryingSwitchingPeerMessageTaskTest.java create mode 100644 ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetBlockFromPeersTaskTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a125cb2501..98ae3516e07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ ### Bug Fixes - Fixes off-by-one error for mainnet TTD fallback [#4223](https://github.com/hyperledger/besu/pull/4223) - Fix off-by-one error in AbstractRetryingPeerTask [#4254](https://github.com/hyperledger/besu/pull/4254) +- Refactor and fix retrying get block switching peer [#4256](https://github.com/hyperledger/besu/pull/4256) - Fix encoding of key (short hex) in eth_getProof [#4261](https://github.com/hyperledger/besu/pull/4261) - Fix for post-merge networks fast-sync [#4224](https://github.com/hyperledger/besu/pull/4224), [#4276](https://github.com/hyperledger/besu/pull/4276) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTask.java index 148c5282511..30033200355 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTask.java @@ -140,12 +140,13 @@ protected void handleTaskError(final Throwable error) { } protected boolean isRetryableError(final Throwable error) { - final boolean isPeerError = - error instanceof PeerBreachedProtocolException - || error instanceof PeerDisconnectedException - || error instanceof NoAvailablePeersException; + return error instanceof TimeoutException || (!assignedPeer.isPresent() && isPeerFailure(error)); + } - return error instanceof TimeoutException || (!assignedPeer.isPresent() && isPeerError); + protected boolean isPeerFailure(final Throwable error) { + return error instanceof PeerBreachedProtocolException + || error instanceof PeerDisconnectedException + || error instanceof NoAvailablePeersException; } protected EthContext getEthContext() { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingSwitchingPeerTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingSwitchingPeerTask.java new file mode 100644 index 00000000000..d9724895e66 --- /dev/null +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingSwitchingPeerTask.java @@ -0,0 +1,153 @@ +/* + * Copyright contributors to Hyperledger Besu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.eth.manager.task; + +import static org.hyperledger.besu.util.Slf4jLambdaHelper.debugLambda; +import static org.hyperledger.besu.util.Slf4jLambdaHelper.traceLambda; + +import org.hyperledger.besu.ethereum.eth.manager.EthContext; +import org.hyperledger.besu.ethereum.eth.manager.EthPeer; +import org.hyperledger.besu.ethereum.eth.manager.EthPeers; +import org.hyperledger.besu.ethereum.eth.manager.exceptions.NoAvailablePeersException; +import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage.DisconnectReason; +import org.hyperledger.besu.plugin.services.MetricsSystem; + +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeoutException; +import java.util.function.Predicate; +import java.util.stream.Stream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractRetryingSwitchingPeerTask extends AbstractRetryingPeerTask { + + private static final Logger LOG = + LoggerFactory.getLogger(AbstractRetryingSwitchingPeerTask.class); + + private final Set triedPeers = new HashSet<>(); + private final Set failedPeers = new HashSet<>(); + + protected AbstractRetryingSwitchingPeerTask( + final EthContext ethContext, + final MetricsSystem metricsSystem, + final Predicate isEmptyResponse, + final int maxRetries) { + super(ethContext, maxRetries, isEmptyResponse, metricsSystem); + } + + @Override + public void assignPeer(final EthPeer peer) { + super.assignPeer(peer); + triedPeers.add(peer); + } + + protected abstract CompletableFuture executeTaskOnCurrentPeer(final EthPeer peer); + + @Override + protected CompletableFuture executePeerTask(final Optional assignedPeer) { + + final Optional maybePeer = + assignedPeer + .filter(u -> getRetryCount() == 1) // first try with the assigned peer if present + .map(Optional::of) + .orElseGet(this::selectNextPeer); // otherwise select a new one from the pool + + if (maybePeer.isEmpty()) { + traceLambda( + LOG, + "No peer found to try to execute task at attempt {}, tried peers {}", + this::getRetryCount, + triedPeers::toString); + final var ex = new NoAvailablePeersException(); + return CompletableFuture.failedFuture(ex); + } + + final EthPeer peerToUse = maybePeer.get(); + assignPeer(peerToUse); + + traceLambda( + LOG, + "Trying to execute task on peer {}, attempt {}", + this::getAssignedPeer, + this::getRetryCount); + + return executeTaskOnCurrentPeer(peerToUse) + .thenApply( + peerResult -> { + traceLambda( + LOG, + "Got result {} from peer {}, attempt {}", + peerResult::toString, + peerToUse::toString, + this::getRetryCount); + result.complete(peerResult); + return peerResult; + }); + } + + @Override + protected void handleTaskError(final Throwable error) { + if (isPeerFailure(error)) { + getAssignedPeer().ifPresent(peer -> failedPeers.add(peer)); + } + super.handleTaskError(error); + } + + @Override + protected boolean isRetryableError(final Throwable error) { + return error instanceof TimeoutException || isPeerFailure(error); + } + + private Optional selectNextPeer() { + final Optional maybeNextPeer = remainingPeersToTry().findFirst(); + + if (maybeNextPeer.isEmpty()) { + // tried all the peers, restart from the best one but excluding the failed ones + refreshPeers(); + triedPeers.retainAll(failedPeers); + return remainingPeersToTry().findFirst(); + } + + return maybeNextPeer; + } + + private Stream remainingPeersToTry() { + return getEthContext() + .getEthPeers() + .streamBestPeers() + .filter(peer -> !peer.isDisconnected() && !triedPeers.contains(peer)); + } + + private void refreshPeers() { + final EthPeers peers = getEthContext().getEthPeers(); + // If we are at max connections, then refresh peers disconnecting one of the failed peers, + // or the least useful + if (peers.peerCount() >= peers.getMaxPeers()) { + failedPeers.stream() + .filter(peer -> !peer.isDisconnected()) + .findAny() + .or(() -> peers.streamAvailablePeers().sorted(peers.getBestChainComparator()).findFirst()) + .ifPresent( + peer -> { + debugLambda(LOG, "Refresh peers disconnecting peer {}", peer::toString); + peer.disconnect(DisconnectReason.USELESS_PEER); + }); + } + } +} diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetBlockFromPeersTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetBlockFromPeersTask.java index 2f2fe3086c6..c1894189065 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetBlockFromPeersTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetBlockFromPeersTask.java @@ -14,135 +14,101 @@ */ package org.hyperledger.besu.ethereum.eth.manager.task; +import static org.hyperledger.besu.util.Slf4jLambdaHelper.debugLambda; + import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthPeer; import org.hyperledger.besu.ethereum.eth.manager.exceptions.IncompleteResultsException; -import org.hyperledger.besu.ethereum.eth.manager.exceptions.NoAvailablePeersException; +import org.hyperledger.besu.ethereum.eth.manager.task.AbstractPeerTask.PeerTaskResult; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.plugin.services.MetricsSystem; -import java.util.HashSet; import java.util.Objects; import java.util.Optional; -import java.util.Set; import java.util.concurrent.CompletableFuture; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class RetryingGetBlockFromPeersTask - extends AbstractRetryingPeerTask> { + extends AbstractRetryingSwitchingPeerTask> { private static final Logger LOG = LoggerFactory.getLogger(RetryingGetBlockFromPeersTask.class); - private final ProtocolContext protocolContext; private final ProtocolSchedule protocolSchedule; - private final Optional blockHash; + private final Optional maybeBlockHash; private final long blockNumber; - private final Set triedPeers = new HashSet<>(); protected RetryingGetBlockFromPeersTask( - final ProtocolContext protocolContext, final EthContext ethContext, final ProtocolSchedule protocolSchedule, final MetricsSystem metricsSystem, final int maxRetries, - final Optional blockHash, + final Optional maybeBlockHash, final long blockNumber) { - super(ethContext, maxRetries, Objects::isNull, metricsSystem); - this.protocolContext = protocolContext; + super(ethContext, metricsSystem, Objects::isNull, maxRetries); this.protocolSchedule = protocolSchedule; - this.blockHash = blockHash; + this.maybeBlockHash = maybeBlockHash; this.blockNumber = blockNumber; } public static RetryingGetBlockFromPeersTask create( - final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, final EthContext ethContext, final MetricsSystem metricsSystem, final int maxRetries, - final Optional hash, + final Optional maybeHash, final long blockNumber) { return new RetryingGetBlockFromPeersTask( - protocolContext, - ethContext, - protocolSchedule, - metricsSystem, - maxRetries, - hash, - blockNumber); - } - - @Override - public void assignPeer(final EthPeer peer) { - super.assignPeer(peer); - triedPeers.add(peer); + ethContext, protocolSchedule, metricsSystem, maxRetries, maybeHash, blockNumber); } @Override - protected CompletableFuture> executePeerTask( - final Optional assignedPeer) { - + protected CompletableFuture> executeTaskOnCurrentPeer( + final EthPeer currentPeer) { final GetBlockFromPeerTask getBlockTask = GetBlockFromPeerTask.create( - protocolSchedule, getEthContext(), blockHash, blockNumber, getMetricsSystem()); - - getBlockTask.assignPeer( - assignedPeer - .filter(unused -> getRetryCount() == 1) // first try with the assigned preferred peer - .orElseGet( // then selecting a new one from the pool - () -> { - assignPeer(selectNextPeer()); - return getAssignedPeer().get(); - })); - - LOG.debug( - "Getting block {} ({}) from peer {}, attempt {}", - blockNumber, - blockHash, - getAssignedPeer(), - getRetryCount()); + protocolSchedule, getEthContext(), maybeBlockHash, blockNumber, getMetricsSystem()); + getBlockTask.assignPeer(currentPeer); return executeSubTask(getBlockTask::run) .thenApply( peerResult -> { + debugLambda( + LOG, + "Got block {} from peer {}, attempt {}", + peerResult.getResult()::toLogString, + peerResult.getPeer()::toString, + this::getRetryCount); result.complete(peerResult); return peerResult; }); } - private EthPeer selectNextPeer() { - return getEthContext() - .getEthPeers() - .streamBestPeers() - .filter(peer -> !triedPeers.contains(peer)) - .findFirst() - .orElseThrow(NoAvailablePeersException::new); - } - @Override protected boolean isRetryableError(final Throwable error) { - return (blockNumber > protocolContext.getBlockchain().getChainHeadBlockNumber()) - && (super.isRetryableError(error) || error instanceof IncompleteResultsException); + return super.isRetryableError(error) || error instanceof IncompleteResultsException; } @Override protected void handleTaskError(final Throwable error) { if (getRetryCount() < getMaxRetries()) { - LOG.debug( - "Failed to get block {} ({}) from peer {}, attempt {}, retrying later", - blockNumber, - blockHash, - getAssignedPeer(), - getRetryCount()); + debugLambda( + LOG, + "Failed to get block {} from peer {}, attempt {}, retrying later", + this::logBlockNumberMaybeHash, + this::getAssignedPeer, + this::getRetryCount); } else { LOG.warn( - "Failed to get block {} ({}) after {} retries", blockNumber, blockHash, getRetryCount()); + "Failed to get block {} after {} retries", logBlockNumberMaybeHash(), getRetryCount()); } super.handleTaskError(error); } + + private String logBlockNumberMaybeHash() { + return blockNumber + maybeBlockHash.map(h -> " (" + h.toHexString() + ")").orElse(""); + } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java index e76b710f9d7..aa72844f6d4 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java @@ -400,7 +400,6 @@ private CompletableFuture getBlockFromPeers( final Optional blockHash) { final RetryingGetBlockFromPeersTask getBlockTask = RetryingGetBlockFromPeersTask.create( - protocolContext, protocolSchedule, ethContext, metricsSystem, diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/SyncStepStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/SyncStepStep.java index d1dae073396..88ddc18b2c6 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/SyncStepStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/SyncStepStep.java @@ -50,7 +50,6 @@ public CompletableFuture executeAsync(final Hash hash) { private CompletableFuture requestBlock(final Hash targetHash) { final RetryingGetBlockFromPeersTask getBlockTask = RetryingGetBlockFromPeersTask.create( - context.getProtocolContext(), context.getProtocolSchedule(), context.getEthContext(), context.getMetricsSystem(), diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java index 81a4cb1c689..d1b787e3013 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java @@ -58,6 +58,7 @@ * @param The type of data returned from the network */ public abstract class AbstractMessageTaskTest { + protected static final int MAX_PEERS = 5; protected static Blockchain blockchain; protected static ProtocolSchedule protocolSchedule; protected static ProtocolContext protocolContext; @@ -77,7 +78,6 @@ public static void setup() { blockchain = blockchainSetupUtil.getBlockchain(); protocolSchedule = blockchainSetupUtil.getProtocolSchedule(); protocolContext = blockchainSetupUtil.getProtocolContext(); - assertThat(blockchainSetupUtil.getMaxBlockNumber()).isGreaterThanOrEqualTo(20L); } @@ -91,7 +91,7 @@ public void setupTest() { EthProtocol.NAME, TestClock.fixed(), metricsSystem, - 25, + MAX_PEERS, EthProtocolConfiguration.DEFAULT_MAX_MESSAGE_SIZE)); final EthMessages ethMessages = new EthMessages(); final EthScheduler ethScheduler = diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/RetryingMessageTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/RetryingMessageTaskTest.java index 5f383d66fd8..b69e316398e 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/RetryingMessageTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/RetryingMessageTaskTest.java @@ -26,6 +26,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import org.junit.Before; import org.junit.Test; /** @@ -34,11 +35,12 @@ * @param The type of data being requested from the network */ public abstract class RetryingMessageTaskTest extends AbstractMessageTaskTest { + protected static final int DEFAULT_MAX_RETRIES = 4; + protected int maxRetries; - protected final int maxRetries; - - protected RetryingMessageTaskTest() { - this.maxRetries = 4; + @Before + public void resetMaxRetries() { + this.maxRetries = DEFAULT_MAX_RETRIES; } @Override diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/RetryingSwitchingPeerMessageTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/RetryingSwitchingPeerMessageTaskTest.java new file mode 100644 index 00000000000..e7c953f0935 --- /dev/null +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/RetryingSwitchingPeerMessageTaskTest.java @@ -0,0 +1,162 @@ +/* + * Copyright contributors to Hyperledger Besu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.eth.manager.ethtaskutils; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.hyperledger.besu.ethereum.eth.manager.EthPeer; +import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil; +import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; +import org.hyperledger.besu.ethereum.eth.manager.exceptions.MaxRetriesReachedException; +import org.hyperledger.besu.ethereum.eth.manager.task.EthTask; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import org.junit.Test; + +/** + * Tests ethTasks that request data from the network, and retry until all of the data is received. + * + * @param The type of data being requested from the network + */ +public abstract class RetryingSwitchingPeerMessageTaskTest extends RetryingMessageTaskTest { + protected Optional responsivePeer = Optional.empty(); + + @Override + protected void assertResultMatchesExpectation( + final T requestedData, final T response, final EthPeer respondingPeer) { + assertThat(response).isEqualTo(requestedData); + responsivePeer.ifPresent(rp -> assertThat(rp).isEqualByComparingTo(respondingPeer)); + } + + @Test + public void completesWhenBestPeerEmptyAndSecondPeerIsResponsive() + throws ExecutionException, InterruptedException { + // Setup first unresponsive peer + final RespondingEthPeer firstPeer = + EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 10); + + // Setup second responsive peer + final RespondingEthPeer secondPeer = + EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 9); + + // Execute task and wait for response + final T requestedData = generateDataToBeRequested(); + final EthTask task = createTask(requestedData); + final CompletableFuture future = task.run(); + + // First peer is not responsive + firstPeer.respond(RespondingEthPeer.emptyResponder()); + // Second peer is responsive + secondPeer.respondTimes( + RespondingEthPeer.blockchainResponder( + blockchain, protocolContext.getWorldStateArchive(), transactionPool), + 2); + + responsivePeer = Optional.of(secondPeer.getEthPeer()); + + assertThat(future.isDone()).isTrue(); + assertResultMatchesExpectation(requestedData, future.get(), secondPeer.getEthPeer()); + } + + @Test + public void completesWhenBestPeerTimeoutsAndSecondPeerIsResponsive() + throws ExecutionException, InterruptedException { + // Setup first unresponsive peer + final RespondingEthPeer firstPeer = + EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 10); + + // Setup second responsive peer + final RespondingEthPeer secondPeer = + EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 9); + + // Execute task and wait for response + final T requestedData = generateDataToBeRequested(); + final EthTask task = createTask(requestedData); + final CompletableFuture future = task.run(); + + // First peer timeouts + peerCountToTimeout.set(1); + firstPeer.respondTimes( + RespondingEthPeer.blockchainResponder( + blockchain, protocolContext.getWorldStateArchive(), transactionPool), + 2); + // Second peer is responsive + secondPeer.respondTimes( + RespondingEthPeer.blockchainResponder( + blockchain, protocolContext.getWorldStateArchive(), transactionPool), + 2); + + responsivePeer = Optional.of(secondPeer.getEthPeer()); + + assertThat(future.isDone()).isTrue(); + assertResultMatchesExpectation(requestedData, future.get(), secondPeer.getEthPeer()); + } + + @Test + public void failsWhenAllPeersFail() { + // Setup first unresponsive peer + final RespondingEthPeer firstPeer = + EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 10); + + // Setup second unresponsive peer + final RespondingEthPeer secondPeer = + EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 9); + + // Execute task and wait for response + final T requestedData = generateDataToBeRequested(); + final EthTask task = createTask(requestedData); + final CompletableFuture future = task.run(); + + for (int i = 0; i < maxRetries && !future.isDone(); i++) { + // First peer is unresponsive + firstPeer.respondWhile(RespondingEthPeer.emptyResponder(), firstPeer::hasOutstandingRequests); + // Second peer is unresponsive + secondPeer.respondWhile( + RespondingEthPeer.emptyResponder(), secondPeer::hasOutstandingRequests); + } + + assertThat(future.isDone()).isTrue(); + assertThat(future.isCompletedExceptionally()).isTrue(); + assertThatThrownBy(future::get).hasCauseInstanceOf(MaxRetriesReachedException.class); + } + + @Test + public void disconnectAPeerWhenAllPeersTried() { + maxRetries = MAX_PEERS + 1; + final int numPeers = MAX_PEERS; + final List respondingPeers = new ArrayList<>(numPeers); + for (int i = 0; i < numPeers; i++) { + respondingPeers.add(EthProtocolManagerTestUtil.createPeer(ethProtocolManager, numPeers - i)); + } + + // Execute task and wait for response + final T requestedData = generateDataToBeRequested(); + final EthTask task = createTask(requestedData); + task.run(); + + respondingPeers.forEach( + respondingPeer -> + respondingPeer.respondWhile( + RespondingEthPeer.emptyResponder(), respondingPeer::hasOutstandingRequests)); + + assertThat(respondingPeers.get(numPeers - 1).getEthPeer().isDisconnected()).isTrue(); + } +} diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetBlockFromPeersTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetBlockFromPeersTaskTest.java new file mode 100644 index 00000000000..9e900287b1f --- /dev/null +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/RetryingGetBlockFromPeersTaskTest.java @@ -0,0 +1,72 @@ +/* + * Copyright contributors to Hyperledger Besu + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.eth.manager.task; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.ethereum.core.BlockHeader.GENESIS_BLOCK_NUMBER; +import static org.mockito.Mockito.mock; + +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.eth.manager.EthPeer; +import org.hyperledger.besu.ethereum.eth.manager.ethtaskutils.RetryingSwitchingPeerMessageTaskTest; +import org.hyperledger.besu.ethereum.eth.manager.task.AbstractPeerTask.PeerTaskResult; + +import java.util.Optional; +import java.util.concurrent.ExecutionException; + +import org.junit.Ignore; +import org.junit.Test; + +public class RetryingGetBlockFromPeersTaskTest + extends RetryingSwitchingPeerMessageTaskTest> { + + @Override + protected void assertResultMatchesExpectation( + final PeerTaskResult requestedData, + final PeerTaskResult response, + final EthPeer respondingPeer) { + assertThat(response.getResult()).isEqualTo(requestedData.getResult()); + } + + @Override + protected PeerTaskResult generateDataToBeRequested() { + final Block block = blockchain.getBlockByNumber(10).get(); + return new PeerTaskResult<>(mock(EthPeer.class), block); + } + + @Override + protected RetryingGetBlockFromPeersTask createTask(final PeerTaskResult requestedData) { + return RetryingGetBlockFromPeersTask.create( + protocolSchedule, + ethContext, + metricsSystem, + maxRetries, + Optional.of(requestedData.getResult().getHash()), + GENESIS_BLOCK_NUMBER); + } + + @Test + @Override + @Ignore("GetBlock could not return partial response") + public void failsWhenPeerReturnsPartialResultThenStops() {} + + @Override + @Test + @Ignore("GetBlock could not return partial response") + public void completesWhenPeerReturnsPartialResult() + throws ExecutionException, InterruptedException { + super.completesWhenPeerReturnsPartialResult(); + } +} diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java index ac6aa6550ad..3f15a68cd99 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java @@ -932,5 +932,40 @@ public void shouldNotListenToBlockAddedEventsWhenTTDReachedAndFinal() { verifyNoInteractions(pendingBlocksManager); } + @Test + public void shouldRequestBlockAgainIfFirstGetBlockFails() { + blockchainUtil.importFirstBlocks(2); + final Block nextBlock = blockchainUtil.getBlock(2); + + // Sanity check + assertThat(blockchain.contains(nextBlock.getHash())).isFalse(); + + blockPropagationManager.start(); + + final RespondingEthPeer firstPeer = + EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 0); + final NewBlockHashesMessage nextAnnouncement = + NewBlockHashesMessage.create( + Collections.singletonList( + new NewBlockHashesMessage.NewBlockHash( + nextBlock.getHash(), nextBlock.getHeader().getNumber()))); + + // Broadcast message and peer fail to respond + EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, firstPeer, nextAnnouncement); + firstPeer.respondWhile(RespondingEthPeer.emptyResponder(), firstPeer::hasOutstandingRequests); + + assertThat(blockchain.contains(nextBlock.getHash())).isFalse(); + + // Re-broadcast the previous message and peer responds + final RespondingEthPeer secondPeer = + EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 0); + EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, secondPeer, nextAnnouncement); + final Responder goodResponder = RespondingEthPeer.blockchainResponder(getFullBlockchain()); + + secondPeer.respondWhile(goodResponder, secondPeer::hasOutstandingRequests); + + assertThat(blockchain.contains(nextBlock.getHash())).isTrue(); + } + public abstract Blockchain getFullBlockchain(); } From e0d554b2251adc9ebecb76dfc901deb55aab9fcb Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Fri, 19 Aug 2022 10:38:22 -0600 Subject: [PATCH 090/109] Update Paris Block Definition (#4277) Paris block definition was set up prior to gray glacier. Update the base to be gray glacier. Signed-off-by: Danno Ferrin --- .../hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java index 3d98746c0f4..33afa720989 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java @@ -618,7 +618,7 @@ static ProtocolSpecBuilder parisDefinition( final boolean quorumCompatibilityMode, final EvmConfiguration evmConfiguration) { - return arrowGlacierDefinition( + return grayGlacierDefinition( chainId, configContractSizeLimit, configStackSizeLimit, From 2b8b4dbc6f3dcc9c39419d18e99678a6b5fcd9c7 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Mon, 22 Aug 2022 08:53:19 -0600 Subject: [PATCH 091/109] Reduce megamorphic call sites in AbstractCallOperation (#4288) The four instances of gas in the CALL operations are all implemented identically. Refactor the method into the abstract parent. Signed-off-by: Danno Ferrin --- .../besu/evm/operation/AbstractCallOperation.java | 6 +++++- .../besu/evm/operation/CallCodeOperation.java | 9 --------- .../hyperledger/besu/evm/operation/CallOperation.java | 9 --------- .../besu/evm/operation/DelegateCallOperation.java | 9 --------- .../besu/evm/operation/StaticCallOperation.java | 9 --------- 5 files changed, 5 insertions(+), 37 deletions(-) diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCallOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCallOperation.java index 28e18b5626c..9f978b1fe49 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCallOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCallOperation.java @@ -14,6 +14,8 @@ */ package org.hyperledger.besu.evm.operation; +import static org.hyperledger.besu.evm.internal.Words.clampedToLong; + import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.evm.Code; @@ -57,7 +59,9 @@ protected AbstractCallOperation( * @param frame The current message frame * @return the additional gas to provide the call operation */ - protected abstract long gas(MessageFrame frame); + protected long gas(final MessageFrame frame) { + return clampedToLong(frame.getStackItem(0)); + } /** * Returns the account the call is being made to. diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/CallCodeOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/CallCodeOperation.java index aa0a443e765..ce4bc56d013 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/CallCodeOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/CallCodeOperation.java @@ -29,15 +29,6 @@ public CallCodeOperation(final GasCalculator gasCalculator) { super(0xF2, "CALLCODE", 7, 1, 1, gasCalculator); } - @Override - protected long gas(final MessageFrame frame) { - try { - return frame.getStackItem(0).trimLeadingZeros().toLong(); - } catch (final ArithmeticException | IllegalArgumentException ae) { - return Long.MAX_VALUE; - } - } - @Override protected Address to(final MessageFrame frame) { return Words.toAddress(frame.getStackItem(1)); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/CallOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/CallOperation.java index c74831dbcb1..1ffd343f1ac 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/CallOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/CallOperation.java @@ -34,15 +34,6 @@ public CallOperation(final GasCalculator gasCalculator) { super(0xF1, "CALL", 7, 1, 1, gasCalculator); } - @Override - protected long gas(final MessageFrame frame) { - try { - return frame.getStackItem(0).trimLeadingZeros().toLong(); - } catch (final ArithmeticException | IllegalArgumentException ae) { - return Long.MAX_VALUE; - } - } - @Override protected Address to(final MessageFrame frame) { return Words.toAddress(frame.getStackItem(1)); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/DelegateCallOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/DelegateCallOperation.java index 301a88110fd..d74d253d558 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/DelegateCallOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/DelegateCallOperation.java @@ -29,15 +29,6 @@ public DelegateCallOperation(final GasCalculator gasCalculator) { super(0xF4, "DELEGATECALL", 6, 1, 1, gasCalculator); } - @Override - protected long gas(final MessageFrame frame) { - try { - return frame.getStackItem(0).trimLeadingZeros().toLong(); - } catch (final ArithmeticException | IllegalArgumentException ae) { - return Long.MAX_VALUE; - } - } - @Override protected Address to(final MessageFrame frame) { return Words.toAddress(frame.getStackItem(1)); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/StaticCallOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/StaticCallOperation.java index e10b88a84db..d6022651a4e 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/StaticCallOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/StaticCallOperation.java @@ -29,15 +29,6 @@ public StaticCallOperation(final GasCalculator gasCalculator) { super(0xFA, "STATICCALL", 6, 1, 1, gasCalculator); } - @Override - protected long gas(final MessageFrame frame) { - try { - return frame.getStackItem(0).trimLeadingZeros().toLong(); - } catch (final ArithmeticException | IllegalArgumentException ae) { - return Long.MAX_VALUE; - } - } - @Override protected Address to(final MessageFrame frame) { return Words.toAddress(frame.getStackItem(1)); From 332ca416ba6c995605cad3b25b3fc1441879407c Mon Sep 17 00:00:00 2001 From: Justin Florentine Date: Mon, 22 Aug 2022 14:04:56 -0400 Subject: [PATCH 092/109] upreved to new snapshot (#4291) * upreved to new snapshot * download links / shas in changelog Signed-off-by: Justin Florentine --- CHANGELOG.md | 13 +++++++++++++ gradle.properties | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98ae3516e07..18127f5c3f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 22.7.2 + +### Additions and Improvements + +### Bug Fixes + + ## 22.7.1 ### Additions and Improvements @@ -15,6 +22,12 @@ - Fix encoding of key (short hex) in eth_getProof [#4261](https://github.com/hyperledger/besu/pull/4261) - Fix for post-merge networks fast-sync [#4224](https://github.com/hyperledger/besu/pull/4224), [#4276](https://github.com/hyperledger/besu/pull/4276) +### Download links +- https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/22.7.1/besu-22.7.1.tar.gz / sha256: `7cca4c11e1d7525c172f2af9fbf456d134ada60e970d8b6abcfcd6c623b5dd36` +- https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/22.7.1/besu-22.7.1.zip / sha256: `ba6e0b9b65ac36d041a5072392f119ff76e8e9f53a3d7b1e1a658ef1e4705d7a` + + + ## 22.7.0 ### Additions and Improvements diff --git a/gradle.properties b/gradle.properties index 538911ba47a..5c3c7bad369 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=22.7.1-SNAPSHOT +version=22.7.2-SNAPSHOT org.gradle.welcome=never org.gradle.jvmargs=-Xmx1g \ No newline at end of file From 98e214cedc475d036e412e9c1cfb931805ac9958 Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Tue, 23 Aug 2022 19:31:27 +1000 Subject: [PATCH 093/109] ignore the tests that use tessera enclave via docker (#4297) Signed-off-by: Sally MacFarlane --- .../acceptance/privacy/BftPrivacyClusterAcceptanceTest.java | 2 ++ .../privacy/DeployPrivateSmartContractAcceptanceTest.java | 2 ++ .../tests/acceptance/privacy/EnclaveErrorAcceptanceTest.java | 1 + .../tests/acceptance/privacy/FlexiblePrivacyAcceptanceTest.java | 2 ++ .../besu/tests/acceptance/privacy/PrivCallAcceptanceTest.java | 2 ++ .../PrivDebugGetStateRootFlexibleGroupAcceptanceTest.java | 2 ++ .../PrivDebugGetStateRootOffchainGroupAcceptanceTest.java | 2 ++ .../tests/acceptance/privacy/PrivGetCodeAcceptanceTest.java | 2 ++ .../tests/acceptance/privacy/PrivGetLogsAcceptanceTest.java | 2 ++ .../privacy/PrivGetPrivateTransactionAcceptanceTest.java | 2 ++ .../tests/acceptance/privacy/PrivacyClusterAcceptanceTest.java | 2 ++ .../tests/acceptance/privacy/PrivacyGroupAcceptanceTest.java | 2 ++ .../tests/acceptance/privacy/PrivacyReceiptAcceptanceTest.java | 2 ++ .../privacy/PrivateContractPublicStateAcceptanceTest.java | 2 ++ .../tests/acceptance/privacy/PrivateGenesisAcceptanceTest.java | 2 ++ .../acceptance/privacy/PrivateLogFilterAcceptanceTest.java | 2 ++ .../multitenancy/FlexibleMultiTenancyAcceptanceTest.java | 2 ++ 17 files changed, 33 insertions(+) diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/BftPrivacyClusterAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/BftPrivacyClusterAcceptanceTest.java index 2baf1d1f5ce..e2672a86d6c 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/BftPrivacyClusterAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/BftPrivacyClusterAcceptanceTest.java @@ -30,6 +30,7 @@ import java.util.Optional; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -38,6 +39,7 @@ import org.web3j.utils.Restriction; @RunWith(Parameterized.class) +@Ignore("Ignored since Tessera/Docker container startup causing errors") public class BftPrivacyClusterAcceptanceTest extends PrivacyAcceptanceTestBase { private final BftPrivacyType bftPrivacyType; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/DeployPrivateSmartContractAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/DeployPrivateSmartContractAcceptanceTest.java index 71aa618cdd8..794a1e00883 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/DeployPrivateSmartContractAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/DeployPrivateSmartContractAcceptanceTest.java @@ -26,9 +26,11 @@ import java.io.IOException; import java.util.Optional; +import org.junit.Ignore; import org.junit.Test; import org.web3j.utils.Restriction; +@Ignore("Ignored since Tessera/Docker container startup causing errors") public class DeployPrivateSmartContractAcceptanceTest extends ParameterizedEnclaveTestBase { private final PrivacyNode minerNode; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/EnclaveErrorAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/EnclaveErrorAcceptanceTest.java index 7822768f140..61fcceac934 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/EnclaveErrorAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/EnclaveErrorAcceptanceTest.java @@ -49,6 +49,7 @@ import org.web3j.utils.Restriction; @RunWith(Parameterized.class) +@Ignore("Ignored since Tessera/Docker container startup causing errors") public class EnclaveErrorAcceptanceTest extends PrivacyAcceptanceTestBase { private final PrivacyNode alice; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/FlexiblePrivacyAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/FlexiblePrivacyAcceptanceTest.java index d64f73d2a03..362b26c56a4 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/FlexiblePrivacyAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/FlexiblePrivacyAcceptanceTest.java @@ -38,6 +38,7 @@ import com.google.common.collect.Lists; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -50,6 +51,7 @@ import org.web3j.tx.Contract; @RunWith(Parameterized.class) +@Ignore("Ignored since Tessera/Docker container startup causing errors") public class FlexiblePrivacyAcceptanceTest extends FlexiblePrivacyAcceptanceTestBase { private final EnclaveType enclaveType; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivCallAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivCallAcceptanceTest.java index b2c9c3bda54..f073872686a 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivCallAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivCallAcceptanceTest.java @@ -33,6 +33,7 @@ import java.util.Optional; import javax.annotation.Nonnull; +import org.junit.Ignore; import org.junit.Test; import org.web3j.abi.FunctionEncoder; import org.web3j.abi.TypeReference; @@ -48,6 +49,7 @@ import org.web3j.tx.Contract; import org.web3j.utils.Restriction; +@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivCallAcceptanceTest extends ParameterizedEnclaveTestBase { private static final int VALUE = 1024; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootFlexibleGroupAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootFlexibleGroupAcceptanceTest.java index 59973fd00be..9681ec60e8c 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootFlexibleGroupAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootFlexibleGroupAcceptanceTest.java @@ -32,6 +32,7 @@ import org.apache.tuweni.bytes.Bytes32; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -39,6 +40,7 @@ import org.testcontainers.containers.Network; @RunWith(Parameterized.class) +@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivDebugGetStateRootFlexibleGroupAcceptanceTest extends FlexiblePrivacyAcceptanceTestBase { diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootOffchainGroupAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootOffchainGroupAcceptanceTest.java index 92643446ddb..2d1fd76ecc4 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootOffchainGroupAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootOffchainGroupAcceptanceTest.java @@ -29,10 +29,12 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes32; +import org.junit.Ignore; import org.junit.Test; import org.testcontainers.containers.Network; import org.web3j.utils.Restriction; +@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivDebugGetStateRootOffchainGroupAcceptanceTest extends ParameterizedEnclaveTestBase { private final PrivacyNode aliceNode; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetCodeAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetCodeAcceptanceTest.java index c08006f694b..640f34639b1 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetCodeAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetCodeAcceptanceTest.java @@ -29,9 +29,11 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; +import org.junit.Ignore; import org.junit.Test; import org.web3j.utils.Restriction; +@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivGetCodeAcceptanceTest extends ParameterizedEnclaveTestBase { private final PrivacyNode alice; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetLogsAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetLogsAcceptanceTest.java index 62519385a2e..e627206592f 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetLogsAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetLogsAcceptanceTest.java @@ -30,12 +30,14 @@ import java.util.List; import java.util.Optional; +import org.junit.Ignore; import org.junit.Test; import org.web3j.protocol.besu.response.privacy.PrivateTransactionReceipt; import org.web3j.protocol.core.methods.response.EthLog.LogResult; import org.web3j.utils.Restriction; @SuppressWarnings("rawtypes") +@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivGetLogsAcceptanceTest extends ParameterizedEnclaveTestBase { /* diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetPrivateTransactionAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetPrivateTransactionAcceptanceTest.java index 91896761d09..0abac7bb9c5 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetPrivateTransactionAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetPrivateTransactionAcceptanceTest.java @@ -32,10 +32,12 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; +import org.junit.Ignore; import org.junit.Test; import org.testcontainers.containers.Network; import org.web3j.utils.Restriction; +@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivGetPrivateTransactionAcceptanceTest extends ParameterizedEnclaveTestBase { private final PrivacyNode alice; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyClusterAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyClusterAcceptanceTest.java index 1284daf917e..0386e29a4dc 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyClusterAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyClusterAcceptanceTest.java @@ -42,6 +42,7 @@ import io.vertx.core.Vertx; import org.apache.tuweni.bytes.Bytes; import org.junit.After; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -57,6 +58,7 @@ import org.web3j.utils.Numeric; @RunWith(Parameterized.class) +@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivacyClusterAcceptanceTest extends PrivacyAcceptanceTestBase { private final PrivacyNode alice; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyGroupAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyGroupAcceptanceTest.java index ab1bd91d0e7..6d6b4b6c3c6 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyGroupAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyGroupAcceptanceTest.java @@ -35,6 +35,7 @@ import java.util.Optional; import org.apache.logging.log4j.Level; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -45,6 +46,7 @@ import org.web3j.utils.Base64String; @RunWith(Parameterized.class) +@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivacyGroupAcceptanceTest extends PrivacyAcceptanceTestBase { private final PrivacyNode alice; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyReceiptAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyReceiptAcceptanceTest.java index 0b45d29732a..f4199ef11c4 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyReceiptAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyReceiptAcceptanceTest.java @@ -34,9 +34,11 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; +import org.junit.Ignore; import org.junit.Test; import org.web3j.utils.Restriction; +@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivacyReceiptAcceptanceTest extends ParameterizedEnclaveTestBase { final MinerTransactions minerTransactions = new MinerTransactions(); diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateContractPublicStateAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateContractPublicStateAcceptanceTest.java index 83a7ce66d8b..9c03b4c3afd 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateContractPublicStateAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateContractPublicStateAcceptanceTest.java @@ -33,6 +33,7 @@ import java.math.BigInteger; import java.util.Optional; +import org.junit.Ignore; import org.junit.Test; import org.testcontainers.containers.Network; import org.web3j.protocol.besu.response.privacy.PrivateTransactionReceipt; @@ -42,6 +43,7 @@ import org.web3j.tx.exceptions.ContractCallException; import org.web3j.utils.Restriction; +@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivateContractPublicStateAcceptanceTest extends ParameterizedEnclaveTestBase { private final PrivacyNode transactionNode; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateGenesisAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateGenesisAcceptanceTest.java index 29d5b655e3c..dea263883b4 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateGenesisAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateGenesisAcceptanceTest.java @@ -29,6 +29,7 @@ import java.math.BigInteger; import java.util.Optional; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -36,6 +37,7 @@ import org.web3j.utils.Restriction; @RunWith(Parameterized.class) +@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivateGenesisAcceptanceTest extends ParameterizedEnclaveTestBase { private final PrivacyNode alice; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateLogFilterAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateLogFilterAcceptanceTest.java index a6837f95465..d2301d0de2c 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateLogFilterAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateLogFilterAcceptanceTest.java @@ -31,12 +31,14 @@ import java.util.List; import java.util.Optional; +import org.junit.Ignore; import org.junit.Test; import org.web3j.protocol.besu.response.privacy.PrivateTransactionReceipt; import org.web3j.protocol.core.methods.response.EthLog.LogResult; import org.web3j.utils.Restriction; @SuppressWarnings("rawtypes") +@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivateLogFilterAcceptanceTest extends ParameterizedEnclaveTestBase { private final PrivacyNode node; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/FlexibleMultiTenancyAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/FlexibleMultiTenancyAcceptanceTest.java index 7907c37a110..4378ab6de11 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/FlexibleMultiTenancyAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/FlexibleMultiTenancyAcceptanceTest.java @@ -40,6 +40,7 @@ import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -50,6 +51,7 @@ import org.web3j.utils.Restriction; @RunWith(Parameterized.class) +@Ignore("Ignored since Tessera/Docker container startup causing errors") public class FlexibleMultiTenancyAcceptanceTest extends FlexiblePrivacyAcceptanceTestBase { private final EnclaveType enclaveType; From 465d7f24c63fc24deefbf23a8d5622690341b4b1 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 23 Aug 2022 11:57:56 +0200 Subject: [PATCH 094/109] Use Blake2bf native implementation if available by default (#4264) Signed-off-by: Fabio Di Fabio Co-authored-by: Antoine Toulme --- CHANGELOG.md | 1 + .../org/hyperledger/besu/cli/BesuCommand.java | 9 ++ .../unstable/NativeLibraryOptions.java | 13 +++ crypto/build.gradle | 1 + .../besu/crypto/Blake2bfMessageDigest.java | 85 ++++++++++--------- .../crypto/Blake2bfMessageDigestTest.java | 28 +++++- .../besu/crypto/eip152TestCases.csv | 6 ++ gradle/versions.gradle | 7 +- 8 files changed, 105 insertions(+), 45 deletions(-) create mode 100644 crypto/src/test/resources/org/hyperledger/besu/crypto/eip152TestCases.csv diff --git a/CHANGELOG.md b/CHANGELOG.md index 18127f5c3f4..52e4bce8f35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 22.7.2 ### Additions and Improvements +- Upgrade besu-native to 0.6.0 and use Blake2bf native implementation if available by default [#4264](https://github.com/hyperledger/besu/pull/4264) ### Bug Fixes diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index d1ec8d28b15..d5fc6fe06ef 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -92,6 +92,7 @@ import org.hyperledger.besu.consensus.qbft.pki.PkiBlockCreationConfigurationProvider; import org.hyperledger.besu.controller.BesuController; import org.hyperledger.besu.controller.BesuControllerBuilder; +import org.hyperledger.besu.crypto.Blake2bfMessageDigest; import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.crypto.KeyPairSecurityModule; import org.hyperledger.besu.crypto.KeyPairUtil; @@ -1718,6 +1719,14 @@ private void configureNativeLibs() { SignatureAlgorithmFactory.getInstance().disableNative(); logger.info("Using the Java implementation of the signature algorithm"); } + + if (unstableNativeLibraryOptions.getNativeBlake2bf() + && Blake2bfMessageDigest.Blake2bfDigest.isNative()) { + logger.info("Using the native implementation of the blake2bf algorithm"); + } else { + Blake2bfMessageDigest.Blake2bfDigest.disableNative(); + logger.info("Using the Java implementation of the blake2bf algorithm"); + } } private void validateOptions() { diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/NativeLibraryOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/NativeLibraryOptions.java index a016e777698..776a582ca8b 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/NativeLibraryOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/NativeLibraryOptions.java @@ -36,6 +36,15 @@ public class NativeLibraryOptions { arity = "1") private final Boolean nativeAltbn128 = Boolean.TRUE; + @CommandLine.Option( + hidden = true, + names = {"--Xblake2bf-native-enabled"}, + description = + "Per default a native library is used for blake2bf if present. " + + "If the Java implementation should be used instead, this option must be set to false", + arity = "1") + private final Boolean nativeBlake2bf = Boolean.TRUE; + public static NativeLibraryOptions create() { return new NativeLibraryOptions(); } @@ -47,4 +56,8 @@ public Boolean getNativeSecp() { public Boolean getNativeAltbn128() { return nativeAltbn128; } + + public Boolean getNativeBlake2bf() { + return nativeBlake2bf; + } } diff --git a/crypto/build.gradle b/crypto/build.gradle index 0374108eec5..5eac9e6d3de 100644 --- a/crypto/build.gradle +++ b/crypto/build.gradle @@ -38,6 +38,7 @@ dependencies { implementation 'org.apache.tuweni:tuweni-units' implementation 'org.hyperledger.besu:secp256k1' implementation 'org.hyperledger.besu:secp256r1' + implementation 'org.hyperledger.besu:blake2bf' testImplementation 'junit:junit' testImplementation 'org.assertj:assertj-core' diff --git a/crypto/src/main/java/org/hyperledger/besu/crypto/Blake2bfMessageDigest.java b/crypto/src/main/java/org/hyperledger/besu/crypto/Blake2bfMessageDigest.java index 7b472ac9cf6..00901696206 100644 --- a/crypto/src/main/java/org/hyperledger/besu/crypto/Blake2bfMessageDigest.java +++ b/crypto/src/main/java/org/hyperledger/besu/crypto/Blake2bfMessageDigest.java @@ -16,12 +16,17 @@ import static java.util.Arrays.copyOfRange; +import org.hyperledger.besu.nativelib.blake2bf.LibBlake2bf; + import org.bouncycastle.crypto.Digest; import org.bouncycastle.jcajce.provider.digest.BCMessageDigest; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Pack; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class Blake2bfMessageDigest extends BCMessageDigest implements Cloneable { + private static final Logger LOG = LoggerFactory.getLogger(Blake2bfMessageDigest.class); public Blake2bfMessageDigest() { super(new Blake2bfDigest()); @@ -37,7 +42,6 @@ public Blake2bfMessageDigest() { *

Optimized for 64-bit platforms */ public static class Blake2bfDigest implements Digest { - public static final int MESSAGE_LENGTH_BYTES = 213; private static final long[] IV = { @@ -76,8 +80,13 @@ public static class Blake2bfDigest implements Digest { private long rounds; // unsigned integer represented as long private final long[] v; + private static boolean useNative = LibBlake2bf.ENABLED; Blake2bfDigest() { + if (!useNative) { + LOG.info("Native blake2bf not available"); + } + buffer = new byte[MESSAGE_LENGTH_BYTES]; bufferPos = 0; @@ -90,20 +99,12 @@ public static class Blake2bfDigest implements Digest { v = new long[16]; } - // for tests - Blake2bfDigest( - final long[] h, final long[] m, final long[] t, final boolean f, final long rounds) { - assert rounds <= 4294967295L; // uint max value - buffer = new byte[MESSAGE_LENGTH_BYTES]; - bufferPos = 0; - - this.h = h; - this.m = m; - this.t = t; - this.f = f; - this.rounds = rounds; + public static void disableNative() { + useNative = false; + } - v = new long[16]; + public static boolean isNative() { + return useNative; } @Override @@ -123,16 +124,10 @@ public int getDigestSize() { */ @Override public void update(final byte in) { - - if (bufferPos == MESSAGE_LENGTH_BYTES) { // full buffer - throw new IllegalArgumentException(); - } else { - buffer[bufferPos] = in; - bufferPos++; - if (bufferPos == MESSAGE_LENGTH_BYTES) { - initialize(); - } - } + checkSize(1); + buffer[bufferPos] = in; + bufferPos++; + maybeInitialize(); } /** @@ -148,6 +143,15 @@ public void update(final byte[] in, final int offset, final int len) { return; } + checkSize(len); + + System.arraycopy(in, offset, buffer, bufferPos, len); + bufferPos += len; + + maybeInitialize(); + } + + private void checkSize(final int len) { if (len > MESSAGE_LENGTH_BYTES - bufferPos) { throw new IllegalArgumentException( "Attempting to update buffer with " @@ -156,12 +160,10 @@ public void update(final byte[] in, final int offset, final int len) { + (MESSAGE_LENGTH_BYTES - bufferPos) + " byte(s) left to fill"); } + } - System.arraycopy(in, offset, buffer, bufferPos, len); - - bufferPos += len; - - if (bufferPos == MESSAGE_LENGTH_BYTES) { + private void maybeInitialize() { + if (!useNative && bufferPos == MESSAGE_LENGTH_BYTES) { initialize(); } } @@ -178,10 +180,13 @@ public int doFinal(final byte[] out, final int offset) { throw new IllegalStateException("The buffer must be filled with 213 bytes"); } - compress(); - - for (int i = 0; i < h.length; i++) { - System.arraycopy(Pack.longToLittleEndian(h[i]), 0, out, i * 8, 8); + if (useNative) { + LibBlake2bf.blake2bf_eip152(out, buffer); + } else { + compress(); + for (int i = 0; i < h.length; i++) { + System.arraycopy(Pack.longToLittleEndian(h[i]), 0, out, i * 8, 8); + } } reset(); @@ -194,12 +199,14 @@ public int doFinal(final byte[] out, final int offset) { public void reset() { bufferPos = 0; Arrays.fill(buffer, (byte) 0); - Arrays.fill(h, 0); - Arrays.fill(m, (byte) 0); - Arrays.fill(t, 0); - f = false; - rounds = 12; - Arrays.fill(v, 0); + if (!useNative) { + Arrays.fill(h, 0); + Arrays.fill(m, (byte) 0); + Arrays.fill(t, 0); + f = false; + rounds = 12; + Arrays.fill(v, 0); + } } private void initialize() { diff --git a/crypto/src/test/java/org/hyperledger/besu/crypto/Blake2bfMessageDigestTest.java b/crypto/src/test/java/org/hyperledger/besu/crypto/Blake2bfMessageDigestTest.java index deb4de81f3a..bd00dc7dae1 100644 --- a/crypto/src/test/java/org/hyperledger/besu/crypto/Blake2bfMessageDigestTest.java +++ b/crypto/src/test/java/org/hyperledger/besu/crypto/Blake2bfMessageDigestTest.java @@ -18,8 +18,10 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import org.bouncycastle.util.Pack; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvFileSource; /** * Test vectors adapted from @@ -47,7 +49,7 @@ public class Blake2bfMessageDigestTest { -61, 120, -93, -42, -38 }; - @Before + @BeforeEach public void setUp() { messageDigest = new Blake2bfMessageDigest(); } @@ -121,4 +123,24 @@ public void throwsIfEmptyBufferUpdatedLargeByteArray() { }) .isInstanceOf(IllegalArgumentException.class); } + + @ParameterizedTest + @CsvFileSource(resources = "eip152TestCases.csv", numLinesToSkip = 1) + public void eip152TestCases(final String hexIn, final String hexExpected) { + System.out.println("in=" + hexIn); + byte[] in = hexStringToByteArray(hexIn); + byte[] expected = hexStringToByteArray(hexExpected); + messageDigest.update(in, 0, 213); + assertThat(messageDigest.digest()).isEqualTo(expected); + } + + private static byte[] hexStringToByteArray(final String s) { + int len = s.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = + (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16)); + } + return data; + } } diff --git a/crypto/src/test/resources/org/hyperledger/besu/crypto/eip152TestCases.csv b/crypto/src/test/resources/org/hyperledger/besu/crypto/eip152TestCases.csv new file mode 100644 index 00000000000..3591d53af8f --- /dev/null +++ b/crypto/src/test/resources/org/hyperledger/besu/crypto/eip152TestCases.csv @@ -0,0 +1,6 @@ +input,expected +0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001,08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b +0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001,ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923 +0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000,75ab69d3190a562c51aef8d88f1c2775876944407270c42c9844252c26d2875298743e7f6d5ea2f2d3e8d226039cd31b4e426ac4f2d3d666a610c2116fde4735 +0000000148c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001,b63a380cb2897d521994a85234ee2c181b5f844d2c624c002677e9703449d2fba551b3a8333bcdf5f2f7e08993d53923de3d64fcc68c034e717b9293fed7a421 +ffffffff48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001,fc59093aafa9ab43daae0e914c57635c5402d8e3d2130eb9b3cc181de7f0ecf9b22bf99a7815ce16419e200e01846e6b5df8cc7703041bbceb571de6631d2615 \ No newline at end of file diff --git a/gradle/versions.gradle b/gradle/versions.gradle index 5232957ab25..86ae9871d73 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -147,9 +147,10 @@ dependencyManagement { dependency 'org.fusesource.jansi:jansi:2.4.0' - dependency 'org.hyperledger.besu:bls12-381:0.5.0' - dependency 'org.hyperledger.besu:secp256k1:0.5.0' - dependency 'org.hyperledger.besu:secp256r1:0.5.0' + dependency 'org.hyperledger.besu:bls12-381:0.6.0' + dependency 'org.hyperledger.besu:secp256k1:0.6.0' + dependency 'org.hyperledger.besu:secp256r1:0.6.0' + dependency 'org.hyperledger.besu:blake2bf:0.6.0' dependency 'org.immutables:value-annotations:2.9.0' dependency 'org.immutables:value:2.9.0' From dcb951eb7d7c8ce1e99845c85ca6c98b0d26b7e5 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 23 Aug 2022 12:37:19 +0200 Subject: [PATCH 095/109] Better management of jemalloc presence/absence (#4237) Signed-off-by: Fabio Di Fabio Co-authored-by: Adrian Sutton --- CHANGELOG.md | 7 ++++--- .../org/hyperledger/besu/cli/BesuCommand.java | 14 ++++++++++++++ besu/src/main/scripts/unixStartScript.txt | 17 ++++++++++++++--- .../hyperledger/besu/cli/BesuCommandTest.java | 18 ++++++++++++++++++ 4 files changed, 50 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52e4bce8f35..0c7d298ee97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Additions and Improvements - Upgrade besu-native to 0.6.0 and use Blake2bf native implementation if available by default [#4264](https://github.com/hyperledger/besu/pull/4264) +- Better management of jemalloc presence/absence in startup script [#4237](https://github.com/hyperledger/besu/pull/4237) ### Bug Fixes @@ -34,7 +35,7 @@ ### Additions and Improvements - Deprecation warning for Ropsten, Rinkeby, Kiln [#4173](https://github.com/hyperledger/besu/pull/4173) -### Bug Fixes +### Bug Fixes - Fixes previous known issue [#3890](https://github.com/hyperledger/besu/issues/3890)from RC3 requiring a restart post-merge to continue correct transaction handling. - Stop producing stack traces when a get headers response only contains the range start header [#4189](https://github.com/hyperledger/besu/pull/4189) @@ -53,8 +54,8 @@ ### Additions and Improvements - Engine API: Change expiration time for JWT tokens to 60s [#4168](https://github.com/hyperledger/besu/pull/4168) - Sepolia mergeNetSplit block [#4158](https://github.com/hyperledger/besu/pull/4158) -- Goerli TTD [#4160](https://github.com/hyperledger/besu/pull/4160) -- Several logging improvements +- Goerli TTD [#4160](https://github.com/hyperledger/besu/pull/4160) +- Several logging improvements ### Bug Fixes - Allow to set any value for baseFeePerGas in the genesis file [#4177](https://github.com/hyperledger/besu/pull/4177) diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index d5fc6fe06ef..e2b16d55bad 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -186,6 +186,7 @@ import org.hyperledger.besu.util.number.Fraction; import org.hyperledger.besu.util.number.Percentage; import org.hyperledger.besu.util.number.PositiveNumber; +import org.hyperledger.besu.util.platform.PlatformDetector; import java.io.File; import java.io.IOException; @@ -1392,6 +1393,7 @@ public void parse( handleUnstableOptions(); preparePlugins(); parse(resultHandler, exceptionHandler, args); + detectJemalloc(); } @Override @@ -1493,6 +1495,18 @@ private void registerConverters() { commandLine.registerConverter(MetricCategory.class, metricCategoryConverter); } + private void detectJemalloc() { + // jemalloc is only supported on Linux at the moment + if (PlatformDetector.getOSType().equals("linux")) { + Optional.ofNullable(environment.get("BESU_USING_JEMALLOC")) + .ifPresentOrElse( + present -> logger.info("Using jemalloc"), + () -> + logger.info( + "jemalloc library not found, memory usage may be reduced by installing it")); + } + } + private void handleStableOptions() { commandLine.addMixin("Ethstats", ethstatsOptions); commandLine.addMixin("Private key file", nodePrivateKeyFileOption); diff --git a/besu/src/main/scripts/unixStartScript.txt b/besu/src/main/scripts/unixStartScript.txt index 50585f07660..3302b9c2fe1 100644 --- a/besu/src/main/scripts/unixStartScript.txt +++ b/besu/src/main/scripts/unixStartScript.txt @@ -182,8 +182,19 @@ APP_ARGS=`save "\$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- \$DEFAULT_JVM_OPTS \$JAVA_OPTS \$${optsEnvironmentVar} <% if ( appNameSystemProperty ) { %>"\"-D${appNameSystemProperty}=\$APP_BASE_NAME\"" <% } %>-classpath "\"\$CLASSPATH\"" <% if ( mainClassName.startsWith('--module ') ) { %>--module-path "\"\$MODULE_PATH\"" <% } %>${mainClassName} "\$APP_ARGS" -# limit malloc to 2 arenas, and use jemalloc if available -export MALLOC_ARENA_MAX=2 -export LD_PRELOAD=libjemalloc.so +unset BESU_USING_JEMALLOC +if [ "\$darwin" = "false" -a "\$msys" = "false" ]; then + # check if jemalloc is available + TEST_JEMALLOC=\$(LD_PRELOAD=libjemalloc.so sh -c true 2>&1) + + # if jemalloc is available the output is empty, otherwise the output has an error line + if [ -z "\$TEST_JEMALLOC" ]; then + export LD_PRELOAD=libjemalloc.so + export BESU_USING_JEMALLOC=true + else + # jemalloc not available, as fallback limit malloc to 2 arenas + export MALLOC_ARENA_MAX=2 + fi +fi exec "\$JAVACMD" "\$@" diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index 1b64a1cdb65..9878140ccd4 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -17,6 +17,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.startsWith; import static org.hyperledger.besu.cli.config.NetworkName.CLASSIC; import static org.hyperledger.besu.cli.config.NetworkName.DEV; @@ -94,6 +95,7 @@ import org.hyperledger.besu.plugin.services.rpc.PluginRpcRequest; import org.hyperledger.besu.util.number.Fraction; import org.hyperledger.besu.util.number.Percentage; +import org.hyperledger.besu.util.platform.PlatformDetector; import java.io.File; import java.io.IOException; @@ -5318,4 +5320,20 @@ public void pkiBlockCreationFullConfig() throws Exception { assertThat(pkiKeyStoreConfig.getTrustStorePassword()).isEqualTo("foo"); assertThat(pkiKeyStoreConfig.getCrlFilePath()).hasValue(Path.of("/tmp/crl")); } + + @Test + public void logsUsingJemallocWhenEnvVarPresent() { + assumeThat(PlatformDetector.getOSType(), is("linux")); + setEnvironmentVariable("BESU_USING_JEMALLOC", "true"); + parseCommand(); + verify(mockLogger).info("Using jemalloc"); + } + + @Test + public void logsSuggestInstallingJemallocWhenEnvVarNotPresent() { + assumeThat(PlatformDetector.getOSType(), is("linux")); + parseCommand(); + verify(mockLogger) + .info("jemalloc library not found, memory usage may be reduced by installing it"); + } } From 16922cac83f27327c4979bd8def12679086074a8 Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Tue, 23 Aug 2022 21:10:23 +1000 Subject: [PATCH 096/109] turn down logging (#4299) Signed-off-by: Sally MacFarlane --- .../java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgent.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgent.java index b9db0cbf0df..81fe8ad7e8e 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgent.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/rlpx/RlpxAgent.java @@ -554,7 +554,7 @@ private int compareDuplicateConnections(final RlpxConnection a, final RlpxConnec } } // Otherwise, keep older connection - LOG.info("comparing timestamps " + a.getInitiatedAt() + " with " + b.getInitiatedAt()); + LOG.debug("comparing timestamps " + a.getInitiatedAt() + " with " + b.getInitiatedAt()); return Math.toIntExact(a.getInitiatedAt() - b.getInitiatedAt()); } From b3b8e0aaebb1ac4390874b4dec7ca13738074296 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 23 Aug 2022 22:21:34 +0200 Subject: [PATCH 097/109] Filter out disconnected peers when fetching available peers (#4269) * Filter out disconnected peers when fetching available peers Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 1 + .../besu/ethereum/eth/manager/EthPeers.java | 4 ++- .../eth/manager/PendingPeerRequest.java | 19 +++++++------ .../AbstractRetryingSwitchingPeerTask.java | 2 +- .../sync/tasks/CompleteBlocksTaskTest.java | 28 +++++++++++++++---- .../DetermineCommonAncestorTaskTest.java | 4 +-- 6 files changed, 39 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c7d298ee97..7c3a4c43406 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Additions and Improvements - Upgrade besu-native to 0.6.0 and use Blake2bf native implementation if available by default [#4264](https://github.com/hyperledger/besu/pull/4264) - Better management of jemalloc presence/absence in startup script [#4237](https://github.com/hyperledger/besu/pull/4237) +- Filter out disconnected peers when fetching available peers [#4269](https://github.com/hyperledger/besu/pull/4269) ### Bug Fixes diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java index b45ab54a17d..dc6eead7920 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java @@ -203,7 +203,9 @@ public Stream streamAllPeers() { } public Stream streamAvailablePeers() { - return streamAllPeers().filter(EthPeer::readyForRequests); + return streamAllPeers() + .filter(EthPeer::readyForRequests) + .filter(peer -> !peer.isDisconnected()); } public Stream streamBestPeers() { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/PendingPeerRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/PendingPeerRequest.java index 57b0d9b5cc1..120b32bdfe3 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/PendingPeerRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/PendingPeerRequest.java @@ -52,18 +52,18 @@ public boolean attemptExecution() { if (result.isDone()) { return true; } - final Optional leastBusySuitablePeer = getLeastBusySuitablePeer(); - if (!leastBusySuitablePeer.isPresent()) { + final Optional maybePeer = getPeerToUse(); + if (maybePeer.isEmpty()) { // No peers have the required height. result.completeExceptionally(new NoAvailablePeersException()); return true; } else { - // At least one peer has the required height, but we not be able to use it if it's busy - final Optional selectedPeer = - leastBusySuitablePeer.filter(EthPeer::hasAvailableRequestCapacity); + // At least one peer has the required height, but we are not able to use it if it's busy + final Optional maybePeerWithCapacity = + maybePeer.filter(EthPeer::hasAvailableRequestCapacity); - selectedPeer.ifPresent(this::sendRequest); - return selectedPeer.isPresent(); + maybePeerWithCapacity.ifPresent(this::sendRequest); + return maybePeerWithCapacity.isPresent(); } } @@ -79,8 +79,9 @@ private synchronized void sendRequest(final EthPeer peer) { } } - private Optional getLeastBusySuitablePeer() { - return peer.isPresent() + private Optional getPeerToUse() { + // return the assigned peer if still valid, otherwise switch to another peer + return peer.filter(p -> !p.isDisconnected()).isPresent() ? peer : ethPeers .streamAvailablePeers() diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingSwitchingPeerTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingSwitchingPeerTask.java index d9724895e66..13751adcdf8 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingSwitchingPeerTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingSwitchingPeerTask.java @@ -131,7 +131,7 @@ private Stream remainingPeersToTry() { return getEthContext() .getEthPeers() .streamBestPeers() - .filter(peer -> !peer.isDisconnected() && !triedPeers.contains(peer)); + .filter(peer -> !triedPeers.contains(peer)); } private void refreshPeers() { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/CompleteBlocksTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/CompleteBlocksTaskTest.java index 2619313fcba..5193dd99865 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/CompleteBlocksTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/CompleteBlocksTaskTest.java @@ -85,21 +85,29 @@ public void shouldReduceTheBlockSegmentSizeAfterEachRetry() { final RespondingEthPeer respondingPeer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 1000); - peerCountToTimeout.set(3); final List requestedData = generateDataToBeRequested(10); final CompleteBlocksTask task = createTask(requestedData); final CompletableFuture> future = task.run(); - final List messageCollector = new ArrayList<>(); + final List messageCollector = new ArrayList<>(4); - respondingPeer.respond( + peerCountToTimeout.set(4); + // after 3 timeouts a peer is disconnected, so we need another peer to reach 4 retries + respondingPeer.respondTimes( + RespondingEthPeer.wrapResponderWithCollector( + RespondingEthPeer.emptyResponder(), messageCollector), + 3); + final RespondingEthPeer respondingPeer2 = + EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 1000); + respondingPeer2.respond( RespondingEthPeer.wrapResponderWithCollector( RespondingEthPeer.emptyResponder(), messageCollector)); assertThat(batchSize(messageCollector.get(0))).isEqualTo(10); assertThat(batchSize(messageCollector.get(1))).isEqualTo(5); assertThat(batchSize(messageCollector.get(2))).isEqualTo(4); + assertThat(batchSize(messageCollector.get(3))).isEqualTo(3); assertThat(future.isCompletedExceptionally()).isTrue(); assertThatThrownBy(future::get).hasCauseInstanceOf(MaxRetriesReachedException.class); } @@ -110,21 +118,29 @@ public void shouldNotReduceTheBlockSegmentSizeIfOnlyOneBlockNeeded() { final RespondingEthPeer respondingPeer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 1000); - peerCountToTimeout.set(3); final List requestedData = generateDataToBeRequested(1); final EthTask> task = createTask(requestedData); final CompletableFuture> future = task.run(); - final List messageCollector = new ArrayList<>(); + final List messageCollector = new ArrayList<>(4); - respondingPeer.respond( + peerCountToTimeout.set(4); + // after 3 timeouts a peer is disconnected, so we need another peer to reach 4 retries + respondingPeer.respondTimes( + RespondingEthPeer.wrapResponderWithCollector( + RespondingEthPeer.emptyResponder(), messageCollector), + 3); + final RespondingEthPeer respondingPeer2 = + EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 1000); + respondingPeer2.respond( RespondingEthPeer.wrapResponderWithCollector( RespondingEthPeer.emptyResponder(), messageCollector)); assertThat(batchSize(messageCollector.get(0))).isEqualTo(1); assertThat(batchSize(messageCollector.get(1))).isEqualTo(1); assertThat(batchSize(messageCollector.get(2))).isEqualTo(1); + assertThat(batchSize(messageCollector.get(3))).isEqualTo(1); assertThat(future.isCompletedExceptionally()).isTrue(); assertThatThrownBy(future::get).hasCauseInstanceOf(MaxRetriesReachedException.class); } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskTest.java index 1312a94711c..f8523b3c557 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskTest.java @@ -42,6 +42,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil; import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; import org.hyperledger.besu.ethereum.eth.manager.exceptions.EthTaskException; +import org.hyperledger.besu.ethereum.eth.manager.exceptions.EthTaskException.FailureReason; import org.hyperledger.besu.ethereum.eth.manager.task.EthTask; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; @@ -117,8 +118,7 @@ public void shouldFailIfPeerDisconnects() { assertThat(failure.get()).isNotNull(); final Throwable error = ExceptionUtils.rootCause(failure.get()); assertThat(error).isInstanceOf(EthTaskException.class); - assertThat(((EthTaskException) error).reason()) - .isEqualTo(EthTaskException.FailureReason.PEER_DISCONNECTED); + assertThat(((EthTaskException) error).reason()).isEqualTo(FailureReason.NO_AVAILABLE_PEERS); } @Test From 13b777f61adb4a4dc00b46cbd97df0b80756f9ad Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Wed, 24 Aug 2022 08:13:47 +1000 Subject: [PATCH 098/109] Reinstate Tessera tests with a fixed version (#4303) * Revert "ignore the tests that use tessera enclave via docker (#4297)" This reverts commit 98e214cedc475d036e412e9c1cfb931805ac9958. Signed-off-by: Sally MacFarlane * lock version of tessera and make public Signed-off-by: Sally MacFarlane Signed-off-by: Sally MacFarlane --- .../privacy/BftPrivacyClusterAcceptanceTest.java | 2 -- .../DeployPrivateSmartContractAcceptanceTest.java | 2 -- .../privacy/EnclaveErrorAcceptanceTest.java | 1 - .../privacy/FlexiblePrivacyAcceptanceTest.java | 2 -- .../acceptance/privacy/PrivCallAcceptanceTest.java | 2 -- ...DebugGetStateRootFlexibleGroupAcceptanceTest.java | 2 -- ...DebugGetStateRootOffchainGroupAcceptanceTest.java | 2 -- .../privacy/PrivGetCodeAcceptanceTest.java | 2 -- .../privacy/PrivGetLogsAcceptanceTest.java | 2 -- .../PrivGetPrivateTransactionAcceptanceTest.java | 2 -- .../privacy/PrivacyClusterAcceptanceTest.java | 2 -- .../privacy/PrivacyGroupAcceptanceTest.java | 2 -- .../privacy/PrivacyReceiptAcceptanceTest.java | 2 -- .../PrivateContractPublicStateAcceptanceTest.java | 2 -- .../privacy/PrivateGenesisAcceptanceTest.java | 2 -- .../privacy/PrivateLogFilterAcceptanceTest.java | 2 -- .../FlexibleMultiTenancyAcceptanceTest.java | 2 -- .../besu/tests/container/ContainerTestBase.java | 12 ++++++------ .../enclave/testutil/TesseraTestHarness.java | 4 ++-- 19 files changed, 8 insertions(+), 41 deletions(-) diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/BftPrivacyClusterAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/BftPrivacyClusterAcceptanceTest.java index e2672a86d6c..2baf1d1f5ce 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/BftPrivacyClusterAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/BftPrivacyClusterAcceptanceTest.java @@ -30,7 +30,6 @@ import java.util.Optional; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -39,7 +38,6 @@ import org.web3j.utils.Restriction; @RunWith(Parameterized.class) -@Ignore("Ignored since Tessera/Docker container startup causing errors") public class BftPrivacyClusterAcceptanceTest extends PrivacyAcceptanceTestBase { private final BftPrivacyType bftPrivacyType; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/DeployPrivateSmartContractAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/DeployPrivateSmartContractAcceptanceTest.java index 794a1e00883..71aa618cdd8 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/DeployPrivateSmartContractAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/DeployPrivateSmartContractAcceptanceTest.java @@ -26,11 +26,9 @@ import java.io.IOException; import java.util.Optional; -import org.junit.Ignore; import org.junit.Test; import org.web3j.utils.Restriction; -@Ignore("Ignored since Tessera/Docker container startup causing errors") public class DeployPrivateSmartContractAcceptanceTest extends ParameterizedEnclaveTestBase { private final PrivacyNode minerNode; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/EnclaveErrorAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/EnclaveErrorAcceptanceTest.java index 61fcceac934..7822768f140 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/EnclaveErrorAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/EnclaveErrorAcceptanceTest.java @@ -49,7 +49,6 @@ import org.web3j.utils.Restriction; @RunWith(Parameterized.class) -@Ignore("Ignored since Tessera/Docker container startup causing errors") public class EnclaveErrorAcceptanceTest extends PrivacyAcceptanceTestBase { private final PrivacyNode alice; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/FlexiblePrivacyAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/FlexiblePrivacyAcceptanceTest.java index 362b26c56a4..d64f73d2a03 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/FlexiblePrivacyAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/FlexiblePrivacyAcceptanceTest.java @@ -38,7 +38,6 @@ import com.google.common.collect.Lists; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -51,7 +50,6 @@ import org.web3j.tx.Contract; @RunWith(Parameterized.class) -@Ignore("Ignored since Tessera/Docker container startup causing errors") public class FlexiblePrivacyAcceptanceTest extends FlexiblePrivacyAcceptanceTestBase { private final EnclaveType enclaveType; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivCallAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivCallAcceptanceTest.java index f073872686a..b2c9c3bda54 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivCallAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivCallAcceptanceTest.java @@ -33,7 +33,6 @@ import java.util.Optional; import javax.annotation.Nonnull; -import org.junit.Ignore; import org.junit.Test; import org.web3j.abi.FunctionEncoder; import org.web3j.abi.TypeReference; @@ -49,7 +48,6 @@ import org.web3j.tx.Contract; import org.web3j.utils.Restriction; -@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivCallAcceptanceTest extends ParameterizedEnclaveTestBase { private static final int VALUE = 1024; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootFlexibleGroupAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootFlexibleGroupAcceptanceTest.java index 9681ec60e8c..59973fd00be 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootFlexibleGroupAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootFlexibleGroupAcceptanceTest.java @@ -32,7 +32,6 @@ import org.apache.tuweni.bytes.Bytes32; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -40,7 +39,6 @@ import org.testcontainers.containers.Network; @RunWith(Parameterized.class) -@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivDebugGetStateRootFlexibleGroupAcceptanceTest extends FlexiblePrivacyAcceptanceTestBase { diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootOffchainGroupAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootOffchainGroupAcceptanceTest.java index 2d1fd76ecc4..92643446ddb 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootOffchainGroupAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootOffchainGroupAcceptanceTest.java @@ -29,12 +29,10 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes32; -import org.junit.Ignore; import org.junit.Test; import org.testcontainers.containers.Network; import org.web3j.utils.Restriction; -@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivDebugGetStateRootOffchainGroupAcceptanceTest extends ParameterizedEnclaveTestBase { private final PrivacyNode aliceNode; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetCodeAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetCodeAcceptanceTest.java index 640f34639b1..c08006f694b 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetCodeAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetCodeAcceptanceTest.java @@ -29,11 +29,9 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.junit.Ignore; import org.junit.Test; import org.web3j.utils.Restriction; -@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivGetCodeAcceptanceTest extends ParameterizedEnclaveTestBase { private final PrivacyNode alice; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetLogsAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetLogsAcceptanceTest.java index e627206592f..62519385a2e 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetLogsAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetLogsAcceptanceTest.java @@ -30,14 +30,12 @@ import java.util.List; import java.util.Optional; -import org.junit.Ignore; import org.junit.Test; import org.web3j.protocol.besu.response.privacy.PrivateTransactionReceipt; import org.web3j.protocol.core.methods.response.EthLog.LogResult; import org.web3j.utils.Restriction; @SuppressWarnings("rawtypes") -@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivGetLogsAcceptanceTest extends ParameterizedEnclaveTestBase { /* diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetPrivateTransactionAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetPrivateTransactionAcceptanceTest.java index 0abac7bb9c5..91896761d09 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetPrivateTransactionAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetPrivateTransactionAcceptanceTest.java @@ -32,12 +32,10 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.junit.Ignore; import org.junit.Test; import org.testcontainers.containers.Network; import org.web3j.utils.Restriction; -@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivGetPrivateTransactionAcceptanceTest extends ParameterizedEnclaveTestBase { private final PrivacyNode alice; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyClusterAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyClusterAcceptanceTest.java index 0386e29a4dc..1284daf917e 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyClusterAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyClusterAcceptanceTest.java @@ -42,7 +42,6 @@ import io.vertx.core.Vertx; import org.apache.tuweni.bytes.Bytes; import org.junit.After; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -58,7 +57,6 @@ import org.web3j.utils.Numeric; @RunWith(Parameterized.class) -@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivacyClusterAcceptanceTest extends PrivacyAcceptanceTestBase { private final PrivacyNode alice; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyGroupAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyGroupAcceptanceTest.java index 6d6b4b6c3c6..ab1bd91d0e7 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyGroupAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyGroupAcceptanceTest.java @@ -35,7 +35,6 @@ import java.util.Optional; import org.apache.logging.log4j.Level; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -46,7 +45,6 @@ import org.web3j.utils.Base64String; @RunWith(Parameterized.class) -@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivacyGroupAcceptanceTest extends PrivacyAcceptanceTestBase { private final PrivacyNode alice; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyReceiptAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyReceiptAcceptanceTest.java index f4199ef11c4..0b45d29732a 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyReceiptAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyReceiptAcceptanceTest.java @@ -34,11 +34,9 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.junit.Ignore; import org.junit.Test; import org.web3j.utils.Restriction; -@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivacyReceiptAcceptanceTest extends ParameterizedEnclaveTestBase { final MinerTransactions minerTransactions = new MinerTransactions(); diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateContractPublicStateAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateContractPublicStateAcceptanceTest.java index 9c03b4c3afd..83a7ce66d8b 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateContractPublicStateAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateContractPublicStateAcceptanceTest.java @@ -33,7 +33,6 @@ import java.math.BigInteger; import java.util.Optional; -import org.junit.Ignore; import org.junit.Test; import org.testcontainers.containers.Network; import org.web3j.protocol.besu.response.privacy.PrivateTransactionReceipt; @@ -43,7 +42,6 @@ import org.web3j.tx.exceptions.ContractCallException; import org.web3j.utils.Restriction; -@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivateContractPublicStateAcceptanceTest extends ParameterizedEnclaveTestBase { private final PrivacyNode transactionNode; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateGenesisAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateGenesisAcceptanceTest.java index dea263883b4..29d5b655e3c 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateGenesisAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateGenesisAcceptanceTest.java @@ -29,7 +29,6 @@ import java.math.BigInteger; import java.util.Optional; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -37,7 +36,6 @@ import org.web3j.utils.Restriction; @RunWith(Parameterized.class) -@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivateGenesisAcceptanceTest extends ParameterizedEnclaveTestBase { private final PrivacyNode alice; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateLogFilterAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateLogFilterAcceptanceTest.java index d2301d0de2c..a6837f95465 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateLogFilterAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateLogFilterAcceptanceTest.java @@ -31,14 +31,12 @@ import java.util.List; import java.util.Optional; -import org.junit.Ignore; import org.junit.Test; import org.web3j.protocol.besu.response.privacy.PrivateTransactionReceipt; import org.web3j.protocol.core.methods.response.EthLog.LogResult; import org.web3j.utils.Restriction; @SuppressWarnings("rawtypes") -@Ignore("Ignored since Tessera/Docker container startup causing errors") public class PrivateLogFilterAcceptanceTest extends ParameterizedEnclaveTestBase { private final PrivacyNode node; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/FlexibleMultiTenancyAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/FlexibleMultiTenancyAcceptanceTest.java index 4378ab6de11..7907c37a110 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/FlexibleMultiTenancyAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/FlexibleMultiTenancyAcceptanceTest.java @@ -40,7 +40,6 @@ import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -51,7 +50,6 @@ import org.web3j.utils.Restriction; @RunWith(Parameterized.class) -@Ignore("Ignored since Tessera/Docker container startup causing errors") public class FlexibleMultiTenancyAcceptanceTest extends FlexiblePrivacyAcceptanceTestBase { private final EnclaveType enclaveType; diff --git a/container-tests/tests/src/test/java/org/hyperledger/besu/tests/container/ContainerTestBase.java b/container-tests/tests/src/test/java/org/hyperledger/besu/tests/container/ContainerTestBase.java index 64930af5bc0..b116a24d139 100644 --- a/container-tests/tests/src/test/java/org/hyperledger/besu/tests/container/ContainerTestBase.java +++ b/container-tests/tests/src/test/java/org/hyperledger/besu/tests/container/ContainerTestBase.java @@ -48,8 +48,8 @@ public class ContainerTestBase { // private final String besuImage = "hyperledger/besu:21.7.0-SNAPSHOT"; private final String besuImage = System.getProperty("containertest.imagename"); - private final String goQuorumVersion = "22.4.4"; - private final String tesseraVersion = "22.1.3"; + public static final String GOQUORUM_VERSION = "22.4.4"; + public static final String TESSERA_VERSION = "22.1.5"; protected final String goQuorumTesseraPubKey = "3XGBIf+x8IdVQOVfIsbRnHwTYOJP/Fx84G8gMmy8qDM="; protected final String besuTesseraPubKey = "8JJLEAbq6o9m4Kqm++v0Y1n9Z2ryAFtZTyhnxSKWgws="; @@ -127,7 +127,7 @@ public void setUp() throws IOException, InterruptedException { goQuorumContainer.getMappedPort(goQuorumRpcPort)); waitFor(10, () -> assertClientVersion(besuWeb3j, "besu")); - waitFor(10, () -> assertClientVersion(goQuorumWeb3j, goQuorumVersion)); + waitFor(10, () -> assertClientVersion(goQuorumWeb3j, GOQUORUM_VERSION)); // Tell GoQuorum to peer to Besu goQuorumContainer.execInContainer( @@ -187,7 +187,7 @@ private GenericContainer buildGoQuorumTesseraContainer( final String containerIpcPath, final String privKeyPath, final String pubKeyPath) { - return new GenericContainer("quorumengineering/tessera:" + tesseraVersion) + return new GenericContainer("quorumengineering/tessera:" + TESSERA_VERSION) .withNetwork(containerNetwork) .withNetworkAliases("goQuorumTessera") .withClasspathResourceMapping( @@ -209,7 +209,7 @@ private GenericContainer buildGoQuorumTesseraContainer( private GenericContainer buildBesuTesseraContainer( final String privKeyPath, final String pubKeyPath) { - return new GenericContainer("quorumengineering/tessera:" + tesseraVersion) + return new GenericContainer("quorumengineering/tessera:" + TESSERA_VERSION) .withNetwork(containerNetwork) .withNetworkAliases("besuTessera") .withClasspathResourceMapping( @@ -230,7 +230,7 @@ private GenericContainer buildBesuTesseraContainer( private GenericContainer buildGoQuorumContainer( final String ipcPath, final String ipcBindDir, final String containerIpcPath) { - return new GenericContainer("quorumengineering/quorum:" + goQuorumVersion) + return new GenericContainer("quorumengineering/quorum:" + GOQUORUM_VERSION) .withNetwork(containerNetwork) .dependsOn(tesseraGoQuorumContainer) .withExposedPorts(goQuorumRpcPort, goQuorumP2pPort) diff --git a/testutil/src/main/java/org/hyperledger/enclave/testutil/TesseraTestHarness.java b/testutil/src/main/java/org/hyperledger/enclave/testutil/TesseraTestHarness.java index e8117e60f0a..f70c97cad91 100644 --- a/testutil/src/main/java/org/hyperledger/enclave/testutil/TesseraTestHarness.java +++ b/testutil/src/main/java/org/hyperledger/enclave/testutil/TesseraTestHarness.java @@ -49,7 +49,7 @@ public class TesseraTestHarness implements EnclaveTestHarness { private URI q2TUri; private URI thirdPartyUri; - private final String tesseraVersion = "latest"; + public static final String TESSERA_VERSION = "22.1.5"; private final int thirdPartyPort = 9081; private final int q2TPort = 9082; @@ -264,7 +264,7 @@ private String buildKeyConfig() { private GenericContainer buildTesseraContainer(final String configFilePath) { final String containerConfigFilePath = "/tmp/config.json"; final String keyDir = enclaveConfiguration.getTempDir().toString(); - return new GenericContainer<>("quorumengineering/tessera:" + tesseraVersion) + return new GenericContainer<>("quorumengineering/tessera:" + TESSERA_VERSION) .withCopyFileToContainer(MountableFile.forHostPath(configFilePath), containerConfigFilePath) .withFileSystemBind(keyDir, containerKeyDir) .withCommand("--configfile " + containerConfigFilePath) From e5e6a679dd50d4cd7625b613e423744aa37286cd Mon Sep 17 00:00:00 2001 From: Stefan Pingel <16143240+pinges@users.noreply.github.com> Date: Wed, 24 Aug 2022 09:15:37 +1000 Subject: [PATCH 099/109] interpret an empty string (0x80) as an unsigned byte of 0 (#4283) * interprete an empty string (0x80) as an unsigned byte of 0 Signed-off-by: Stefan Co-authored-by: Sally MacFarlane --- CHANGELOG.md | 1 + .../p2p/rlpx/wire/WireMessagesSedesTest.java | 20 +++++++++++++++---- .../besu/ethereum/rlp/AbstractRLPInput.java | 11 +++++++--- .../besu/ethereum/rlp/RLPInput.java | 9 ++++++++- 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c3a4c43406..cb95fabebf9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - Refactor and fix retrying get block switching peer [#4256](https://github.com/hyperledger/besu/pull/4256) - Fix encoding of key (short hex) in eth_getProof [#4261](https://github.com/hyperledger/besu/pull/4261) - Fix for post-merge networks fast-sync [#4224](https://github.com/hyperledger/besu/pull/4224), [#4276](https://github.com/hyperledger/besu/pull/4276) +- Accept wit/80 from Nethermind [#4279](https://github.com/hyperledger/besu/pull/4279) ### Download links - https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/22.7.1/besu-22.7.1.tar.gz / sha256: `7cca4c11e1d7525c172f2af9fbf456d134ada60e970d8b6abcfcd6c623b5dd36` diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/wire/WireMessagesSedesTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/wire/WireMessagesSedesTest.java index e3e3ffcd82f..6adbd1b24bc 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/wire/WireMessagesSedesTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/rlpx/wire/WireMessagesSedesTest.java @@ -34,7 +34,7 @@ public void deserializeHello() { + "b35761b0fe3f0de19cb96092be29a0d0c033a1629d3cf270345586679aba8bbda61069532e3ac7551fc3a9" + "7766c30037184a5bed48a821861"); - assertSedesWorks(rlp); + assertSedesWorks(rlp, true); rlp = decodeHexDump( @@ -43,11 +43,21 @@ public void deserializeHello() { + "dd83a6a6580b2559c3c2d87527b83ea8f232ddeed2fff3263949105761ab5d0fe3733046e0e75aaa83cada" + "3b1e5d41"); - assertSedesWorks(rlp); + assertSedesWorks(rlp, true); + + rlp = + decodeHexDump( + "f8a305b74e65746865726d696e642f76312e31332e342d302d3365353937326332342d32303232303831312f5836342d4c696e75782f362e302e36e4c5836574683ec5836574683fc58365746840c58365746841c58365746842c5837769748082765db84005c95b2618ba1ca53f0f019d1750d12769267705e46b4dbfb77f73998b21d30973161542a2090bcaa5876e6aed99436009f3f646029bb723b8dff75feec27374"); + // This test conatains a hello message from Nethermind. The Capability version of the wit + // capability is encoded as 0x80, which is an empty string + assertSedesWorks(rlp, false); } - private static void assertSedesWorks(final byte[] data) { + private static void assertSedesWorks(final byte[] data, final boolean encEqualsInput) { + // TODO: the boolean was added because we do encode the version number 0 as 0x00, not as 0x80 + // Ticket #4284 to address the broader issue of encoding/decoding zero final Bytes input = Bytes.wrap(data); + final PeerInfo peerInfo = PeerInfo.readFrom(RLP.input(input)); assertThat(peerInfo.getClientId()).isNotBlank(); @@ -59,6 +69,8 @@ private static void assertSedesWorks(final byte[] data) { // Re-serialize and check that data matches final BytesValueRLPOutput out = new BytesValueRLPOutput(); peerInfo.writeTo(out); - assertThat(out.encoded()).isEqualTo(input); + if (encEqualsInput) { + assertThat(out.encoded()).isEqualTo(input); + } } } diff --git a/ethereum/rlp/src/main/java/org/hyperledger/besu/ethereum/rlp/AbstractRLPInput.java b/ethereum/rlp/src/main/java/org/hyperledger/besu/ethereum/rlp/AbstractRLPInput.java index 584ecf373d9..65c07297fae 100644 --- a/ethereum/rlp/src/main/java/org/hyperledger/besu/ethereum/rlp/AbstractRLPInput.java +++ b/ethereum/rlp/src/main/java/org/hyperledger/besu/ethereum/rlp/AbstractRLPInput.java @@ -129,13 +129,13 @@ private void prepareCurrentItem() { // Sets the kind of the item, the offset at which his payload starts and the size of this // payload. try { - RLPDecodingHelpers.RLPElementMetadata elementMetadata = + final RLPDecodingHelpers.RLPElementMetadata elementMetadata = RLPDecodingHelpers.rlpElementMetadata(this::inputByte, size, currentItem); currentKind = elementMetadata.kind; currentPayloadOffset = elementMetadata.payloadStart; currentPayloadSize = elementMetadata.payloadSize; - } catch (RLPException exception) { - String message = + } catch (final RLPException exception) { + final String message = String.format( exception.getMessage() + getErrorMessageSuffix(), getErrorMessageSuffixParams()); throw new RLPException(message, exception); @@ -526,6 +526,11 @@ public boolean isEndOfCurrentList() { return depth > 0 && currentItem >= endOfListOffset[depth - 1]; } + @Override + public boolean isZeroLengthString() { + return currentKind == RLPDecodingHelpers.Kind.SHORT_ELEMENT && currentPayloadSize == 0; + } + @Override public void reset() { setTo(0); diff --git a/ethereum/rlp/src/main/java/org/hyperledger/besu/ethereum/rlp/RLPInput.java b/ethereum/rlp/src/main/java/org/hyperledger/besu/ethereum/rlp/RLPInput.java index 9fa5d53d3fb..49b01c65404 100644 --- a/ethereum/rlp/src/main/java/org/hyperledger/besu/ethereum/rlp/RLPInput.java +++ b/ethereum/rlp/src/main/java/org/hyperledger/besu/ethereum/rlp/RLPInput.java @@ -221,6 +221,11 @@ public interface RLPInput { * long. */ default int readUnsignedByte() { + if (isZeroLengthString()) { + // Decode an empty string (0x80) as an unsigned byte with value 0 + readBytes(); + return 0; + } return readByte() & 0xFF; } @@ -276,7 +281,7 @@ default long readUnsignedInt() { Bytes32 readBytes32(); /** - * Reads the next iterm of this input (assuming it is not a list) and transform it with the + * Reads the next item of this input (assuming it is not a list) and transforms it with the * provided mapping function. * *

Note that the only benefit of this method over calling the mapper function on the result of @@ -311,6 +316,8 @@ default long readUnsignedInt() { */ Bytes raw(); + boolean isZeroLengthString(); + /** Resets this RLP input to the start. */ void reset(); From 80b79504571ce499b42658d2e800536c88f3e00d Mon Sep 17 00:00:00 2001 From: Pedro Novais Date: Wed, 24 Aug 2022 14:13:01 +0100 Subject: [PATCH 100/109] create AbstractJsonRpcTest for better code reuse in other similar tests (#4286) * create AbstractJsonRpcTest to enable future code reuse in similar tests Signed-off-by: Pedro Novais Co-authored-by: Antony Denyer --- .../JsonRpcTestCase.java} | 6 +- .../jsonrpc/AbstractJsonRpcTest.java | 103 ++++++++++++++++++ .../ExecutionEngineAcceptanceTest.java | 70 +----------- 3 files changed, 112 insertions(+), 67 deletions(-) rename acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/{engine/EngineTestCase.java => rpc/JsonRpcTestCase.java} (92%) create mode 100644 acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/AbstractJsonRpcTest.java diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/engine/EngineTestCase.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/rpc/JsonRpcTestCase.java similarity index 92% rename from acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/engine/EngineTestCase.java rename to acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/rpc/JsonRpcTestCase.java index 6d888b054b1..50dbff13f94 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/engine/EngineTestCase.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/rpc/JsonRpcTestCase.java @@ -12,19 +12,19 @@ * * SPDX-License-Identifier: Apache-2.0 */ -package org.hyperledger.besu.tests.acceptance.dsl.engine; +package org.hyperledger.besu.tests.acceptance.dsl.rpc; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.JsonNode; -public class EngineTestCase { +public class JsonRpcTestCase { private final JsonNode request; private final JsonNode response; private final int statusCode; @JsonCreator - public EngineTestCase( + public JsonRpcTestCase( @JsonProperty("request") final JsonNode request, @JsonProperty("response") final JsonNode response, @JsonProperty("statusCode") final int statusCode) { diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/AbstractJsonRpcTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/AbstractJsonRpcTest.java new file mode 100644 index 00000000000..b174a5e1b4d --- /dev/null +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/AbstractJsonRpcTest.java @@ -0,0 +1,103 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.tests.acceptance.jsonrpc; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.hyperledger.besu.tests.acceptance.dsl.condition.net.NetConditions; +import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode; +import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.Cluster; +import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.BesuNodeFactory; +import org.hyperledger.besu.tests.acceptance.dsl.rpc.JsonRpcTestCase; +import org.hyperledger.besu.tests.acceptance.dsl.transaction.net.NetTransactions; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.databind.ObjectMapper; +import okhttp3.Call; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import org.junit.Test; + +abstract class AbstractJsonRpcTest { + private static final MediaType MEDIA_TYPE_JSON = + MediaType.parse("application/json; charset=utf-8"); + + static class JsonRpcTestsContext { + final Cluster cluster; + final BesuNode executionEngine; + final OkHttpClient consensusClient; + final ObjectMapper mapper; + + public JsonRpcTestsContext(final String genesisFile) throws IOException { + cluster = new Cluster(new NetConditions(new NetTransactions())); + executionEngine = + new BesuNodeFactory().createExecutionEngineGenesisNode("executionEngine", genesisFile); + cluster.start(executionEngine); + consensusClient = new OkHttpClient(); + + mapper = new ObjectMapper(); + } + + public void tearDown() { + cluster.close(); + } + } + + private final JsonRpcTestsContext testsContext; + private final URI testCaseFileURI; + + public AbstractJsonRpcTest( + final String ignored, final JsonRpcTestsContext testsContext, final URI testCaseFileURI) { + this.testCaseFileURI = testCaseFileURI; + this.testsContext = testsContext; + } + + @Test + public void test() throws IOException { + final JsonRpcTestCase testCase = + testsContext.mapper.readValue(testCaseFileURI.toURL(), JsonRpcTestCase.class); + + final Call preparePayloadRequest = + testsContext.consensusClient.newCall( + new Request.Builder() + .url(testsContext.executionEngine.engineRpcUrl().get()) + .post(RequestBody.create(testCase.getRequest().toString(), MEDIA_TYPE_JSON)) + .build()); + final Response response = preparePayloadRequest.execute(); + + assertThat(response.code()).isEqualTo(testCase.getStatusCode()); + assertThat(response.body().string()).isEqualTo(testCase.getResponse().toPrettyString()); + } + + public static Iterable testCases(final String testCasesPath) throws URISyntaxException { + + final File[] testCasesList = + new File(AbstractJsonRpcTest.class.getResource(testCasesPath).toURI()).listFiles(); + + return Arrays.stream(testCasesList) + .sorted() + .map(file -> new Object[] {file.getName(), file.toURI()}) + .collect(Collectors.toList()); + } +} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEngineAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEngineAcceptanceTest.java index a7329112d24..0ee0c17aa6b 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEngineAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEngineAcceptanceTest.java @@ -14,96 +14,38 @@ */ package org.hyperledger.besu.tests.acceptance.jsonrpc; -import static org.assertj.core.api.Assertions.assertThat; - -import org.hyperledger.besu.tests.acceptance.dsl.condition.net.NetConditions; -import org.hyperledger.besu.tests.acceptance.dsl.engine.EngineTestCase; -import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode; -import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.Cluster; -import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.BesuNodeFactory; -import org.hyperledger.besu.tests.acceptance.dsl.transaction.net.NetTransactions; - -import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; -import java.util.Arrays; -import java.util.stream.Collectors; -import com.fasterxml.jackson.databind.ObjectMapper; -import okhttp3.Call; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; import org.junit.AfterClass; import org.junit.BeforeClass; -import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @RunWith(Parameterized.class) -public class ExecutionEngineAcceptanceTest { +public class ExecutionEngineAcceptanceTest extends AbstractJsonRpcTest { private static final String GENESIS_FILE = "/jsonrpc/engine/genesis.json"; private static final String TEST_CASE_PATH = "/jsonrpc/engine/test-cases/"; - private static final MediaType MEDIA_TYPE_JSON = - MediaType.parse("application/json; charset=utf-8"); - - private static Cluster cluster; - private static BesuNode executionEngine; - private static OkHttpClient consensusClient; - private static ObjectMapper mapper; - private final URI testCaseFileURI; + private static JsonRpcTestsContext testsContext; public ExecutionEngineAcceptanceTest(final String ignored, final URI testCaseFileURI) { - this.testCaseFileURI = testCaseFileURI; + super(ignored, testsContext, testCaseFileURI); } @BeforeClass public static void init() throws IOException { - cluster = new Cluster(new NetConditions(new NetTransactions())); - - executionEngine = - new BesuNodeFactory().createExecutionEngineGenesisNode("executionEngine", GENESIS_FILE); - cluster.start(executionEngine); - consensusClient = new OkHttpClient(); - - mapper = new ObjectMapper(); - } - - @Test - public void test() throws IOException { - final EngineTestCase testCase = mapper.readValue(testCaseFileURI.toURL(), EngineTestCase.class); - - final Call preparePayloadRequest = - consensusClient.newCall( - new Request.Builder() - .url(executionEngine.engineRpcUrl().get()) - .post(RequestBody.create(testCase.getRequest().toString(), MEDIA_TYPE_JSON)) - .build()); - final Response response = preparePayloadRequest.execute(); - - assertThat(response.code()).isEqualTo(testCase.getStatusCode()); - assertThat(response.body().string()).isEqualTo(testCase.getResponse().toPrettyString()); + testsContext = new JsonRpcTestsContext(GENESIS_FILE); } @Parameterized.Parameters(name = "{0}") public static Iterable testCases() throws URISyntaxException { - - final File testCasePath = - new File(ExecutionEngineAcceptanceTest.class.getResource(TEST_CASE_PATH).toURI()); - final File[] testCasesList = testCasePath.listFiles(); - - return Arrays.stream(testCasesList) - .sorted() - .map(file -> new Object[] {file.getName(), file.toURI()}) - .collect(Collectors.toList()); + return AbstractJsonRpcTest.testCases(TEST_CASE_PATH); } @AfterClass public static void tearDown() { - cluster.close(); + testsContext.cluster.close(); } } From 4622cf6820a3bbf788de736099f5807a781305a6 Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Thu, 25 Aug 2022 09:46:01 +1000 Subject: [PATCH 101/109] update Tessera version and ubuntu for xl-machine-executor (#4305) * latest ubuntu for xl-machine-ex * tessera docker image version Signed-off-by: Sally MacFarlane --- .circleci/config.yml | 2 +- build.gradle | 2 +- .../org/hyperledger/besu/tests/container/ContainerTestBase.java | 2 +- .../org/hyperledger/enclave/testutil/TesseraTestHarness.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 106d7667324..5b5923e2200 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -48,7 +48,7 @@ executors: xl_machine_executor: machine: - image: ubuntu-2004:202101-01 + image: ubuntu-2004:202201-02 #Ubuntu 20.04, Docker v20.10.12, Docker Compose v1.29.2, Google Cloud SDK updates resource_class: xlarge trivy_executor: diff --git a/build.gradle b/build.gradle index a4e5651b89f..78b62d86885 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ import net.ltgt.gradle.errorprone.CheckSeverity import java.text.SimpleDateFormat plugins { - id 'com.diffplug.spotless' version '6.8.0' + id 'com.diffplug.spotless' version '6.10.0' id 'com.github.ben-manes.versions' version '0.42.0' id 'com.github.hierynomus.license' version '0.16.1-fix' id 'com.jfrog.artifactory' version '4.28.3' diff --git a/container-tests/tests/src/test/java/org/hyperledger/besu/tests/container/ContainerTestBase.java b/container-tests/tests/src/test/java/org/hyperledger/besu/tests/container/ContainerTestBase.java index b116a24d139..5e5e17e6a22 100644 --- a/container-tests/tests/src/test/java/org/hyperledger/besu/tests/container/ContainerTestBase.java +++ b/container-tests/tests/src/test/java/org/hyperledger/besu/tests/container/ContainerTestBase.java @@ -49,7 +49,7 @@ public class ContainerTestBase { private final String besuImage = System.getProperty("containertest.imagename"); public static final String GOQUORUM_VERSION = "22.4.4"; - public static final String TESSERA_VERSION = "22.1.5"; + public static final String TESSERA_VERSION = "22.1.6"; protected final String goQuorumTesseraPubKey = "3XGBIf+x8IdVQOVfIsbRnHwTYOJP/Fx84G8gMmy8qDM="; protected final String besuTesseraPubKey = "8JJLEAbq6o9m4Kqm++v0Y1n9Z2ryAFtZTyhnxSKWgws="; diff --git a/testutil/src/main/java/org/hyperledger/enclave/testutil/TesseraTestHarness.java b/testutil/src/main/java/org/hyperledger/enclave/testutil/TesseraTestHarness.java index f70c97cad91..79795e9965e 100644 --- a/testutil/src/main/java/org/hyperledger/enclave/testutil/TesseraTestHarness.java +++ b/testutil/src/main/java/org/hyperledger/enclave/testutil/TesseraTestHarness.java @@ -49,7 +49,7 @@ public class TesseraTestHarness implements EnclaveTestHarness { private URI q2TUri; private URI thirdPartyUri; - public static final String TESSERA_VERSION = "22.1.5"; + public static final String TESSERA_VERSION = "22.1.6"; private final int thirdPartyPort = 9081; private final int q2TPort = 9082; From 44987b0bead139af4f6bb8949777763c7b570ace Mon Sep 17 00:00:00 2001 From: Pedro Novais Date: Thu, 25 Aug 2022 01:45:15 +0100 Subject: [PATCH 102/109] small variables renaming in AbstractJsonRpcTest (#4308) Signed-off-by: Pedro Novais Signed-off-by: Pedro Novais Co-authored-by: Sally MacFarlane --- .../jsonrpc/AbstractJsonRpcTest.java | 18 +++++++++--------- .../jsonrpc/ExecutionEngineAcceptanceTest.java | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/AbstractJsonRpcTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/AbstractJsonRpcTest.java index b174a5e1b4d..421021fbe8e 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/AbstractJsonRpcTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/AbstractJsonRpcTest.java @@ -45,16 +45,16 @@ abstract class AbstractJsonRpcTest { static class JsonRpcTestsContext { final Cluster cluster; - final BesuNode executionEngine; - final OkHttpClient consensusClient; + final BesuNode besuNode; + final OkHttpClient httpClient; final ObjectMapper mapper; public JsonRpcTestsContext(final String genesisFile) throws IOException { cluster = new Cluster(new NetConditions(new NetTransactions())); - executionEngine = + besuNode = new BesuNodeFactory().createExecutionEngineGenesisNode("executionEngine", genesisFile); - cluster.start(executionEngine); - consensusClient = new OkHttpClient(); + cluster.start(besuNode); + httpClient = new OkHttpClient(); mapper = new ObjectMapper(); } @@ -78,13 +78,13 @@ public void test() throws IOException { final JsonRpcTestCase testCase = testsContext.mapper.readValue(testCaseFileURI.toURL(), JsonRpcTestCase.class); - final Call preparePayloadRequest = - testsContext.consensusClient.newCall( + final Call testRequest = + testsContext.httpClient.newCall( new Request.Builder() - .url(testsContext.executionEngine.engineRpcUrl().get()) + .url(testsContext.besuNode.engineRpcUrl().get()) .post(RequestBody.create(testCase.getRequest().toString(), MEDIA_TYPE_JSON)) .build()); - final Response response = preparePayloadRequest.execute(); + final Response response = testRequest.execute(); assertThat(response.code()).isEqualTo(testCase.getStatusCode()); assertThat(response.body().string()).isEqualTo(testCase.getResponse().toPrettyString()); diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEngineAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEngineAcceptanceTest.java index 0ee0c17aa6b..3e32955eb6f 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEngineAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/jsonrpc/ExecutionEngineAcceptanceTest.java @@ -41,7 +41,7 @@ public static void init() throws IOException { @Parameterized.Parameters(name = "{0}") public static Iterable testCases() throws URISyntaxException { - return AbstractJsonRpcTest.testCases(TEST_CASE_PATH); + return testCases(TEST_CASE_PATH); } @AfterClass From c0af9619b21a20a69ca6678684ee090849d63df0 Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Thu, 25 Aug 2022 12:29:58 +1000 Subject: [PATCH 103/109] moved 4279 to 22.7.2 (#4309) Signed-off-by: Sally MacFarlane --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb95fabebf9..c1a5fac348a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Filter out disconnected peers when fetching available peers [#4269](https://github.com/hyperledger/besu/pull/4269) ### Bug Fixes +- Accept wit/80 from Nethermind [#4279](https://github.com/hyperledger/besu/pull/4279) ## 22.7.1 @@ -24,7 +25,6 @@ - Refactor and fix retrying get block switching peer [#4256](https://github.com/hyperledger/besu/pull/4256) - Fix encoding of key (short hex) in eth_getProof [#4261](https://github.com/hyperledger/besu/pull/4261) - Fix for post-merge networks fast-sync [#4224](https://github.com/hyperledger/besu/pull/4224), [#4276](https://github.com/hyperledger/besu/pull/4276) -- Accept wit/80 from Nethermind [#4279](https://github.com/hyperledger/besu/pull/4279) ### Download links - https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/22.7.1/besu-22.7.1.tar.gz / sha256: `7cca4c11e1d7525c172f2af9fbf456d134ada60e970d8b6abcfcd6c623b5dd36` From a44cb1cabc90d3c238f26b82893e0601ebee5250 Mon Sep 17 00:00:00 2001 From: matkt Date: Thu, 25 Aug 2022 13:14:17 +0200 Subject: [PATCH 104/109] Update fast-sync-min-peers default value for post merge (#4298) Signed-off-by: Karim TAAM --- CHANGELOG.md | 1 + .../org/hyperledger/besu/cli/BesuCommand.java | 20 ++++++- .../besu/cli/DefaultCommandValues.java | 1 + .../besu/cli/config/NetworkName.java | 12 ++++ .../hyperledger/besu/cli/BesuCommandTest.java | 60 +++++++++++++++++++ 5 files changed, 91 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1a5fac348a..ebf680a2201 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Upgrade besu-native to 0.6.0 and use Blake2bf native implementation if available by default [#4264](https://github.com/hyperledger/besu/pull/4264) - Better management of jemalloc presence/absence in startup script [#4237](https://github.com/hyperledger/besu/pull/4237) - Filter out disconnected peers when fetching available peers [#4269](https://github.com/hyperledger/besu/pull/4269) +- Updated the default value of fast-sync-min-peers post merge [#4298](https://github.com/hyperledger/besu/pull/4298) ### Bug Fixes - Accept wit/80 from Nethermind [#4279](https://github.com/hyperledger/besu/pull/4279) diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index e2b16d55bad..ae056f28365 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -20,6 +20,7 @@ import static java.util.Collections.singletonList; import static org.hyperledger.besu.cli.DefaultCommandValues.getDefaultBesuDataPath; import static org.hyperledger.besu.cli.config.NetworkName.MAINNET; +import static org.hyperledger.besu.cli.config.NetworkName.isMergedNetwork; import static org.hyperledger.besu.cli.util.CommandLineUtils.DEPENDENCY_WARNING_MSG; import static org.hyperledger.besu.cli.util.CommandLineUtils.DEPRECATED_AND_USELESS_WARNING_MSG; import static org.hyperledger.besu.cli.util.CommandLineUtils.DEPRECATION_WARNING_MSG; @@ -507,8 +508,12 @@ private InetAddress autoDiscoverDefaultIP() { names = {"--fast-sync-min-peers"}, paramLabel = MANDATORY_INTEGER_FORMAT_HELP, description = - "Minimum number of peers required before starting fast sync. (default: ${DEFAULT-VALUE})") - private final Integer fastSyncMinPeerCount = FAST_SYNC_MIN_PEER_COUNT; + "Minimum number of peers required before starting fast sync. (default pre-merge: " + + FAST_SYNC_MIN_PEER_COUNT + + " and post-merge: " + + FAST_SYNC_MIN_PEER_COUNT_POST_MERGE + + ")") + private final Integer fastSyncMinPeerCount = null; @Option( names = {"--network"}, @@ -2783,10 +2788,19 @@ private Optional maybePkiBlockCreationConfigurati } private SynchronizerConfiguration buildSyncConfig() { + Integer fastSyncMinPeers = fastSyncMinPeerCount; + if (fastSyncMinPeers == null) { + if (isMergedNetwork(network)) { + fastSyncMinPeers = FAST_SYNC_MIN_PEER_COUNT_POST_MERGE; + } else { + fastSyncMinPeers = FAST_SYNC_MIN_PEER_COUNT; + } + } + return unstableSynchronizerOptions .toDomainObject() .syncMode(syncMode) - .fastSyncMinimumPeerCount(fastSyncMinPeerCount) + .fastSyncMinimumPeerCount(fastSyncMinPeers) .build(); } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java b/besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java index 2ca3b5d7ab1..ef4fe428525 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java @@ -57,6 +57,7 @@ public interface DefaultCommandValues { NatMethod DEFAULT_NAT_METHOD = NatMethod.AUTO; JwtAlgorithm DEFAULT_JWT_ALGORITHM = JwtAlgorithm.RS256; int FAST_SYNC_MIN_PEER_COUNT = 5; + int FAST_SYNC_MIN_PEER_COUNT_POST_MERGE = 1; int DEFAULT_MAX_PEERS = 25; int DEFAULT_P2P_PEER_LOWER_BOUND = 25; int DEFAULT_HTTP_MAX_CONNECTIONS = 80; diff --git a/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java b/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java index 0592fcffc51..5505a0853fe 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java @@ -86,4 +86,16 @@ public boolean isDeprecated() { public Optional getDeprecationDate() { return Optional.ofNullable(deprecationDate); } + + public static boolean isMergedNetwork(final NetworkName networkName) { + switch (networkName) { + case GOERLI: + case ROPSTEN: + case SEPOLIA: + case KILN: + return true; + default: + return false; + } + } } diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index 9878140ccd4..d5eedd22b92 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -1706,6 +1706,42 @@ public void helpShouldDisplayFastSyncOptions() { assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); } + @Test + public void checkValidDefaultFastSyncMinPeersOption() { + parseCommand("--sync-mode", "FAST"); + verify(mockControllerBuilder).synchronizerConfiguration(syncConfigurationCaptor.capture()); + + final SynchronizerConfiguration syncConfig = syncConfigurationCaptor.getValue(); + assertThat(syncConfig.getSyncMode()).isEqualTo(SyncMode.FAST); + assertThat(syncConfig.getFastSyncMinimumPeerCount()).isEqualTo(5); + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + } + + @Test + public void checkValidDefaultFastSyncMinPeersPreMergeOption() { + parseCommand("--sync-mode", "FAST", "--network", "CLASSIC"); + verify(mockControllerBuilder).synchronizerConfiguration(syncConfigurationCaptor.capture()); + + final SynchronizerConfiguration syncConfig = syncConfigurationCaptor.getValue(); + assertThat(syncConfig.getSyncMode()).isEqualTo(SyncMode.FAST); + assertThat(syncConfig.getFastSyncMinimumPeerCount()).isEqualTo(5); + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + } + + @Test + public void checkValidDefaultFastSyncMinPeersPostMergeOption() { + parseCommand("--sync-mode", "FAST", "--network", "GOERLI"); + verify(mockControllerBuilder).synchronizerConfiguration(syncConfigurationCaptor.capture()); + + final SynchronizerConfiguration syncConfig = syncConfigurationCaptor.getValue(); + assertThat(syncConfig.getSyncMode()).isEqualTo(SyncMode.FAST); + assertThat(syncConfig.getFastSyncMinimumPeerCount()).isEqualTo(1); + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + } + @Test public void parsesValidFastSyncMinPeersOption() { parseCommand("--sync-mode", "FAST", "--fast-sync-min-peers", "11"); @@ -1718,6 +1754,30 @@ public void parsesValidFastSyncMinPeersOption() { assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); } + @Test + public void parsesValidFastSyncMinPeersOptionPreMerge() { + parseCommand("--sync-mode", "FAST", "--network", "CLASSIC", "--fast-sync-min-peers", "11"); + verify(mockControllerBuilder).synchronizerConfiguration(syncConfigurationCaptor.capture()); + + final SynchronizerConfiguration syncConfig = syncConfigurationCaptor.getValue(); + assertThat(syncConfig.getSyncMode()).isEqualTo(SyncMode.FAST); + assertThat(syncConfig.getFastSyncMinimumPeerCount()).isEqualTo(11); + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + } + + @Test + public void parsesValidFastSyncMinPeersOptionPostMerge() { + parseCommand("--sync-mode", "FAST", "--network", "GOERLI", "--fast-sync-min-peers", "11"); + verify(mockControllerBuilder).synchronizerConfiguration(syncConfigurationCaptor.capture()); + + final SynchronizerConfiguration syncConfig = syncConfigurationCaptor.getValue(); + assertThat(syncConfig.getSyncMode()).isEqualTo(SyncMode.FAST); + assertThat(syncConfig.getFastSyncMinimumPeerCount()).isEqualTo(11); + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + } + @Test public void parsesInvalidFastSyncMinPeersOptionWrongFormatShouldFail() { From d438b1a273401db27deb3a405e35fd96896e69cc Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Fri, 26 Aug 2022 08:18:12 +1000 Subject: [PATCH 105/109] update docker version on quorum ats executor (#4306) * docker version Signed-off-by: Sally MacFarlane Signed-off-by: Sally MacFarlane --- .circleci/config.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5b5923e2200..365e10b22f7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -41,7 +41,7 @@ executors: quorum_ats_executor: docker: - image: cimg/openjdk:11.0 - resource_class: large + resource_class: xlarge working_directory: ~/project environment: GRADLE_OPTS: -Dorg.gradle.daemon=false @@ -257,7 +257,9 @@ jobs: steps: - attach_workspace: at: ~/project - - setup_remote_docker + - setup_remote_docker: + version: 20.10.14 + docker_layer_caching: true - run: name: Quorum Acceptance Tests no_output_timeout: 30m From b25779149892733e4a943c95e1f06a5ce755d047 Mon Sep 17 00:00:00 2001 From: Jiri Peinlich Date: Fri, 26 Aug 2022 02:38:42 +0100 Subject: [PATCH 106/109] Reducing verbosity during BWS errors (#4311) Stacktrace can be retrieved by increasing the log level Signed-off-by: Jiri Peinlich Co-authored-by: Sally MacFarlane --- .../backwardsync/BackwardSyncContext.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java index 25a6a9582b9..78576b105d3 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContext.java @@ -202,24 +202,24 @@ protected void processException(final Throwable throwable) { backwardSyncException -> { if (backwardSyncException.shouldRestart()) { LOG.info( - "Backward sync failed ({}). Current Peers: {}. Retrying in " - + millisBetweenRetries - + " milliseconds...", - backwardSyncException.getMessage(), - ethContext.getEthPeers().peerCount()); - return; + "Backward sync failed ({}). Current Peers: {}. Retrying in {} milliseconds...", + throwable.getMessage(), + ethContext.getEthPeers().peerCount(), + millisBetweenRetries); } else { debugLambda( LOG, "Not recoverable backward sync exception {}", throwable::getMessage); throw backwardSyncException; } }, - () -> - LOG.warn( - "There was an uncaught exception during Backwards Sync. Retrying in " - + millisBetweenRetries - + " milliseconds...", - throwable)); + () -> { + LOG.warn( + "Backward sync failed ({}). Current Peers: {}. Retrying in {} milliseconds...", + throwable.getMessage(), + ethContext.getEthPeers().peerCount(), + millisBetweenRetries); + LOG.debug("Exception details:", throwable); + }); } private Optional extractBackwardSyncException(final Throwable throwable) { From c5ae9f5da9ae4a5a0cd96a70bcdd6bfc637b806c Mon Sep 17 00:00:00 2001 From: Pedro Novais Date: Fri, 26 Aug 2022 06:41:14 +0100 Subject: [PATCH 107/109] changes MergeCoordinator fields to protected to allow extension; (#4287) Signed-off-by: Pedro Novais Co-authored-by: Antony Denyer Co-authored-by: Sally MacFarlane --- .../merge/blockcreation/MergeCoordinator.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java index 9254ccf5c61..3cfb0366cb0 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java @@ -56,15 +56,16 @@ public class MergeCoordinator implements MergeMiningCoordinator, BadChainListener { private static final Logger LOG = LoggerFactory.getLogger(MergeCoordinator.class); - final AtomicLong targetGasLimit; - final MiningParameters miningParameters; - final MergeBlockCreatorFactory mergeBlockCreator; - final AtomicReference extraData = new AtomicReference<>(Bytes.fromHexString("0x")); - final AtomicReference latestDescendsFromTerminal = new AtomicReference<>(); - private final MergeContext mergeContext; - private final ProtocolContext protocolContext; - private final BackwardSyncContext backwardSyncContext; - private final ProtocolSchedule protocolSchedule; + protected final AtomicLong targetGasLimit; + protected final MiningParameters miningParameters; + protected final MergeBlockCreatorFactory mergeBlockCreator; + protected final AtomicReference extraData = + new AtomicReference<>(Bytes.fromHexString("0x")); + protected final AtomicReference latestDescendsFromTerminal = new AtomicReference<>(); + protected final MergeContext mergeContext; + protected final ProtocolContext protocolContext; + protected final BackwardSyncContext backwardSyncContext; + protected final ProtocolSchedule protocolSchedule; public MergeCoordinator( final ProtocolContext protocolContext, @@ -594,7 +595,7 @@ public void onBadChain( } @FunctionalInterface - interface MergeBlockCreatorFactory { + protected interface MergeBlockCreatorFactory { MergeBlockCreator forParams(BlockHeader header, Optional

feeRecipient); } From c321a85ef020fa9a4d4747b8035fe83fc4d4d7ce Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 26 Aug 2022 10:40:00 +0200 Subject: [PATCH 108/109] Log imported block info post merge (#4310) Removed ommers and added base fee. Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 1 + .../org/hyperledger/besu/datatypes/Wei.java | 49 +++++++++++++++++++ .../hyperledger/besu/datatypes/WeiTest.java | 47 ++++++++++++++++++ .../methods/engine/EngineNewPayload.java | 23 ++++++++- .../ExecutionEngineJsonRpcMethods.java | 10 +++- .../methods/JsonRpcMethodsFactory.java | 2 +- .../methods/engine/EngineNewPayloadTest.java | 6 ++- 7 files changed, 133 insertions(+), 5 deletions(-) create mode 100644 datatypes/src/test/java/org/hyperledger/besu/datatypes/WeiTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index ebf680a2201..9d1c453735a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Better management of jemalloc presence/absence in startup script [#4237](https://github.com/hyperledger/besu/pull/4237) - Filter out disconnected peers when fetching available peers [#4269](https://github.com/hyperledger/besu/pull/4269) - Updated the default value of fast-sync-min-peers post merge [#4298](https://github.com/hyperledger/besu/pull/4298) +- Log imported block info post merge [#4310](https://github.com/hyperledger/besu/pull/4310) ### Bug Fixes - Accept wit/80 from Nethermind [#4279](https://github.com/hyperledger/besu/pull/4279) diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Wei.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Wei.java index 5e23ff8d21a..aa19235fdee 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Wei.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Wei.java @@ -17,6 +17,7 @@ import org.hyperledger.besu.plugin.data.Quantity; import java.math.BigInteger; +import java.util.Arrays; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.BaseUInt256Value; @@ -98,4 +99,52 @@ public String toShortHexString() { public static Wei fromQuantity(final Quantity quantity) { return Wei.wrap((Bytes) quantity); } + + public String toHumanReadableString() { + final BigInteger amount = toBigInteger(); + final int numOfDigits = amount.toString().length(); + final Unit preferredUnit = Unit.getPreferred(numOfDigits); + final double res = amount.doubleValue() / preferredUnit.divisor; + return String.format("%1." + preferredUnit.decimals + "f %s", res, preferredUnit); + } + + enum Unit { + Wei(0, 0), + KWei(3), + MWei(6), + GWei(9), + Szabo(12), + Finney(15), + Ether(18), + KEther(21), + MEther(24), + GEther(27), + TEther(30); + + final int pow; + final double divisor; + final int decimals; + + Unit(final int pow) { + this(pow, 2); + } + + Unit(final int pow, final int decimals) { + this.pow = pow; + this.decimals = decimals; + this.divisor = Math.pow(10, pow); + } + + static Unit getPreferred(final int numOfDigits) { + return Arrays.stream(values()) + .filter(u -> numOfDigits <= u.pow + 3) + .findFirst() + .orElse(TEther); + } + + @Override + public String toString() { + return name().toLowerCase(); + } + } } diff --git a/datatypes/src/test/java/org/hyperledger/besu/datatypes/WeiTest.java b/datatypes/src/test/java/org/hyperledger/besu/datatypes/WeiTest.java new file mode 100644 index 00000000000..aa9a82b9110 --- /dev/null +++ b/datatypes/src/test/java/org/hyperledger/besu/datatypes/WeiTest.java @@ -0,0 +1,47 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.datatypes; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.math.BigInteger; +import java.util.Arrays; + +import org.junit.Test; + +public class WeiTest { + + @Test + public void toHumanReadableString() { + assertThat(Wei.ZERO.toHumanReadableString()).isEqualTo("0 wei"); + assertThat(Wei.ONE.toHumanReadableString()).isEqualTo("1 wei"); + + assertThat(Wei.of(999).toHumanReadableString()).isEqualTo("999 wei"); + assertThat(Wei.of(1000).toHumanReadableString()).isEqualTo("1.00 kwei"); + + assertThat(Wei.of(1009).toHumanReadableString()).isEqualTo("1.01 kwei"); + assertThat(Wei.of(1011).toHumanReadableString()).isEqualTo("1.01 kwei"); + + assertThat(Wei.of(new BigInteger("1000000000")).toHumanReadableString()).isEqualTo("1.00 gwei"); + + assertThat(Wei.of(new BigInteger("1000000000000000000")).toHumanReadableString()) + .isEqualTo("1.00 ether"); + + final char[] manyZeros = new char[32]; + Arrays.fill(manyZeros, '0'); + assertThat(Wei.of(new BigInteger("1" + String.valueOf(manyZeros))).toHumanReadableString()) + .isEqualTo("100.00 tether"); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java index 73c94f47796..ebd541a3991 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java @@ -25,6 +25,7 @@ import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.BlockValidator; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; @@ -41,6 +42,7 @@ import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; +import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.mainnet.BodyValidation; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; import org.hyperledger.besu.ethereum.rlp.RLPException; @@ -62,13 +64,16 @@ public class EngineNewPayload extends ExecutionEngineJsonRpcMethod { private static final Logger LOG = LoggerFactory.getLogger(EngineNewPayload.class); private static final BlockHeaderFunctions headerFunctions = new MainnetBlockHeaderFunctions(); private final MergeMiningCoordinator mergeCoordinator; + private final EthPeers ethPeers; public EngineNewPayload( final Vertx vertx, final ProtocolContext protocolContext, - final MergeMiningCoordinator mergeCoordinator) { + final MergeMiningCoordinator mergeCoordinator, + final EthPeers ethPeers) { super(vertx, protocolContext); this.mergeCoordinator = mergeCoordinator; + this.ethPeers = ethPeers; } @Override @@ -200,9 +205,11 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) } // execute block and return result response + final long startTimeMs = System.currentTimeMillis(); final BlockValidator.Result executionResult = mergeCoordinator.rememberBlock(block); if (executionResult.errorMessage.isEmpty()) { + logImportedBlockInfo(block, (System.currentTimeMillis() - startTimeMs) / 1000.0); return respondWith(reqId, blockParam, newBlockHeader.getHash(), VALID); } else { LOG.debug("New payload is invalid: {}", executionResult.errorMessage.get()); @@ -252,4 +259,18 @@ JsonRpcResponse respondWithInvalid( requestId, new EnginePayloadStatusResult(INVALID, latestValidHash, Optional.of(validationError))); } + + private void logImportedBlockInfo(final Block block, final double timeInS) { + LOG.info( + String.format( + "Imported #%,d / %d tx / base fee %s / %,d (%01.1f%%) gas / (%s) in %01.3fs. Peers: %d", + block.getHeader().getNumber(), + block.getBody().getTransactions().size(), + block.getHeader().getBaseFee().map(Wei::toHumanReadableString).orElse("N/A"), + block.getHeader().getGasUsed(), + (block.getHeader().getGasUsed() * 100.0) / block.getHeader().getGasLimit(), + block.getHash().toHexString(), + timeInS, + ethPeers.peerCount())); + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java index 8c81681974e..7336f461ac6 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java @@ -24,6 +24,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineNewPayload; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; +import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import java.util.Map; import java.util.Optional; @@ -38,14 +39,19 @@ public class ExecutionEngineJsonRpcMethods extends ApiGroupJsonRpcMethods { private final Optional mergeCoordinator; private final ProtocolContext protocolContext; + private final EthPeers ethPeers; + ExecutionEngineJsonRpcMethods( - final MiningCoordinator miningCoordinator, final ProtocolContext protocolContext) { + final MiningCoordinator miningCoordinator, + final ProtocolContext protocolContext, + final EthPeers ethPeers) { this.mergeCoordinator = Optional.ofNullable(miningCoordinator) .filter(mc -> mc.isCompatibleWithEngineApi()) .map(MergeMiningCoordinator.class::cast); this.protocolContext = protocolContext; + this.ethPeers = ethPeers; } @Override @@ -59,7 +65,7 @@ protected Map create() { if (mergeCoordinator.isPresent()) { return mapOf( new EngineGetPayload(syncVertx, protocolContext, blockResultFactory), - new EngineNewPayload(syncVertx, protocolContext, mergeCoordinator.get()), + new EngineNewPayload(syncVertx, protocolContext, mergeCoordinator.get(), ethPeers), new EngineForkchoiceUpdated(syncVertx, protocolContext, mergeCoordinator.get()), new EngineExchangeTransitionConfiguration(syncVertx, protocolContext)); } else { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java index 59bf78ee886..bf63527949a 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java @@ -94,7 +94,7 @@ public Map methods( blockchainQueries, protocolSchedule, metricsSystem, transactionPool, dataDir), new EeaJsonRpcMethods( blockchainQueries, protocolSchedule, transactionPool, privacyParameters), - new ExecutionEngineJsonRpcMethods(miningCoordinator, protocolContext), + new ExecutionEngineJsonRpcMethods(miningCoordinator, protocolContext, ethPeers), new GoQuorumJsonRpcPrivacyMethods( blockchainQueries, protocolSchedule, transactionPool, privacyParameters), new EthJsonRpcMethods( diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java index 74d48c62d29..ce7759feae6 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadTest.java @@ -48,6 +48,7 @@ import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; +import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import java.util.Collections; import java.util.List; @@ -77,11 +78,14 @@ public class EngineNewPayloadTest { @Mock private MutableBlockchain blockchain; + @Mock private EthPeers ethPeers; + @Before public void before() { when(protocolContext.safeConsensusContext(Mockito.any())).thenReturn(Optional.of(mergeContext)); when(protocolContext.getBlockchain()).thenReturn(blockchain); - this.method = new EngineNewPayload(vertx, protocolContext, mergeCoordinator); + when(ethPeers.peerCount()).thenReturn(1); + this.method = new EngineNewPayload(vertx, protocolContext, mergeCoordinator, ethPeers); } @Test From af65c86e64a56fe043e2fe90d97dc9ec0bbec9ad Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 26 Aug 2022 11:14:29 +0200 Subject: [PATCH 109/109] Retry mechanism when getting a broadcasted block fail on all peers (#4271) Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 1 + .../task/AbstractRetryingPeerTask.java | 4 +- .../eth/sync/BlockPropagationManager.java | 240 +++++++++++++++--- .../eth/sync/SynchronizerConfiguration.java | 23 +- .../AbstractBlockPropagationManagerTest.java | 15 +- 5 files changed, 235 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d1c453735a..47d304928f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Additions and Improvements - Upgrade besu-native to 0.6.0 and use Blake2bf native implementation if available by default [#4264](https://github.com/hyperledger/besu/pull/4264) - Better management of jemalloc presence/absence in startup script [#4237](https://github.com/hyperledger/besu/pull/4237) +- Retry mechanism when getting a broadcasted block fail on all peers [#4271](https://github.com/hyperledger/besu/pull/4271) - Filter out disconnected peers when fetching available peers [#4269](https://github.com/hyperledger/besu/pull/4269) - Updated the default value of fast-sync-min-peers post merge [#4298](https://github.com/hyperledger/besu/pull/4298) - Log imported block info post merge [#4310](https://github.com/hyperledger/besu/pull/4310) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTask.java index 30033200355..cf48d69847d 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/task/AbstractRetryingPeerTask.java @@ -114,9 +114,9 @@ protected void handleTaskError(final Throwable error) { if (cause instanceof NoAvailablePeersException) { LOG.debug( - "No useful peer found, checking remaining current peers for usefulness: {}", + "No useful peer found, wait max 5 seconds for new peer to connect: current peers {}", ethContext.getEthPeers().peerCount()); - // Wait for new peer to connect + final WaitForPeerTask waitTask = WaitForPeerTask.create(ethContext, metricsSystem); executeSubTask( () -> diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java index aa72844f6d4..20355f474d4 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java @@ -14,6 +14,8 @@ */ package org.hyperledger.besu.ethereum.eth.sync; +import static org.hyperledger.besu.util.FutureUtils.exceptionallyCompose; +import static org.hyperledger.besu.util.Slf4jLambdaHelper.debugLambda; import static org.hyperledger.besu.util.Slf4jLambdaHelper.traceLambda; import org.hyperledger.besu.consensus.merge.ForkchoiceMessageListener; @@ -23,6 +25,7 @@ import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; import org.hyperledger.besu.ethereum.chain.BlockAddedEvent.EventType; import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Difficulty; @@ -46,6 +49,7 @@ import org.hyperledger.besu.ethereum.rlp.RLPException; import org.hyperledger.besu.plugin.services.MetricsSystem; +import java.time.Duration; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -53,8 +57,10 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -76,12 +82,9 @@ public class BlockPropagationManager implements ForkchoiceMessageListener { private final BlockBroadcaster blockBroadcaster; private final AtomicBoolean started = new AtomicBoolean(false); - - private final Set importingBlocks = Collections.newSetFromMap(new ConcurrentHashMap<>()); - private final Set requestedBlocks = Collections.newSetFromMap(new ConcurrentHashMap<>()); - private final Set requestedNonAnnouncedBlocks = - Collections.newSetFromMap(new ConcurrentHashMap<>()); + private final ProcessingBlocksManager processingBlocksManager; private final PendingBlocksManager pendingBlocksManager; + private final Duration getBlockTimeoutMillis; private Optional onBlockAddedSId = Optional.empty(); private Optional newBlockSId; private Optional newBlockHashesSId; @@ -95,6 +98,28 @@ public class BlockPropagationManager implements ForkchoiceMessageListener { final PendingBlocksManager pendingBlocksManager, final MetricsSystem metricsSystem, final BlockBroadcaster blockBroadcaster) { + this( + config, + protocolSchedule, + protocolContext, + ethContext, + syncState, + pendingBlocksManager, + metricsSystem, + blockBroadcaster, + new ProcessingBlocksManager()); + } + + BlockPropagationManager( + final SynchronizerConfiguration config, + final ProtocolSchedule protocolSchedule, + final ProtocolContext protocolContext, + final EthContext ethContext, + final SyncState syncState, + final PendingBlocksManager pendingBlocksManager, + final MetricsSystem metricsSystem, + final BlockBroadcaster blockBroadcaster, + final ProcessingBlocksManager processingBlocksManager) { this.config = config; this.protocolSchedule = protocolSchedule; this.protocolContext = protocolContext; @@ -104,6 +129,9 @@ public class BlockPropagationManager implements ForkchoiceMessageListener { this.syncState = syncState; this.pendingBlocksManager = pendingBlocksManager; this.syncState.subscribeTTDReached(this::reactToTTDReachedEvent); + this.getBlockTimeoutMillis = + Duration.ofMillis(config.getPropagationManagerGetBlockTimeoutMillis()); + this.processingBlocksManager = processingBlocksManager; } public void start() { @@ -156,6 +184,7 @@ private void clearListeners() { private void onBlockAdded(final BlockAddedEvent blockAddedEvent) { // Check to see if any of our pending blocks are now ready for import final Block newBlock = blockAddedEvent.getBlock(); + traceLambda( LOG, "Block added event type {} for block {}. Current status {}", @@ -247,7 +276,7 @@ private void maybeProcessNonAnnouncedBlocks(final Block newBlock) { if (distance < config.getBlockPropagationRange().upperEndpoint() && minAnnouncedBlockNumber > firstNonAnnouncedBlockNumber) { - if (requestedNonAnnouncedBlocks.add(firstNonAnnouncedBlockNumber)) { + if (processingBlocksManager.addNonAnnouncedBlocks(firstNonAnnouncedBlockNumber)) { retrieveNonAnnouncedBlock(firstNonAnnouncedBlockNumber); } } @@ -338,7 +367,7 @@ private void handleNewBlockHashesFromNetwork(final EthMessage message) { LOG.trace("New block hash from network {} is already pending", announcedBlock); continue; } - if (importingBlocks.contains(announcedBlock.hash())) { + if (processingBlocksManager.alreadyImporting(announcedBlock.hash())) { LOG.trace("New block hash from network {} is already importing", announcedBlock); continue; } @@ -346,7 +375,7 @@ private void handleNewBlockHashesFromNetwork(final EthMessage message) { LOG.trace("New block hash from network {} was already imported", announcedBlock); continue; } - if (requestedBlocks.add(announcedBlock.hash())) { + if (processingBlocksManager.addRequestedBlock(announcedBlock.hash())) { newBlocks.add(announcedBlock); } else { LOG.trace("New block hash from network {} was already requested", announcedBlock); @@ -379,7 +408,7 @@ private CompletableFuture processAnnouncedBlock( private void requestParentBlock(final Block block) { final BlockHeader blockHeader = block.getHeader(); - if (requestedBlocks.add(blockHeader.getParentHash())) { + if (processingBlocksManager.addRequestedBlock(blockHeader.getParentHash())) { retrieveParentBlock(blockHeader); } else { LOG.debug("Parent block with hash {} is already requested", blockHeader.getParentHash()); @@ -397,34 +426,115 @@ private CompletableFuture retrieveParentBlock(final BlockHeader blockHead private CompletableFuture getBlockFromPeers( final Optional preferredPeer, final long blockNumber, - final Optional blockHash) { + final Optional maybeBlockHash) { + return repeatableGetBlockFromPeer(preferredPeer, blockNumber, maybeBlockHash) + .whenComplete( + (block, throwable) -> { + if (block != null) { + debugLambda(LOG, "Successfully retrieved block {}", block::toLogString); + processingBlocksManager.registerReceivedBlock(block); + } else { + if (throwable != null) { + LOG.warn( + "Failed to retrieve block " + + logBlockNumberMaybeHash(blockNumber, maybeBlockHash), + throwable); + } else { + // this could happen if we give up at some point since we find that it make no + // sense to retry + debugLambda( + LOG, + "Block {} not retrieved", + () -> logBlockNumberMaybeHash(blockNumber, maybeBlockHash)); + } + processingBlocksManager.registerFailedGetBlock(blockNumber, maybeBlockHash); + } + }); + } + + private CompletableFuture repeatableGetBlockFromPeer( + final Optional preferredPeer, + final long blockNumber, + final Optional maybeBlockHash) { + return exceptionallyCompose( + scheduleGetBlockFromPeers(preferredPeer, blockNumber, maybeBlockHash), + handleGetBlockErrors(blockNumber, maybeBlockHash)) + .thenCompose(r -> maybeRepeatGetBlock(blockNumber, maybeBlockHash)); + } + + private Function> handleGetBlockErrors( + final long blockNumber, final Optional maybeBlockHash) { + return throwable -> { + debugLambda( + LOG, + "Temporary failure retrieving block {} from peers with error {}", + () -> logBlockNumberMaybeHash(blockNumber, maybeBlockHash), + throwable::toString); + return CompletableFuture.completedFuture(null); + }; + } + + private CompletableFuture maybeRepeatGetBlock( + final long blockNumber, final Optional maybeBlockHash) { + final MutableBlockchain blockchain = protocolContext.getBlockchain(); + final Optional maybeBlock = + maybeBlockHash + .map(hash -> blockchain.getBlockByHash(hash)) + .orElseGet(() -> blockchain.getBlockByNumber(blockNumber)); + + // check if we got this block by other means + if (maybeBlock.isPresent()) { + final Block block = maybeBlock.get(); + debugLambda( + LOG, "No need to retry to get block {} since it is already present", block::toLogString); + return CompletableFuture.completedFuture(block); + } + + final long localChainHeight = blockchain.getChainHeadBlockNumber(); + final long bestChainHeight = syncState.bestChainHeight(localChainHeight); + if (!shouldImportBlockAtHeight(blockNumber, localChainHeight, bestChainHeight)) { + debugLambda( + LOG, + "Not retrying to get block {} since we are too far from local chain head {}", + () -> logBlockNumberMaybeHash(blockNumber, maybeBlockHash), + blockchain.getChainHead()::toLogString); + return CompletableFuture.completedFuture(null); + } + + debugLambda( + LOG, + "Retrying to get block {}", + () -> logBlockNumberMaybeHash(blockNumber, maybeBlockHash)); + + return ethContext + .getScheduler() + .scheduleSyncWorkerTask( + () -> repeatableGetBlockFromPeer(Optional.empty(), blockNumber, maybeBlockHash)); + } + + private CompletableFuture scheduleGetBlockFromPeers( + final Optional maybePreferredPeer, + final long blockNumber, + final Optional maybeBlockHash) { final RetryingGetBlockFromPeersTask getBlockTask = RetryingGetBlockFromPeersTask.create( protocolSchedule, ethContext, metricsSystem, - ethContext.getEthPeers().getMaxPeers(), - blockHash, + Math.max(1, ethContext.getEthPeers().peerCount()), + maybeBlockHash, blockNumber); - preferredPeer.ifPresent(getBlockTask::assignPeer); + maybePreferredPeer.ifPresent(getBlockTask::assignPeer); - return ethContext - .getScheduler() - .scheduleSyncWorkerTask(getBlockTask::run) - .thenCompose(r -> importOrSavePendingBlock(r.getResult(), r.getPeer().nodeId())) - .whenComplete( - (r, t) -> { - requestedNonAnnouncedBlocks.remove(blockNumber); - blockHash.ifPresentOrElse( - requestedBlocks::remove, - () -> { - if (r != null) { - // in case we successfully retrieved only by block number, when can remove - // the request by hash too - requestedBlocks.remove(r.getHash()); - } - }); - }); + var future = + ethContext + .getScheduler() + .scheduleSyncWorkerTask(getBlockTask::run) + .thenCompose(r -> importOrSavePendingBlock(r.getResult(), r.getPeer().nodeId())); + + ethContext.getScheduler().failAfterTimeout(future, getBlockTimeoutMillis); + + return future; } private void broadcastBlock(final Block block, final BlockHeader parent) { @@ -453,14 +563,14 @@ CompletableFuture importOrSavePendingBlock(final Block block, final Bytes return CompletableFuture.completedFuture(block); } - if (!importingBlocks.add(block.getHash())) { + if (!processingBlocksManager.addImportingBlock(block.getHash())) { traceLambda(LOG, "We're already importing this block {}", block::toLogString); return CompletableFuture.completedFuture(block); } if (protocolContext.getBlockchain().contains(block.getHash())) { traceLambda(LOG, "We've already imported this block {}", block::toLogString); - importingBlocks.remove(block.getHash()); + processingBlocksManager.registerBlockImportDone(block.getHash()); return CompletableFuture.completedFuture(block); } @@ -537,7 +647,7 @@ private CompletableFuture validateAndProcessPendingBlock( ethContext.getScheduler().scheduleSyncWorkerTask(() -> broadcastBlock(block, parent)); return runImportTask(block); } else { - importingBlocks.remove(block.getHash()); + processingBlocksManager.registerBlockImportDone(block.getHash()); badBlockManager.addBadBlock(block); LOG.warn("Failed to import announced block {}", block.toLogString()); return CompletableFuture.completedFuture(block); @@ -557,7 +667,7 @@ private CompletableFuture runImportTask(final Block block) { .run() .whenComplete( (result, throwable) -> { - importingBlocks.remove(block.getHash()); + processingBlocksManager.registerBlockImportDone(block.getHash()); if (throwable != null) { LOG.warn("Failed to import announced block {}", block.toLogString()); } @@ -591,17 +701,17 @@ private void reactToTTDReachedEvent(final boolean ttdReached) { @Override public String toString() { return "BlockPropagationManager{" - + "requestedBlocks=" - + requestedBlocks - + ", requestedNonAnnounceBlocks=" - + requestedNonAnnouncedBlocks - + ", importingBlocks=" - + importingBlocks + + processingBlocksManager + ", pendingBlocksManager=" + pendingBlocksManager + '}'; } + private String logBlockNumberMaybeHash( + final long blockNumber, final Optional maybeBlockHash) { + return blockNumber + maybeBlockHash.map(h -> " (" + h + ")").orElse(""); + } + @Override public void onNewForkchoiceMessage( final Hash headBlockHash, @@ -611,4 +721,54 @@ public void onNewForkchoiceMessage( stop(); } } + + static class ProcessingBlocksManager { + private final Set importingBlocks = Collections.newSetFromMap(new ConcurrentHashMap<>()); + private final Set requestedBlocks = Collections.newSetFromMap(new ConcurrentHashMap<>()); + private final Set requestedNonAnnouncedBlocks = + Collections.newSetFromMap(new ConcurrentHashMap<>()); + + boolean addRequestedBlock(final Hash hash) { + return requestedBlocks.add(hash); + } + + public boolean addNonAnnouncedBlocks(final long blockNumber) { + return requestedNonAnnouncedBlocks.add(blockNumber); + } + + public boolean alreadyImporting(final Hash hash) { + return importingBlocks.contains(hash); + } + + public synchronized void registerReceivedBlock(final Block block) { + requestedBlocks.remove(block.getHash()); + requestedNonAnnouncedBlocks.remove(block.getHeader().getNumber()); + } + + public synchronized void registerFailedGetBlock( + final long blockNumber, final Optional maybeBlockHash) { + requestedNonAnnouncedBlocks.remove(blockNumber); + maybeBlockHash.ifPresent(requestedBlocks::remove); + } + + public boolean addImportingBlock(final Hash hash) { + return importingBlocks.add(hash); + } + + public void registerBlockImportDone(final Hash hash) { + importingBlocks.remove(hash); + } + + @Override + public synchronized String toString() { + return "ProcessingBlocksManager{" + + "importingBlocks=" + + importingBlocks + + ", requestedBlocks=" + + requestedBlocks + + ", requestedNonAnnouncedBlocks=" + + requestedNonAnnouncedBlocks + + '}'; + } + } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/SynchronizerConfiguration.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/SynchronizerConfiguration.java index e18590a774c..4077ec5f6f9 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/SynchronizerConfiguration.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/SynchronizerConfiguration.java @@ -47,6 +47,8 @@ public class SynchronizerConfiguration { public static final int DEFAULT_COMPUTATION_PARALLELISM = 2; public static final int DEFAULT_WORLD_STATE_TASK_CACHE_SIZE = CachingTaskCollection.DEFAULT_CACHE_SIZE; + public static final long DEFAULT_PROPAGATION_MANAGER_GET_BLOCK_TIMEOUT_MILLIS = + TimeUnit.SECONDS.toMillis(60); // Fast sync config private final int fastSyncPivotDistance; @@ -77,6 +79,7 @@ public class SynchronizerConfiguration { private final int computationParallelism; private final int maxTrailingPeers; private final long worldStateMinMillisBeforeStalling; + private final long propagationManagerGetBlockTimeoutMillis; private SynchronizerConfiguration( final int fastSyncPivotDistance, @@ -98,7 +101,8 @@ private SynchronizerConfiguration( final int downloaderParallelism, final int transactionsParallelism, final int computationParallelism, - final int maxTrailingPeers) { + final int maxTrailingPeers, + final long propagationManagerGetBlockTimeoutMillis) { this.fastSyncPivotDistance = fastSyncPivotDistance; this.fastSyncFullValidationRate = fastSyncFullValidationRate; this.fastSyncMinimumPeerCount = fastSyncMinimumPeerCount; @@ -119,6 +123,7 @@ private SynchronizerConfiguration( this.transactionsParallelism = transactionsParallelism; this.computationParallelism = computationParallelism; this.maxTrailingPeers = maxTrailingPeers; + this.propagationManagerGetBlockTimeoutMillis = propagationManagerGetBlockTimeoutMillis; } public static Builder builder() { @@ -234,6 +239,10 @@ public int getMaxTrailingPeers() { return maxTrailingPeers; } + public long getPropagationManagerGetBlockTimeoutMillis() { + return propagationManagerGetBlockTimeoutMillis; + } + public static class Builder { private SyncMode syncMode = SyncMode.FULL; private int fastSyncMinimumPeerCount = DEFAULT_FAST_SYNC_MINIMUM_PEERS; @@ -260,6 +269,9 @@ public static class Builder { private long worldStateMinMillisBeforeStalling = DEFAULT_WORLD_STATE_MIN_MILLIS_BEFORE_STALLING; private int worldStateTaskCacheSize = DEFAULT_WORLD_STATE_TASK_CACHE_SIZE; + private long propagationManagerGetBlockTimeoutMillis = + DEFAULT_PROPAGATION_MANAGER_GET_BLOCK_TIMEOUT_MILLIS; + public Builder fastSyncPivotDistance(final int distance) { fastSyncPivotDistance = distance; return this; @@ -371,6 +383,12 @@ public Builder maxTrailingPeers(final int maxTailingPeers) { return this; } + public Builder propagationManagerGetBlockTimeoutMillis( + final long propagationManagerGetBlockTimeoutMillis) { + this.propagationManagerGetBlockTimeoutMillis = propagationManagerGetBlockTimeoutMillis; + return this; + } + public SynchronizerConfiguration build() { return new SynchronizerConfiguration( fastSyncPivotDistance, @@ -392,7 +410,8 @@ public SynchronizerConfiguration build() { downloaderParallelism, transactionsParallelism, computationParallelism, - maxTrailingPeers); + maxTrailingPeers, + propagationManagerGetBlockTimeoutMillis); } } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java index 3f15a68cd99..39666aebb54 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/AbstractBlockPropagationManagerTest.java @@ -50,6 +50,7 @@ import org.hyperledger.besu.ethereum.eth.messages.EthPV62; import org.hyperledger.besu.ethereum.eth.messages.NewBlockHashesMessage; import org.hyperledger.besu.ethereum.eth.messages.NewBlockMessage; +import org.hyperledger.besu.ethereum.eth.sync.BlockPropagationManager.ProcessingBlocksManager; import org.hyperledger.besu.ethereum.eth.sync.state.PendingBlocksManager; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; @@ -87,6 +88,8 @@ public abstract class AbstractBlockPropagationManagerTest { spy( new PendingBlocksManager( SynchronizerConfiguration.builder().blockPropagationRange(-10, 30).build())); + protected final ProcessingBlocksManager processingBlocksManager = + spy(new ProcessingBlocksManager()); protected SyncState syncState; protected final MetricsSystem metricsSystem = new NoOpMetricsSystem(); private final Hash finalizedHash = Hash.fromHexStringLenient("0x1337"); @@ -119,7 +122,8 @@ protected void setup(final DataStorageFormat dataStorageFormat) { syncState, pendingBlocksManager, metricsSystem, - blockBroadcaster); + blockBroadcaster, + processingBlocksManager); } @Test @@ -933,7 +937,7 @@ public void shouldNotListenToBlockAddedEventsWhenTTDReachedAndFinal() { } @Test - public void shouldRequestBlockAgainIfFirstGetBlockFails() { + public void shouldRequestBlockFromOtherPeersIfFirstPeerFails() { blockchainUtil.importFirstBlocks(2); final Block nextBlock = blockchainUtil.getBlock(2); @@ -956,15 +960,18 @@ public void shouldRequestBlockAgainIfFirstGetBlockFails() { assertThat(blockchain.contains(nextBlock.getHash())).isFalse(); - // Re-broadcast the previous message and peer responds + // second peer responds final RespondingEthPeer secondPeer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 0); - EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, secondPeer, nextAnnouncement); final Responder goodResponder = RespondingEthPeer.blockchainResponder(getFullBlockchain()); secondPeer.respondWhile(goodResponder, secondPeer::hasOutstandingRequests); assertThat(blockchain.contains(nextBlock.getHash())).isTrue(); + verify(processingBlocksManager).addRequestedBlock(nextBlock.getHash()); + verify(processingBlocksManager).addImportingBlock(nextBlock.getHash()); + verify(processingBlocksManager).registerReceivedBlock(nextBlock); + verify(processingBlocksManager).registerBlockImportDone(nextBlock.getHash()); } public abstract Blockchain getFullBlockchain();