mirror of https://github.com/hyperledger/besu
Fix EIP-2124 Fork identifier for chain compatibility checks. (#1050)
Before this pull request Besu was using the latest known fork id to create status message for Ethereum P2P protocol handshake. This latest known fork id was created based on a list of forks retrieved from the Genesis. For private networks it is possible that all fork blocks number are set to 0. The algorithm to compute the valid fork hashes excludes 0 values. As a result, the list was empty and the `getLatestForkId` was returning `null`. This is an issue when you support capabilities >= to Eth/64 sub protocol because other peers expect the fork id value in the `RLP` encoded message. Moreover, the algorithm to compute the fork id should be aware of the chain head number and update `CRC` value only for fork blocks below the current head. This pull request fixes this issue by fetching the chain head number and update accordingly the `CRC` value. Unit tests have been extended to cover an exhaustive list of possible combinations on named networks (`goerli`, `rinkeby`, `ropsten` and `mainnet`). Signed-off-by: Abdelhamid Bakhta <abdelhamid.bakhta@consensys.net>pull/1067/head
parent
9f2f3b9fb5
commit
8589177e49
@ -0,0 +1,96 @@ |
||||
/* |
||||
* 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.besu.ethereum.eth.manager; |
||||
|
||||
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; |
||||
import org.hyperledger.besu.ethereum.rlp.RLPInput; |
||||
import org.hyperledger.besu.ethereum.rlp.RLPOutput; |
||||
import org.hyperledger.besu.util.EndianUtils; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes; |
||||
|
||||
public class ForkId { |
||||
final Bytes hash; |
||||
final Bytes next; |
||||
Bytes forkIdRLP; |
||||
|
||||
protected ForkId(final Bytes hash, final Bytes next) { |
||||
this.hash = hash; |
||||
this.next = next; |
||||
createForkIdRLP(); |
||||
} |
||||
|
||||
public ForkId(final Bytes hash, final long next) { |
||||
this(hash, Bytes.wrap(EndianUtils.longToBigEndian(next)).trimLeadingZeros()); |
||||
} |
||||
|
||||
public long getNext() { |
||||
return next.toLong(); |
||||
} |
||||
|
||||
public Bytes getHash() { |
||||
return hash; |
||||
} |
||||
|
||||
void createForkIdRLP() { |
||||
final BytesValueRLPOutput out = new BytesValueRLPOutput(); |
||||
writeTo(out); |
||||
forkIdRLP = out.encoded(); |
||||
} |
||||
|
||||
public void writeTo(final RLPOutput out) { |
||||
out.startList(); |
||||
out.writeBytes(hash); |
||||
out.writeBytes(next); |
||||
out.endList(); |
||||
} |
||||
|
||||
public static ForkId readFrom(final RLPInput in) { |
||||
in.enterList(); |
||||
final Bytes hash = in.readBytes(); |
||||
final long next = in.readLongScalar(); |
||||
in.leaveList(); |
||||
return new ForkId(hash, next); |
||||
} |
||||
|
||||
public List<ForkId> asList() { |
||||
final ArrayList<ForkId> forRLP = new ArrayList<>(); |
||||
forRLP.add(this); |
||||
return forRLP; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return "ForkId(hash=" + this.hash + ", next=" + next.toLong() + ")"; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(final Object obj) { |
||||
if (obj instanceof ForkId) { |
||||
final ForkId other = (ForkId) obj; |
||||
final long thisNext = next.toLong(); |
||||
return other.getHash().equals(this.hash) && thisNext == other.getNext(); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return super.hashCode(); |
||||
} |
||||
} |
@ -0,0 +1,735 @@ |
||||
/* |
||||
* 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.besu.ethereum.eth.manager; |
||||
|
||||
import static com.google.common.primitives.Longs.asList; |
||||
import static java.util.Optional.empty; |
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.mockito.Mockito.mock; |
||||
import static org.mockito.Mockito.when; |
||||
|
||||
import org.hyperledger.besu.ethereum.chain.Blockchain; |
||||
import org.hyperledger.besu.ethereum.core.Block; |
||||
import org.hyperledger.besu.ethereum.core.BlockHeader; |
||||
import org.hyperledger.besu.ethereum.core.Hash; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.Collection; |
||||
import java.util.List; |
||||
import java.util.Optional; |
||||
|
||||
import org.apache.logging.log4j.LogManager; |
||||
import org.apache.logging.log4j.Logger; |
||||
import org.apache.tuweni.bytes.Bytes; |
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
import org.junit.runners.Parameterized; |
||||
import org.junit.runners.Parameterized.Parameters; |
||||
|
||||
@RunWith(Parameterized.class) |
||||
public class EIP2124Test { |
||||
private static final Logger LOG = LogManager.getLogger(); |
||||
|
||||
@Parameters(name = "{index}: {0}") |
||||
public static Collection<Object[]> data() { |
||||
return Arrays.asList( |
||||
new Object[][] { |
||||
// Mainnet test cases
|
||||
{ |
||||
"Mainnet // Unsynced", |
||||
Network.MAINNET, |
||||
0L, |
||||
wantForkId("0xfc64ec04", 1150000L), |
||||
Optional.of(ForkIds.MAINNET), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Mainnet // First Homestead block", |
||||
Network.MAINNET, |
||||
1150000L, |
||||
wantForkId("0x97c2c34c", 1920000L), |
||||
Optional.of(ForkIds.MAINNET), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Mainnet // Last Homestead block", |
||||
Network.MAINNET, |
||||
1919999L, |
||||
wantForkId("0x97c2c34c", 1920000L), |
||||
Optional.of(ForkIds.MAINNET), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Mainnet // First DAO block", |
||||
Network.MAINNET, |
||||
1920000L, |
||||
wantForkId("0x91d1f948", 2463000L), |
||||
Optional.of(ForkIds.MAINNET), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Mainnet // Last DAO block", |
||||
Network.MAINNET, |
||||
2462999L, |
||||
wantForkId("0x91d1f948", 2463000L), |
||||
Optional.of(ForkIds.MAINNET), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Mainnet // First Tangerine block", |
||||
Network.MAINNET, |
||||
2463000L, |
||||
wantForkId("0x7a64da13", 2675000L), |
||||
Optional.of(ForkIds.MAINNET), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Mainnet // Last Tangerine block", |
||||
Network.MAINNET, |
||||
2674999L, |
||||
wantForkId("0x7a64da13", 2675000L), |
||||
Optional.of(ForkIds.MAINNET), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Mainnet // First Spurious block", |
||||
Network.MAINNET, |
||||
2675000L, |
||||
wantForkId("0x3edd5b10", 4370000L), |
||||
Optional.of(ForkIds.MAINNET), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Mainnet // Last Spurious block", |
||||
Network.MAINNET, |
||||
4369999L, |
||||
wantForkId("0x3edd5b10", 4370000L), |
||||
Optional.of(ForkIds.MAINNET), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Mainnet // First Byzantium block", |
||||
Network.MAINNET, |
||||
4370000L, |
||||
wantForkId("0xa00bc324", 7280000L), |
||||
Optional.of(ForkIds.MAINNET), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Mainnet // Last Byzantium block", |
||||
Network.MAINNET, |
||||
7279999L, |
||||
wantForkId("0xa00bc324", 7280000L), |
||||
Optional.of(ForkIds.MAINNET), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Mainnet // First and last Constantinople, first Petersburg block", |
||||
Network.MAINNET, |
||||
7280000L, |
||||
wantForkId("0x668db0af", 9069000L), |
||||
Optional.of(ForkIds.MAINNET), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Mainnet // Last Petersburg block", |
||||
Network.MAINNET, |
||||
9068999L, |
||||
wantForkId("0x668db0af", 9069000L), |
||||
Optional.of(ForkIds.MAINNET), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Mainnet // First Istanbul and first Muir Glacier block", |
||||
Network.MAINNET, |
||||
9069000L, |
||||
wantForkId("0x879d6e30", 9200000L), |
||||
Optional.of(ForkIds.MAINNET), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Mainnet // Last Istanbul and first Muir Glacier block", |
||||
Network.MAINNET, |
||||
9199999L, |
||||
wantForkId("0x879d6e30", 9200000L), |
||||
Optional.of(ForkIds.MAINNET), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Mainnet // First Muir Glacier block", |
||||
Network.MAINNET, |
||||
9200000L, |
||||
wantForkId("0xe029e991", 0L), |
||||
Optional.of(ForkIds.MAINNET), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Mainnet // Future Muir Glacier block", |
||||
Network.MAINNET, |
||||
10000000L, |
||||
wantForkId("0xe029e991", 0L), |
||||
Optional.of(ForkIds.MAINNET), |
||||
empty() |
||||
}, |
||||
// Ropsten test cases
|
||||
{ |
||||
"Ropsten // Unsynced, last Frontier, Homestead and first Tangerine block", |
||||
Network.ROPSTEN, |
||||
0L, |
||||
wantForkId("0x30c7ddbc", 10L), |
||||
Optional.of(ForkIds.ROPSTEN), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Ropsten // Last Tangerine block", |
||||
Network.ROPSTEN, |
||||
9L, |
||||
wantForkId("0x30c7ddbc", 10L), |
||||
Optional.of(ForkIds.ROPSTEN), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Ropsten // First Spurious block", |
||||
Network.ROPSTEN, |
||||
10L, |
||||
wantForkId("0x63760190", 1700000L), |
||||
Optional.of(ForkIds.ROPSTEN), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Ropsten // Last Spurious block", |
||||
Network.ROPSTEN, |
||||
1699999L, |
||||
wantForkId("0x63760190", 1700000L), |
||||
Optional.of(ForkIds.ROPSTEN), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Ropsten // First Byzantium block", |
||||
Network.ROPSTEN, |
||||
1700000L, |
||||
wantForkId("0x3ea159c7", 4230000L), |
||||
Optional.of(ForkIds.ROPSTEN), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Ropsten // First Byzantium block", |
||||
Network.ROPSTEN, |
||||
4229999L, |
||||
wantForkId("0x3ea159c7", 4230000L), |
||||
Optional.of(ForkIds.ROPSTEN), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Ropsten // First Constantinople block", |
||||
Network.ROPSTEN, |
||||
4230000L, |
||||
wantForkId("0x97b544f3", 4939394L), |
||||
Optional.of(ForkIds.ROPSTEN), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Ropsten // Last Constantinople block", |
||||
Network.ROPSTEN, |
||||
4939393L, |
||||
wantForkId("0x97b544f3", 4939394L), |
||||
Optional.of(ForkIds.ROPSTEN), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Ropsten // First Petersburg block", |
||||
Network.ROPSTEN, |
||||
4939394L, |
||||
wantForkId("0xd6e2149b", 6485846L), |
||||
Optional.of(ForkIds.ROPSTEN), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Ropsten // Last Petersburg block", |
||||
Network.ROPSTEN, |
||||
6485845L, |
||||
wantForkId("0xd6e2149b", 6485846L), |
||||
Optional.of(ForkIds.ROPSTEN), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Ropsten // First Istanbul block", |
||||
Network.ROPSTEN, |
||||
6485846L, |
||||
wantForkId("0x4bc66396", 7117117L), |
||||
Optional.of(ForkIds.ROPSTEN), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Ropsten // Last Istanbul block", |
||||
Network.ROPSTEN, |
||||
7117116L, |
||||
wantForkId("0x4bc66396", 7117117L), |
||||
Optional.of(ForkIds.ROPSTEN), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Ropsten // First Muir Glacier block", |
||||
Network.ROPSTEN, |
||||
7117117L, |
||||
wantForkId("0x6727ef90", 0L), |
||||
Optional.of(ForkIds.ROPSTEN), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Ropsten // Future", |
||||
Network.ROPSTEN, |
||||
7500000L, |
||||
wantForkId("0x6727ef90", 0L), |
||||
Optional.of(ForkIds.ROPSTEN), |
||||
empty() |
||||
}, |
||||
// Rinkeby test cases
|
||||
{ |
||||
"Rinkeby // Unsynced, last Frontier block", |
||||
Network.RINKEBY, |
||||
0L, |
||||
wantForkId("0x3b8e0691", 1L), |
||||
Optional.of(ForkIds.RINKEBY), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Rinkeby // First and last Homestead block", |
||||
Network.RINKEBY, |
||||
1L, |
||||
wantForkId("0x60949295", 2L), |
||||
Optional.of(ForkIds.RINKEBY), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Rinkeby // First and last Tangerine block", |
||||
Network.RINKEBY, |
||||
2L, |
||||
wantForkId("0x8bde40dd", 3L), |
||||
Optional.of(ForkIds.RINKEBY), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Rinkeby // First Spurious block", |
||||
Network.RINKEBY, |
||||
3L, |
||||
wantForkId("0xcb3a64bb", 1035301L), |
||||
Optional.of(ForkIds.RINKEBY), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Rinkeby // Last Spurious block", |
||||
Network.RINKEBY, |
||||
1035300L, |
||||
wantForkId("0xcb3a64bb", 1035301L), |
||||
Optional.of(ForkIds.RINKEBY), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Rinkeby // First Byzantium block", |
||||
Network.RINKEBY, |
||||
1035301L, |
||||
wantForkId("0x8d748b57", 3660663L), |
||||
Optional.of(ForkIds.RINKEBY), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Rinkeby // Last Byzantium block", |
||||
Network.RINKEBY, |
||||
3660662L, |
||||
wantForkId("0x8d748b57", 3660663L), |
||||
Optional.of(ForkIds.RINKEBY), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Rinkeby // First Constantinople block", |
||||
Network.RINKEBY, |
||||
3660663L, |
||||
wantForkId("0xe49cab14", 4321234L), |
||||
Optional.of(ForkIds.RINKEBY), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Rinkeby // Last Constantinople block", |
||||
Network.RINKEBY, |
||||
4321233L, |
||||
wantForkId("0xe49cab14", 4321234L), |
||||
Optional.of(ForkIds.RINKEBY), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Rinkeby // First Petersburg block", |
||||
Network.RINKEBY, |
||||
4321234L, |
||||
wantForkId("0xafec6b27", 5435345L), |
||||
Optional.of(ForkIds.RINKEBY), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Rinkeby // Last Petersburg block", |
||||
Network.RINKEBY, |
||||
5435344L, |
||||
wantForkId("0xafec6b27", 5435345L), |
||||
Optional.of(ForkIds.RINKEBY), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Rinkeby // First Istanbul block", |
||||
Network.RINKEBY, |
||||
5435345L, |
||||
wantForkId("0xcbdb8838", 0L), |
||||
Optional.of(ForkIds.RINKEBY), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Rinkeby // Future Istanbul block", |
||||
Network.RINKEBY, |
||||
6000000L, |
||||
wantForkId("0xcbdb8838", 0L), |
||||
Optional.of(ForkIds.RINKEBY), |
||||
empty() |
||||
}, |
||||
// Goerli test cases
|
||||
{ |
||||
"Goerli // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople and first Petersburg block", |
||||
Network.GOERLI, |
||||
0L, |
||||
wantForkId("0xa3f5ab08", 1561651L), |
||||
Optional.of(ForkIds.GOERLI), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Goerli // Last Petersburg block", |
||||
Network.GOERLI, |
||||
1561650L, |
||||
wantForkId("0xa3f5ab08", 1561651L), |
||||
Optional.of(ForkIds.GOERLI), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Goerli // First Istanbul block", |
||||
Network.GOERLI, |
||||
1561651L, |
||||
wantForkId("0xc25efa5c", 0L), |
||||
Optional.of(ForkIds.GOERLI), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Goerli // Future Istanbul block", |
||||
Network.GOERLI, |
||||
2000000L, |
||||
wantForkId("0xc25efa5c", 0L), |
||||
Optional.of(ForkIds.GOERLI), |
||||
empty() |
||||
}, |
||||
// Private network test cases
|
||||
{ |
||||
"Private // Unsynced", |
||||
Network.PRIVATE, |
||||
0L, |
||||
wantForkId("0x190a55ad", 0L), |
||||
empty(), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Private // First block", |
||||
Network.PRIVATE, |
||||
1L, |
||||
wantForkId("0x190a55ad", 0L), |
||||
empty(), |
||||
empty() |
||||
}, |
||||
{ |
||||
"Private // Future block", |
||||
Network.PRIVATE, |
||||
1000000L, |
||||
wantForkId("0x190a55ad", 0L), |
||||
empty(), |
||||
empty() |
||||
}, |
||||
// Peer check cases
|
||||
{ |
||||
"check1PetersburgWithRemoteAnnouncingTheSame", |
||||
Network.MAINNET, |
||||
7987396L, |
||||
empty(), |
||||
empty(), |
||||
wantPeerCheck("0x668db0af", 0L, true) |
||||
}, |
||||
{ |
||||
"check2PetersburgWithRemoteAnnouncingTheSameAndNextFork", |
||||
Network.MAINNET, |
||||
7987396L, |
||||
empty(), |
||||
empty(), |
||||
wantPeerCheck("0x668db0af", Long.MAX_VALUE, true) |
||||
}, |
||||
{ |
||||
"check3ByzantiumAwareOfPetersburgRemoteUnawareOfPetersburg", |
||||
Network.MAINNET, |
||||
7279999L, |
||||
empty(), |
||||
empty(), |
||||
wantPeerCheck("0xa00bc324", 0L, true) |
||||
}, |
||||
{ |
||||
"check4ByzantiumAwareOfPetersburgRemoteAwareOfPetersburg", |
||||
Network.MAINNET, |
||||
7987396L, |
||||
empty(), |
||||
empty(), |
||||
wantPeerCheck("0xa00bc324", 7280000L, true) |
||||
}, |
||||
{ |
||||
"check5ByzantiumAwareOfPetersburgRemoteAnnouncingUnknownFork", |
||||
Network.MAINNET, |
||||
7279999L, |
||||
empty(), |
||||
empty(), |
||||
wantPeerCheck("0xa00bc324", Long.MAX_VALUE, true) |
||||
}, |
||||
{ |
||||
"check6PetersburgWithRemoteAnnouncingByzantiumAwareOfPetersburg", |
||||
Network.MAINNET, |
||||
7987396L, |
||||
empty(), |
||||
empty(), |
||||
wantPeerCheck("0x668db0af", 7280000L, true) |
||||
}, |
||||
{ |
||||
"check7PetersburgWithRemoteAnnouncingSpuriousAwareOfByzantiumRemoteMayNeedUpdate", |
||||
Network.MAINNET, |
||||
7987396L, |
||||
empty(), |
||||
empty(), |
||||
wantPeerCheck("0x3edd5b10", 4370000L, true) |
||||
}, |
||||
{ |
||||
"check8ByzantiumWithRemoteAnnouncingPetersburgLocalOutOfSync", |
||||
Network.MAINNET, |
||||
727999L, |
||||
empty(), |
||||
empty(), |
||||
wantPeerCheck("0x668db0af", 0L, true) |
||||
}, |
||||
{ |
||||
"check9SpuriousWithRemoteAnnouncingByzantiumRemoteUnawareOfPetersburg", |
||||
Network.MAINNET, |
||||
4369999L, |
||||
empty(), |
||||
empty(), |
||||
wantPeerCheck("0xa00bc324", 0L, true) |
||||
}, |
||||
{ |
||||
"check10PetersburgWithRemoteAnnouncingByzantiumRemoteUnawareOfAdditionalForks", |
||||
Network.network( |
||||
GenesisHash.MAINNET, |
||||
asList(1150000L, 1920000L, 2463000L, 2675000L, 4370000L, 7280000L)), |
||||
7987396L, |
||||
empty(), |
||||
empty(), |
||||
wantPeerCheck("0xa00bc324", 0L, false) |
||||
}, |
||||
{ |
||||
"check11PetersburgWithRemoteAnnouncingPetersburgAndFutureForkLocalNeedsUpdate", |
||||
Network.network( |
||||
GenesisHash.MAINNET, |
||||
asList(1150000L, 1920000L, 2463000L, 2675000L, 4370000L, 7280000L)), |
||||
7987396L, |
||||
empty(), |
||||
empty(), |
||||
wantPeerCheck("0x5cddc0e1", 0L, false) |
||||
}, |
||||
{ |
||||
"check12ByzantiumWithRemoteAnnouncingPetersburgAndFutureForkLocalNeedsUpdate", |
||||
Network.network( |
||||
GenesisHash.MAINNET, |
||||
asList(1150000L, 1920000L, 2463000L, 2675000L, 4370000L, 7280000L)), |
||||
7279999L, |
||||
empty(), |
||||
empty(), |
||||
wantPeerCheck("0x5cddc0e1", 0L, false) |
||||
}, |
||||
{ |
||||
"check13ByzantiumWithRemoteAnnouncingRinkebyPetersburg", |
||||
Network.network( |
||||
GenesisHash.MAINNET, |
||||
asList(1150000L, 1920000L, 2463000L, 2675000L, 4370000L, 7280000L)), |
||||
7987396L, |
||||
empty(), |
||||
empty(), |
||||
wantPeerCheck("0xafec6b27", 0L, false) |
||||
} |
||||
}); |
||||
} |
||||
|
||||
private final String name; |
||||
private final Network network; |
||||
private final long head; |
||||
private final Optional<ForkId> wantForkId; |
||||
private final Optional<List<ForkId>> wantForkIds; |
||||
private final Optional<PeerCheckCase> wantPeerCheckCase; |
||||
|
||||
@Test |
||||
public void test() { |
||||
LOG.info("Running test case {}", name); |
||||
final ForkIdManager forkIdManager = |
||||
new ForkIdManager(mockBlockchain(network.hash, head), network.forks); |
||||
wantForkId.ifPresent(forkId -> assertThat(forkIdManager.computeForkId()).isEqualTo(forkId)); |
||||
wantForkIds.ifPresent( |
||||
forkIds -> |
||||
assertThat(forkIdManager.getForkAndHashList()).containsExactlyElementsOf(forkIds)); |
||||
wantPeerCheckCase.ifPresent( |
||||
peerCheckCase -> |
||||
assertThat( |
||||
forkIdManager.peerCheck( |
||||
new ForkId( |
||||
Bytes.fromHexString(peerCheckCase.forkIdHash), |
||||
peerCheckCase.forkIdNext))) |
||||
.isEqualTo(peerCheckCase.want)); |
||||
} |
||||
|
||||
public EIP2124Test( |
||||
final String name, |
||||
final Network network, |
||||
final long head, |
||||
final Optional<ForkId> wantForkId, |
||||
final Optional<List<ForkId>> wantForkIds, |
||||
final Optional<PeerCheckCase> wantPeerCheckCase) { |
||||
this.name = name; |
||||
this.network = network; |
||||
this.head = head; |
||||
this.wantForkId = wantForkId; |
||||
this.wantForkIds = wantForkIds; |
||||
this.wantPeerCheckCase = wantPeerCheckCase; |
||||
} |
||||
|
||||
private static Blockchain mockBlockchain(final String genesisHash, final long chainHeight) { |
||||
final Blockchain mockchain = mock(Blockchain.class); |
||||
final BlockHeader mockHeader = mock(BlockHeader.class); |
||||
final Block block = new Block(mockHeader, null); |
||||
when(mockchain.getGenesisBlock()).thenReturn(block); |
||||
when(mockchain.getChainHeadBlockNumber()).thenReturn(chainHeight); |
||||
when(mockHeader.getHash()).thenReturn(Hash.fromHexString(genesisHash)); |
||||
return mockchain; |
||||
} |
||||
|
||||
private static class GenesisHash { |
||||
private static final String MAINNET = |
||||
"0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"; |
||||
private static final String ROPSTEN = |
||||
"0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"; |
||||
private static final String RINKEBY = |
||||
"0x6341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177"; |
||||
private static final String GOERLI = |
||||
"0xbf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a"; |
||||
private static final String PRIVATE = |
||||
"0x0000000000000000000000000000000000000000000000000000000000000000"; |
||||
} |
||||
|
||||
private static class Forks { |
||||
private static final List<Long> MAINNET = |
||||
Arrays.asList( |
||||
1920000L, 1150000L, 2463000L, 2675000L, 2675000L, 4370000L, 7280000L, 7280000L, |
||||
9069000L, 9200000L); |
||||
private static final List<Long> ROPSTEN = |
||||
Arrays.asList(0L, 0L, 10L, 1700000L, 4230000L, 4939394L, 6485846L, 7117117L); |
||||
private static final List<Long> RINKEBY = |
||||
Arrays.asList(1L, 2L, 3L, 3L, 1035301L, 3660663L, 4321234L, 5435345L); |
||||
private static final List<Long> GOERLI = Arrays.asList(0L, 0L, 0L, 0L, 0L, 0L, 0L, 1561651L); |
||||
private static final List<Long> PRIVATE = Arrays.asList(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L); |
||||
} |
||||
|
||||
private static class ForkIds { |
||||
private static final List<ForkId> MAINNET = |
||||
Arrays.asList( |
||||
new ForkId(Bytes.fromHexString("0xfc64ec04"), 1150000L), // Unsynced
|
||||
new ForkId(Bytes.fromHexString("0x97c2c34c"), 1920000L), // First Homestead block
|
||||
new ForkId(Bytes.fromHexString("0x91d1f948"), 2463000L), // First DAO block
|
||||
new ForkId(Bytes.fromHexString("0x7a64da13"), 2675000L), // First Tangerine block
|
||||
new ForkId(Bytes.fromHexString("0x3edd5b10"), 4370000L), // First Spurious block
|
||||
new ForkId(Bytes.fromHexString("0xa00bc324"), 7280000L), // First Byzantium block
|
||||
new ForkId(Bytes.fromHexString("0x668db0af"), 9069000L), |
||||
new ForkId(Bytes.fromHexString("0x879d6e30"), 9200000L), |
||||
new ForkId(Bytes.fromHexString("0xe029e991"), 0L)); |
||||
private static final List<ForkId> ROPSTEN = |
||||
Arrays.asList( |
||||
new ForkId(Bytes.fromHexString("0x30c7ddbc"), 10L), |
||||
new ForkId(Bytes.fromHexString("0x63760190"), 1700000L), |
||||
new ForkId(Bytes.fromHexString("0x3ea159c7"), 4230000L), |
||||
new ForkId(Bytes.fromHexString("0x97b544f3"), 4939394L), |
||||
new ForkId(Bytes.fromHexString("0xd6e2149b"), 6485846L), |
||||
new ForkId(Bytes.fromHexString("0x4bc66396"), 7117117L), |
||||
new ForkId(Bytes.fromHexString("0x6727ef90"), 0L)); |
||||
private static final List<ForkId> RINKEBY = |
||||
Arrays.asList( |
||||
new ForkId(Bytes.fromHexString("0x3b8e0691"), 1L), |
||||
new ForkId(Bytes.fromHexString("0x60949295"), 2L), |
||||
new ForkId(Bytes.fromHexString("0x8bde40dd"), 3L), |
||||
new ForkId(Bytes.fromHexString("0xcb3a64bb"), 1035301L), |
||||
new ForkId(Bytes.fromHexString("0x8d748b57"), 3660663L), |
||||
new ForkId(Bytes.fromHexString("0xe49cab14"), 4321234L), |
||||
new ForkId(Bytes.fromHexString("0xafec6b27"), 5435345L), |
||||
new ForkId(Bytes.fromHexString("0xcbdb8838"), 0L)); |
||||
private static final List<ForkId> GOERLI = |
||||
Arrays.asList( |
||||
new ForkId(Bytes.fromHexString("0xa3f5ab08"), 1561651L), |
||||
new ForkId(Bytes.fromHexString("0xc25efa5c"), 0L)); |
||||
} |
||||
|
||||
private static class Network { |
||||
private static final Network MAINNET = network(GenesisHash.MAINNET, Forks.MAINNET); |
||||
private static final Network ROPSTEN = network(GenesisHash.ROPSTEN, Forks.ROPSTEN); |
||||
private static final Network RINKEBY = network(GenesisHash.RINKEBY, Forks.RINKEBY); |
||||
private static final Network GOERLI = network(GenesisHash.GOERLI, Forks.GOERLI); |
||||
private static final Network PRIVATE = network(GenesisHash.PRIVATE, Forks.PRIVATE); |
||||
private final String hash; |
||||
private final List<Long> forks; |
||||
|
||||
Network(final String hash, final List<Long> forks) { |
||||
this.hash = hash; |
||||
this.forks = forks; |
||||
} |
||||
|
||||
private static Network network(final String hash, final List<Long> forks) { |
||||
return new Network(hash, forks); |
||||
} |
||||
} |
||||
|
||||
private static class PeerCheckCase { |
||||
private final String forkIdHash; |
||||
private final long forkIdNext; |
||||
private final boolean want; |
||||
|
||||
private PeerCheckCase(final String forkIdHash, final long forkIdNext, final boolean want) { |
||||
this.forkIdHash = forkIdHash; |
||||
this.forkIdNext = forkIdNext; |
||||
this.want = want; |
||||
} |
||||
} |
||||
|
||||
private static ForkId forkId(final String hash, final long next) { |
||||
return new ForkId(Bytes.fromHexString(hash), next); |
||||
} |
||||
|
||||
private static Optional<ForkId> wantForkId(final String hash, final long next) { |
||||
return Optional.of(forkId(hash, next)); |
||||
} |
||||
|
||||
private static Optional<PeerCheckCase> wantPeerCheck( |
||||
final String hash, final long next, final boolean want) { |
||||
return Optional.of(new PeerCheckCase(hash, next, want)); |
||||
} |
||||
} |
@ -1,389 +0,0 @@ |
||||
/* |
||||
* 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.besu.ethereum.eth.manager; |
||||
|
||||
import static java.util.Collections.emptyList; |
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy; |
||||
import static org.mockito.Mockito.mock; |
||||
import static org.mockito.Mockito.when; |
||||
|
||||
import org.hyperledger.besu.ethereum.chain.Blockchain; |
||||
import org.hyperledger.besu.ethereum.core.Block; |
||||
import org.hyperledger.besu.ethereum.core.BlockHeader; |
||||
import org.hyperledger.besu.ethereum.core.Hash; |
||||
import org.hyperledger.besu.ethereum.eth.manager.ForkIdManager.ForkId; |
||||
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; |
||||
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.List; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes; |
||||
import org.junit.Test; |
||||
|
||||
public class ForkIdManagerTest { |
||||
private final Long[] forksMainnet = {1150000L, 1920000L, 2463000L, 2675000L, 4370000L, 7280000L}; |
||||
private final String mainnetGenHash = |
||||
"0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"; |
||||
private final String consortiumNetworkGenHash = |
||||
"0x4109c6d17ca107e4de7565c94b429db8f5839593a9c57f3f31430b29b378b39d"; |
||||
|
||||
private Blockchain mockBlockchain(final String genesisHash, final long chainHeight) { |
||||
final Blockchain mockchain = mock(Blockchain.class); |
||||
final BlockHeader mockHeader = mock(BlockHeader.class); |
||||
final Block block = new Block(mockHeader, null); |
||||
when(mockchain.getGenesisBlock()).thenReturn(block); |
||||
when(mockchain.getChainHeadBlockNumber()).thenReturn(chainHeight); |
||||
when(mockHeader.getHash()).thenReturn(Hash.fromHexString(genesisHash)); |
||||
return mockchain; |
||||
} |
||||
|
||||
@Test |
||||
public void checkItFunctionsWithPresentBehavior() { |
||||
final ForkIdManager forkIdManager = |
||||
new ForkIdManager(mockBlockchain(mainnetGenHash, 0), emptyList()); |
||||
assertThat(forkIdManager.peerCheck(Hash.fromHexString(mainnetGenHash))).isFalse(); |
||||
assertThat(forkIdManager.getLatestForkId()).isNull(); |
||||
} |
||||
|
||||
@Test |
||||
public void checkCorrectMainnetForkIdHashesGenerated() { |
||||
final ForkId[] checkIds = { |
||||
new ForkId(Bytes.fromHexString("0xfc64ec04"), 1150000L), // Unsynced
|
||||
new ForkId(Bytes.fromHexString("0x97c2c34c"), 1920000L), // First Homestead block
|
||||
new ForkId(Bytes.fromHexString("0x91d1f948"), 2463000L), // First DAO block
|
||||
new ForkId(Bytes.fromHexString("0x7a64da13"), 2675000L), // First Tangerine block
|
||||
new ForkId(Bytes.fromHexString("0x3edd5b10"), 4370000L), // First Spurious block
|
||||
new ForkId(Bytes.fromHexString("0xa00bc324"), 7280000L), // First Byzantium block
|
||||
new ForkId(Bytes.fromHexString("0x668db0af"), 0L) // Today Petersburg block
|
||||
}; |
||||
final List<Long> list = Arrays.asList(forksMainnet); |
||||
final ForkIdManager forkIdManager = new ForkIdManager(mockBlockchain(mainnetGenHash, 0), list); |
||||
final List<ForkId> entries = forkIdManager.getForkAndHashList(); |
||||
assertThat(entries).containsExactly(checkIds); |
||||
assertThat(forkIdManager.getLatestForkId()).isNotNull(); |
||||
assertThat(forkIdManager.getLatestForkId()).isEqualTo(checkIds[6]); |
||||
} |
||||
|
||||
@Test |
||||
public void checkCorrectRopstenForkIdHashesGenerated() { |
||||
final Long[] forks = {10L, 1700000L, 4230000L, 4939394L}; |
||||
final String genHash = "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"; |
||||
final ForkId[] checkIds = { |
||||
new ForkId( |
||||
Bytes.fromHexString("0x30c7ddbc"), |
||||
10L), // Unsynced, last Frontier, Homestead and first Tangerine block
|
||||
new ForkId(Bytes.fromHexString("0x63760190"), 1700000L), // First Spurious block
|
||||
new ForkId(Bytes.fromHexString("0x3ea159c7"), 4230000L), // First Byzantium block
|
||||
new ForkId(Bytes.fromHexString("0x97b544f3"), 4939394L), // First Constantinople block
|
||||
new ForkId(Bytes.fromHexString("0xd6e2149b"), 0L) // Today Petersburg block
|
||||
}; |
||||
final List<Long> list = Arrays.asList(forks); |
||||
final ForkIdManager forkIdManager = new ForkIdManager(mockBlockchain(genHash, 0), list); |
||||
final List<ForkId> entries = forkIdManager.getForkAndHashList(); |
||||
|
||||
assertThat(entries).containsExactly(checkIds); |
||||
assertThat(forkIdManager.getLatestForkId()).isNotNull(); |
||||
assertThat(forkIdManager.getLatestForkId()).isEqualTo(checkIds[4]); |
||||
} |
||||
|
||||
@Test |
||||
public void checkCorrectRinkebyForkIdHashesGenerated() { |
||||
final Long[] forks = {1L, 2L, 3L, 1035301L, 3660663L, 4321234L}; |
||||
final String genHash = "0x6341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177"; |
||||
final ForkId[] checkIds = { |
||||
new ForkId( |
||||
Bytes.fromHexString("0x3b8e0691"), |
||||
1L), // Unsynced, last Frontier, Homestead and first Tangerine block
|
||||
new ForkId(Bytes.fromHexString("0x60949295"), 2L), // Last Tangerine block
|
||||
new ForkId(Bytes.fromHexString("0x8bde40dd"), 3L), // First Spurious block
|
||||
new ForkId(Bytes.fromHexString("0xcb3a64bb"), 1035301L), // First Byzantium block
|
||||
new ForkId(Bytes.fromHexString("0x8d748b57"), 3660663L), // First Constantinople block
|
||||
new ForkId(Bytes.fromHexString("0xe49cab14"), 4321234L), // First Petersburg block
|
||||
new ForkId(Bytes.fromHexString("0xafec6b27"), 0L) // Today Petersburg block
|
||||
}; |
||||
final List<Long> list = Arrays.asList(forks); |
||||
final ForkIdManager forkIdManager = new ForkIdManager(mockBlockchain(genHash, 0), list); |
||||
final List<ForkId> entries = forkIdManager.getForkAndHashList(); |
||||
|
||||
assertThat(entries).containsExactly(checkIds); |
||||
assertThat(forkIdManager.getLatestForkId()).isNotNull(); |
||||
assertThat(forkIdManager.getLatestForkId()).isEqualTo(checkIds[6]); |
||||
} |
||||
|
||||
@Test |
||||
public void checkCorrectGoerliForkIdHashesGenerated() { |
||||
final Long[] forks = {1561651L}; |
||||
final String genHash = "0xbf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a"; |
||||
final ForkId[] checkIds = { |
||||
new ForkId(Bytes.fromHexString("0xa3f5ab08"), 1561651L), // Frontier->Petersburg
|
||||
new ForkId(Bytes.fromHexString("0xc25efa5c"), 0L) // Istanbul
|
||||
}; |
||||
final List<Long> list = Arrays.asList(forks); |
||||
final ForkIdManager forkIdManager = new ForkIdManager(mockBlockchain(genHash, 0), list); |
||||
final List<ForkId> entries = forkIdManager.getForkAndHashList(); |
||||
|
||||
assertThat(entries).containsExactly(checkIds); |
||||
assertThat(forkIdManager.getLatestForkId()).isNotNull(); |
||||
assertThat(forkIdManager.getLatestForkId()).isEqualTo(checkIds[1]); |
||||
} |
||||
|
||||
@Test |
||||
public void check1PetersburgWithRemoteAnnouncingTheSame() { |
||||
// 1 Local is mainnet Petersburg, remote announces the same. No future fork is announced.
|
||||
// {7987396, ID{Hash: 0x668db0af, Next: 0}, nil},
|
||||
final List<Long> forkList = Arrays.asList(forksMainnet); |
||||
final ForkIdManager forkIdManager = |
||||
new ForkIdManager(mockBlockchain(mainnetGenHash, 7987396L), forkList); |
||||
final Boolean result = |
||||
forkIdManager.peerCheck(new ForkId(Bytes.fromHexString("0x668db0af"), 0L)); |
||||
assertThat(result).isTrue(); |
||||
assertThat(forkIdManager.getLatestForkId()).isNotNull(); |
||||
} |
||||
|
||||
@Test |
||||
public void check2PetersburgWithRemoteAnnouncingTheSameAndNextFork() { |
||||
// 2 Local is mainnet Petersburg, remote announces the same. Remote also announces a next fork
|
||||
// at block 0xffffffff, but that is uncertain.
|
||||
// {7987396, ID{Hash: 0x668db0af, Next: math.MaxUint64}, nil},
|
||||
final List<Long> forkList = Arrays.asList(forksMainnet); |
||||
final ForkIdManager forkIdManager = |
||||
new ForkIdManager(mockBlockchain(mainnetGenHash, 7987396L), forkList); |
||||
final Boolean result = |
||||
forkIdManager.peerCheck(new ForkId(Bytes.fromHexString("0x668db0af"), Long.MAX_VALUE)); |
||||
assertThat(result).isTrue(); |
||||
} |
||||
|
||||
@Test |
||||
public void check3ByzantiumAwareOfPetersburgRemoteUnawareOfPetersburg() { |
||||
// 3 Local is mainnet currently in Byzantium only (so it's aware of Petersburg), remote
|
||||
// announces also Byzantium, but it's not yet aware of Petersburg (e.g. non updated node before
|
||||
// the fork).
|
||||
// In this case we don't know if Petersburg passed yet or not.
|
||||
// {7279999, ID{Hash: 0xa00bc324, Next: 0}, nil},
|
||||
final List<Long> forkList = Arrays.asList(forksMainnet); |
||||
final ForkIdManager forkIdManager = |
||||
new ForkIdManager(mockBlockchain(mainnetGenHash, 7279999L), forkList); |
||||
final Boolean result = |
||||
forkIdManager.peerCheck(new ForkId(Bytes.fromHexString("0xa00bc324"), 0L)); |
||||
assertThat(result).isTrue(); |
||||
} |
||||
|
||||
@Test |
||||
public void check4ByzantiumAwareOfPetersburgRemoteAwareOfPetersburg() { |
||||
// 4 Local is mainnet currently in Byzantium only (so it's aware of Petersburg), remote
|
||||
// announces also Byzantium, and it's also aware of Petersburg (e.g. updated node before the
|
||||
// fork). We don't know if Petersburg passed yet (will pass) or not.
|
||||
// {7279999, ID{Hash: 0xa00bc324, Next: 7280000}, nil},
|
||||
final List<Long> forkList = Arrays.asList(forksMainnet); |
||||
final ForkIdManager forkIdManager = |
||||
new ForkIdManager(mockBlockchain(mainnetGenHash, 7987396L), forkList); |
||||
final Boolean result = |
||||
forkIdManager.peerCheck(new ForkId(Bytes.fromHexString("0xa00bc324"), 7280000L)); |
||||
assertThat(result).isTrue(); |
||||
} |
||||
|
||||
@Test |
||||
public void check5ByzantiumAwareOfPetersburgRemoteAnnouncingUnknownFork() { |
||||
// 5 Local is mainnet currently in Byzantium only (so it's aware of Petersburg), remote
|
||||
// announces also Byzantium, and it's also aware of some random fork (e.g. misconfigured
|
||||
// Petersburg).
|
||||
// As neither forks passed at neither nodes, they may mismatch, but we still connect for now.
|
||||
// {7279999, ID{Hash: 0xa00bc324, Next: math.MaxUint64}, nil},
|
||||
final List<Long> forkList = Arrays.asList(forksMainnet); |
||||
final ForkIdManager forkIdManager = |
||||
new ForkIdManager(mockBlockchain(mainnetGenHash, 7279999), forkList); |
||||
final Boolean result = |
||||
forkIdManager.peerCheck(new ForkId(Bytes.fromHexString("0xa00bc324"), Long.MAX_VALUE)); |
||||
assertThat(result).isTrue(); |
||||
} |
||||
|
||||
@Test |
||||
public void check6PetersburgWithRemoteAnnouncingByzantiumAwareOfPetersburg() { |
||||
// 6 Local is mainnet Petersburg, remote announces Byzantium + knowledge about Petersburg.
|
||||
// Remote is simply out of sync, accept.
|
||||
// {7987396, ID{Hash: 0x668db0af, Next: 7280000}, nil},
|
||||
final List<Long> forkList = Arrays.asList(forksMainnet); |
||||
final ForkIdManager forkIdManager = |
||||
new ForkIdManager(mockBlockchain(mainnetGenHash, 7987396L), forkList); |
||||
final Boolean result = |
||||
forkIdManager.peerCheck(new ForkId(Bytes.fromHexString("0x668db0af"), 7280000L)); |
||||
assertThat(result).isTrue(); |
||||
} |
||||
|
||||
@Test |
||||
public void check7PetersburgWithRemoteAnnouncingSpuriousAwareOfByzantiumRemoteMayNeedUpdate() { |
||||
// 7 Local is mainnet Petersburg, remote announces Spurious + knowledge about Byzantium.
|
||||
// Remote is definitely out of sync. It may or may not need the Petersburg update, we don't know
|
||||
// yet.
|
||||
// {7987396, ID{Hash: 0x3edd5b10, Next: 4370000}, nil},
|
||||
final List<Long> forkList = Arrays.asList(forksMainnet); |
||||
final ForkIdManager forkIdManager = |
||||
new ForkIdManager(mockBlockchain(mainnetGenHash, 7987396L), forkList); |
||||
final Boolean result = |
||||
forkIdManager.peerCheck(new ForkId(Bytes.fromHexString("0x3edd5b10"), 4370000L)); |
||||
assertThat(result).isTrue(); |
||||
} |
||||
|
||||
@Test |
||||
public void check8ByzantiumWithRemoteAnnouncingPetersburgLocalOutOfSync() { |
||||
// 8 Local is mainnet Byzantium, remote announces Petersburg. Local is out of sync, accept.
|
||||
// {7279999, ID{Hash: 0x668db0af, Next: 0}, nil},
|
||||
final List<Long> forkList = Arrays.asList(forksMainnet); |
||||
final ForkIdManager forkIdManager = |
||||
new ForkIdManager(mockBlockchain(mainnetGenHash, 727999L), forkList); |
||||
final Boolean result = |
||||
forkIdManager.peerCheck(new ForkId(Bytes.fromHexString("0x668db0af"), 0L)); |
||||
assertThat(result).isTrue(); |
||||
} |
||||
|
||||
@Test |
||||
public void check9SpuriousWithRemoteAnnouncingByzantiumRemoteUnawareOfPetersburg() { |
||||
// 9 Local is mainnet Spurious, remote announces Byzantium, but is not aware of Petersburg.
|
||||
// Local out of sync. Local also knows about a future fork, but that is uncertain yet.
|
||||
// {4369999, ID{Hash: 0xa00bc324, Next: 0}, nil},
|
||||
final List<Long> forkList = Arrays.asList(forksMainnet); |
||||
final ForkIdManager forkIdManager = |
||||
new ForkIdManager(mockBlockchain(mainnetGenHash, 4369999L), forkList); |
||||
final Boolean result = |
||||
forkIdManager.peerCheck(new ForkId(Bytes.fromHexString("0xa00bc324"), 0L)); |
||||
assertThat(result).isTrue(); |
||||
} |
||||
|
||||
@Test |
||||
public void check10PetersburgWithRemoteAnnouncingByzantiumRemoteUnawareOfAdditionalForks() { |
||||
// 10 Local is mainnet Petersburg. remote announces Byzantium but is not aware of further forks.
|
||||
// Remote needs software update.
|
||||
// {7987396, ID{Hash: 0xa00bc324, Next: 0}, ErrRemoteStale},
|
||||
final List<Long> forkList = Arrays.asList(forksMainnet); |
||||
final ForkIdManager forkIdManager = |
||||
new ForkIdManager(mockBlockchain(mainnetGenHash, 7987396L), forkList); |
||||
final Boolean result = |
||||
forkIdManager.peerCheck(new ForkId(Bytes.fromHexString("0xa00bc324"), 0L)); |
||||
assertThat(result).isFalse(); |
||||
} |
||||
|
||||
@Test |
||||
public void check11PetersburgWithRemoteAnnouncingPetersburgAndFutureForkLocalNeedsUpdate() { |
||||
// 11 Local is mainnet Petersburg, and isn't aware of more forks. Remote announces Petersburg +
|
||||
// 0xffffffff. Local needs software update, reject.
|
||||
// {7987396, ID{Hash: 0x5cddc0e1, Next: 0}, ErrLocalIncompatibleOrStale},
|
||||
final List<Long> forkList = Arrays.asList(forksMainnet); |
||||
final ForkIdManager forkIdManager = |
||||
new ForkIdManager(mockBlockchain(mainnetGenHash, 7987396L), forkList); |
||||
final Boolean result = |
||||
forkIdManager.peerCheck(new ForkId(Bytes.fromHexString("0x5cddc0e1"), 0L)); |
||||
assertThat(result).isFalse(); |
||||
} |
||||
|
||||
@Test |
||||
public void check12ByzantiumWithRemoteAnnouncingPetersburgAndFutureForkLocalNeedsUpdate() { |
||||
// 12 Local is mainnet Byzantium, and is aware of Petersburg. Remote announces Petersburg +
|
||||
// 0xffffffff. Local needs software update, reject.
|
||||
// {7279999, ID{Hash: 0x5cddc0e1, Next: 0}, ErrLocalIncompatibleOrStale},
|
||||
final List<Long> forkList = Arrays.asList(forksMainnet); |
||||
final ForkIdManager forkIdManager = |
||||
new ForkIdManager(mockBlockchain(mainnetGenHash, 7279999L), forkList); |
||||
final Boolean result = |
||||
forkIdManager.peerCheck(new ForkId(Bytes.fromHexString("0x5cddc0e1"), 0L)); |
||||
assertThat(result).isFalse(); |
||||
} |
||||
|
||||
@Test |
||||
public void check13ByzantiumWithRemoteAnnouncingRinkebyPetersburg() { |
||||
// 13 Local is mainnet Petersburg, remote is Rinkeby Petersburg.
|
||||
// {7987396, ID{Hash: 0xafec6b27, Next: 0}, ErrLocalIncompatibleOrStale},
|
||||
final List<Long> forkList = Arrays.asList(forksMainnet); |
||||
final ForkIdManager forkIdManager = |
||||
new ForkIdManager(mockBlockchain(mainnetGenHash, 7987396L), forkList); |
||||
final Boolean result = |
||||
forkIdManager.peerCheck(new ForkId(Bytes.fromHexString("0xafec6b27"), 0L)); |
||||
assertThat(result).isFalse(); |
||||
} |
||||
|
||||
@Test |
||||
public void createAndDecodeRLP() { |
||||
final ForkId forkIdEntry = new ForkId(Bytes.fromHexString("0xa00bc324"), 7280000L); |
||||
final BytesValueRLPOutput out = new BytesValueRLPOutput(); |
||||
forkIdEntry.writeTo(out); |
||||
final Bytes bytesValue = out.encoded(); |
||||
final BytesValueRLPInput in = new BytesValueRLPInput(bytesValue, false); |
||||
final ForkId decodedEntry = ForkIdManager.readFrom(in); |
||||
assertThat(forkIdEntry).isEqualTo(decodedEntry); |
||||
} |
||||
|
||||
@Test |
||||
public void check1ZeroZeroProperRLPEncoding() { |
||||
final ForkId forkIdEntry = new ForkId(Bytes.fromHexString("0x00000000"), 0); |
||||
final BytesValueRLPOutput out = new BytesValueRLPOutput(); |
||||
forkIdEntry.writeTo(out); |
||||
final String str1 = "0xc6840000000080"; |
||||
final Bytes bytesValue = out.encoded(); |
||||
assertThat(str1).isEqualTo(bytesValue.toString()); |
||||
final BytesValueRLPInput in = new BytesValueRLPInput(bytesValue, false); |
||||
final ForkId decodedEntry = ForkIdManager.readFrom(in); |
||||
assertThat(forkIdEntry).isEqualTo(decodedEntry); |
||||
} |
||||
|
||||
@Test |
||||
public void check2ArbitraryProperRLPEncoding() { |
||||
final ForkId forkIdEntry = new ForkId(Bytes.fromHexString("0xdeadbeef"), 0xbaddcafeL); |
||||
final BytesValueRLPOutput out = new BytesValueRLPOutput(); |
||||
forkIdEntry.writeTo(out); |
||||
final String str1 = "0xca84deadbeef84baddcafe"; |
||||
final Bytes bytesValue = out.encoded(); |
||||
assertThat(str1).isEqualTo(bytesValue.toString()); |
||||
final BytesValueRLPInput in = new BytesValueRLPInput(bytesValue, false); |
||||
final ForkId decodedEntry = ForkIdManager.readFrom(in); |
||||
assertThat(forkIdEntry).isEqualTo(decodedEntry); |
||||
} |
||||
|
||||
@Test |
||||
public void check3MaximumsProperRLPEncoding() { |
||||
final ForkId forkIdEntry = new ForkId(Bytes.fromHexString("0xffffffff"), 0xffffffffffffffffL); |
||||
final BytesValueRLPOutput out = new BytesValueRLPOutput(); |
||||
forkIdEntry.writeTo(out); |
||||
final String str1 = |
||||
"0xce84ffffffff88ffffffffffffffff"; // Check value supplied in EIP-2124 spec via GO lang
|
||||
final Bytes bytesValue = out.encoded(); |
||||
assertThat(str1).isEqualTo(bytesValue.toString()); |
||||
final BytesValueRLPInput in = new BytesValueRLPInput(bytesValue, false); |
||||
final ForkId decodedEntry = ForkIdManager.readFrom(in); |
||||
assertThat(forkIdEntry).isEqualTo(decodedEntry); |
||||
} |
||||
|
||||
@Test |
||||
public void checkConsortiumNetworkAlwaysAcceptPeersIfOnlyZeroForkBlocks() { |
||||
final List<Long> list = Arrays.asList(0L, 0L, 0L, 0L); |
||||
|
||||
final ForkIdManager forkIdManager = |
||||
new ForkIdManager(mockBlockchain(consortiumNetworkGenHash, 0), list); |
||||
assertThat(forkIdManager.peerCheck(new ForkId(Bytes.random(32), 0))).isTrue(); |
||||
} |
||||
|
||||
@Test |
||||
public void checkAlwaysAcceptPeersIfNull() { |
||||
final ForkIdManager forkIdManager = |
||||
new ForkIdManager(mockBlockchain(consortiumNetworkGenHash, 0), emptyList()); |
||||
assertThat(forkIdManager.peerCheck((ForkId) null)).isTrue(); |
||||
} |
||||
|
||||
@Test |
||||
public void assertThatConstructorParametersMustNotBeNull() { |
||||
assertThatThrownBy(() -> new ForkIdManager(mockBlockchain(consortiumNetworkGenHash, 0), null)) |
||||
.isExactlyInstanceOf(NullPointerException.class); |
||||
} |
||||
} |
@ -0,0 +1,34 @@ |
||||
/* |
||||
* 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.besu.util; |
||||
|
||||
public class EndianUtils { |
||||
// next two methods adopted from:
|
||||
// https://github.com/bcgit/bc-java/blob/master/core/src/main/java/org/bouncycastle/util/Pack.java
|
||||
public static byte[] longToBigEndian(final long n) { |
||||
final byte[] bs = new byte[8]; |
||||
intToBigEndian((int) (n >>> 32), bs, 0); |
||||
intToBigEndian((int) (n & 0xffffffffL), bs, 4); |
||||
return bs; |
||||
} |
||||
|
||||
@SuppressWarnings("MethodInputParametersMustBeFinal") |
||||
public static void intToBigEndian(final int n, final byte[] bs, int off) { |
||||
bs[off] = (byte) (n >>> 24); |
||||
bs[++off] = (byte) (n >>> 16); |
||||
bs[++off] = (byte) (n >>> 8); |
||||
bs[++off] = (byte) (n); |
||||
} |
||||
} |
Loading…
Reference in new issue