mirror of
https://github.com/vacp2p/linea-besu.git
synced 2026-01-09 23:47:57 -05:00
Remove RLPUtils from ProofOfWorkValidationRule (#83)
Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
This commit is contained in:
@@ -63,6 +63,25 @@ public class BlockHeaderBuilder {
|
||||
return new BlockHeaderBuilder();
|
||||
}
|
||||
|
||||
public static BlockHeaderBuilder fromHeader(final BlockHeader header) {
|
||||
return create()
|
||||
.parentHash(header.getParentHash())
|
||||
.ommersHash(header.getOmmersHash())
|
||||
.coinbase(header.getCoinbase())
|
||||
.stateRoot(header.getStateRoot())
|
||||
.transactionsRoot(header.getTransactionsRoot())
|
||||
.receiptsRoot(header.getReceiptsRoot())
|
||||
.logsBloom(header.getLogsBloom())
|
||||
.difficulty(header.getDifficulty())
|
||||
.number(header.getNumber())
|
||||
.gasLimit(header.getGasLimit())
|
||||
.gasUsed(header.getGasUsed())
|
||||
.timestamp(header.getTimestamp())
|
||||
.extraData(header.getExtraData())
|
||||
.mixHash(header.getMixHash())
|
||||
.nonce(header.getNonce());
|
||||
}
|
||||
|
||||
public BlockHeader buildBlockHeader() {
|
||||
validateBlockHeader();
|
||||
|
||||
|
||||
@@ -12,64 +12,34 @@
|
||||
*/
|
||||
package tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules;
|
||||
|
||||
import tech.pegasys.pantheon.crypto.BouncyCastleMessageDigestFactory;
|
||||
import tech.pegasys.pantheon.ethereum.core.BlockHeader;
|
||||
import tech.pegasys.pantheon.ethereum.core.Hash;
|
||||
import tech.pegasys.pantheon.ethereum.mainnet.DetachedBlockHeaderValidationRule;
|
||||
import tech.pegasys.pantheon.ethereum.mainnet.EthHasher;
|
||||
import tech.pegasys.pantheon.ethereum.rlp.RLP;
|
||||
import tech.pegasys.pantheon.ethereum.rlp.RlpUtils;
|
||||
import tech.pegasys.pantheon.ethereum.rlp.BytesValueRLPOutput;
|
||||
import tech.pegasys.pantheon.util.bytes.Bytes32;
|
||||
import tech.pegasys.pantheon.util.bytes.BytesValue;
|
||||
import tech.pegasys.pantheon.util.bytes.BytesValues;
|
||||
import tech.pegasys.pantheon.util.uint.UInt256;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public final class ProofOfWorkValidationRule implements DetachedBlockHeaderValidationRule {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ProofOfWorkValidationRule.class);
|
||||
|
||||
private static final int SERIALIZED_HASH_SIZE = 33;
|
||||
|
||||
private static final int SERIALIZED_NONCE_SIZE = 9;
|
||||
private static final Logger LOG = LogManager.getLogger();
|
||||
|
||||
private static final BigInteger ETHHASH_TARGET_UPPER_BOUND = BigInteger.valueOf(2).pow(256);
|
||||
|
||||
private static final EthHasher HASHER = new EthHasher.Light();
|
||||
|
||||
private static final ThreadLocal<MessageDigest> KECCAK_256 =
|
||||
ThreadLocal.withInitial(
|
||||
() -> {
|
||||
try {
|
||||
return BouncyCastleMessageDigestFactory.create(
|
||||
tech.pegasys.pantheon.crypto.Hash.KECCAK256_ALG);
|
||||
} catch (final NoSuchAlgorithmException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public boolean validate(final BlockHeader header, final BlockHeader parent) {
|
||||
final MessageDigest keccak256 = KECCAK_256.get();
|
||||
|
||||
final byte[] bytes = RLP.encode(header::writeTo).extractArray();
|
||||
final int listOffset = RlpUtils.decodeOffset(bytes, 0);
|
||||
final int length = RlpUtils.decodeLength(bytes, 0);
|
||||
|
||||
final byte[] listHeadBuff = new byte[10];
|
||||
final int newLength = length - SERIALIZED_HASH_SIZE - SERIALIZED_NONCE_SIZE;
|
||||
final int sizeLen = writeListPrefix(newLength - listOffset, listHeadBuff);
|
||||
|
||||
keccak256.update(listHeadBuff, 0, sizeLen);
|
||||
keccak256.update(bytes, listOffset, newLength - sizeLen);
|
||||
final byte[] hashBuffer = new byte[64];
|
||||
HASHER.hash(hashBuffer, header.getNonce(), header.getNumber(), keccak256.digest());
|
||||
final Hash headerHash = hashHeader(header);
|
||||
HASHER.hash(hashBuffer, header.getNonce(), header.getNumber(), headerHash.extractArray());
|
||||
|
||||
if (header.getDifficulty().isZero()) {
|
||||
LOG.trace("Rejecting header because difficulty is 0");
|
||||
@@ -105,19 +75,31 @@ public final class ProofOfWorkValidationRule implements DetachedBlockHeaderValid
|
||||
return true;
|
||||
}
|
||||
|
||||
private Hash hashHeader(final BlockHeader header) {
|
||||
final BytesValueRLPOutput out = new BytesValueRLPOutput();
|
||||
|
||||
// Encode header without nonce and mixhash
|
||||
out.startList();
|
||||
out.writeBytesValue(header.getParentHash());
|
||||
out.writeBytesValue(header.getOmmersHash());
|
||||
out.writeBytesValue(header.getCoinbase());
|
||||
out.writeBytesValue(header.getStateRoot());
|
||||
out.writeBytesValue(header.getTransactionsRoot());
|
||||
out.writeBytesValue(header.getReceiptsRoot());
|
||||
out.writeBytesValue(header.getLogsBloom().getBytes());
|
||||
out.writeUInt256Scalar(header.getDifficulty());
|
||||
out.writeLongScalar(header.getNumber());
|
||||
out.writeLongScalar(header.getGasLimit());
|
||||
out.writeLongScalar(header.getGasUsed());
|
||||
out.writeLongScalar(header.getTimestamp());
|
||||
out.writeBytesValue(header.getExtraData());
|
||||
out.endList();
|
||||
|
||||
return Hash.hash(out.encoded());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includeInLightValidation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int writeListPrefix(final int size, final byte[] target) {
|
||||
final int sizeLength = 4 - Integer.numberOfLeadingZeros(size) / 8;
|
||||
target[0] = (byte) (0xf7 + sizeLength);
|
||||
int shift = 0;
|
||||
for (int i = 0; i < sizeLength; i++) {
|
||||
target[sizeLength - i] = (byte) (size >> shift);
|
||||
shift += 8;
|
||||
}
|
||||
return 1 + sizeLength;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2018 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.
|
||||
*/
|
||||
package tech.pegasys.pantheon.ethereum.mainnet.headervalidationrules;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.BlockHashFunction;
|
||||
import tech.pegasys.pantheon.ethereum.core.BlockHeader;
|
||||
import tech.pegasys.pantheon.ethereum.core.BlockHeaderBuilder;
|
||||
import tech.pegasys.pantheon.ethereum.core.Hash;
|
||||
import tech.pegasys.pantheon.ethereum.mainnet.MainnetProtocolSchedule;
|
||||
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
|
||||
import tech.pegasys.pantheon.ethereum.mainnet.ScheduleBasedBlockHashFunction;
|
||||
import tech.pegasys.pantheon.ethereum.mainnet.ValidationTestUtils;
|
||||
import tech.pegasys.pantheon.util.uint.UInt256;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
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 ProofOfWorkValidationRuleTest {
|
||||
|
||||
private final BlockHeader blockHeader;
|
||||
private final BlockHeader parentHeader;
|
||||
private final ProofOfWorkValidationRule validationRule;
|
||||
|
||||
public ProofOfWorkValidationRuleTest(final long parentBlockNum, final long blockNum)
|
||||
throws IOException {
|
||||
blockHeader = ValidationTestUtils.readHeader(parentBlockNum);
|
||||
parentHeader = ValidationTestUtils.readHeader(blockNum);
|
||||
validationRule = new ProofOfWorkValidationRule();
|
||||
}
|
||||
|
||||
@Parameters(name = "block {1}")
|
||||
public static Collection<Object[]> data() {
|
||||
|
||||
return Arrays.asList(
|
||||
new Object[][] {
|
||||
{300005, 300006},
|
||||
{1200000, 1200001},
|
||||
{4400000, 4400001},
|
||||
{4400001, 4400002}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validatesValidBlocks() {
|
||||
assertThat(validationRule.validate(blockHeader, parentHeader)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failsBlockWithZeroValuedDifficulty() {
|
||||
BlockHeader header =
|
||||
BlockHeaderBuilder.fromHeader(blockHeader)
|
||||
.difficulty(UInt256.ZERO)
|
||||
.blockHashFunction(mainnetBlockHashFunction())
|
||||
.buildBlockHeader();
|
||||
assertThat(validationRule.validate(header, parentHeader)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failsWithVeryLargeDifficulty() {
|
||||
UInt256 largeDifficulty = UInt256.of(BigInteger.valueOf(2).pow(255));
|
||||
BlockHeader header =
|
||||
BlockHeaderBuilder.fromHeader(blockHeader)
|
||||
.difficulty(largeDifficulty)
|
||||
.blockHashFunction(mainnetBlockHashFunction())
|
||||
.buildBlockHeader();
|
||||
assertThat(validationRule.validate(header, parentHeader)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failsWithMisMatchedMixHash() {
|
||||
Hash updateMixHash = Hash.wrap(blockHeader.getMixHash().asUInt256().minus(1L).getBytes());
|
||||
BlockHeader header =
|
||||
BlockHeaderBuilder.fromHeader(blockHeader)
|
||||
.mixHash(updateMixHash)
|
||||
.blockHashFunction(mainnetBlockHashFunction())
|
||||
.buildBlockHeader();
|
||||
assertThat(validationRule.validate(header, parentHeader)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failsWithMisMatchedNonce() {
|
||||
long updatedNonce = blockHeader.getNonce() + 1;
|
||||
BlockHeader header =
|
||||
BlockHeaderBuilder.fromHeader(blockHeader)
|
||||
.nonce(updatedNonce)
|
||||
.blockHashFunction(mainnetBlockHashFunction())
|
||||
.buildBlockHeader();
|
||||
assertThat(validationRule.validate(header, parentHeader)).isFalse();
|
||||
}
|
||||
|
||||
private BlockHashFunction mainnetBlockHashFunction() {
|
||||
ProtocolSchedule<Void> protocolSchedule = MainnetProtocolSchedule.create();
|
||||
return ScheduleBasedBlockHashFunction.create(protocolSchedule);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user