mirror of https://github.com/hyperledger/besu
[NC-1582] Moved all the legacy iBFT classes for block importing into the newly created ibftlegacy module (#96)
parent
eb7f062171
commit
7cb8fef4d4
@ -0,0 +1,33 @@ |
|||||||
|
apply plugin: 'java-library' |
||||||
|
|
||||||
|
jar { |
||||||
|
baseName 'pantheon-ibftlegacy' |
||||||
|
manifest { |
||||||
|
attributes('Implementation-Title': baseName, |
||||||
|
'Implementation-Version': project.version) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
dependencies { |
||||||
|
implementation project(':consensus:common') |
||||||
|
implementation project(':consensus:ibft') |
||||||
|
implementation project(':crypto') |
||||||
|
implementation project(':ethereum:core') |
||||||
|
implementation project(':ethereum:eth') |
||||||
|
implementation project(':ethereum:jsonrpc') |
||||||
|
implementation project(':ethereum:rlp') |
||||||
|
implementation project(':ethereum:p2p') |
||||||
|
implementation project(':services:kvstore') |
||||||
|
|
||||||
|
implementation 'com.google.guava:guava' |
||||||
|
implementation 'io.vertx:vertx-core' |
||||||
|
|
||||||
|
testImplementation project( path: ':ethereum:core', configuration: 'testSupportArtifacts') |
||||||
|
testImplementation project( path: ':consensus:ibft', configuration: 'testSupportArtifacts') |
||||||
|
|
||||||
|
testImplementation group: 'junit', name: 'junit', version: '4.12' |
||||||
|
testImplementation "org.awaitility:awaitility:3.1.2" |
||||||
|
|
||||||
|
testImplementation "org.assertj:assertj-core:3.10.0" |
||||||
|
testImplementation 'org.mockito:mockito-core' |
||||||
|
} |
@ -0,0 +1,87 @@ |
|||||||
|
/* |
||||||
|
* 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.consensus.ibftlegacy; |
||||||
|
|
||||||
|
import tech.pegasys.pantheon.consensus.common.EpochManager; |
||||||
|
import tech.pegasys.pantheon.consensus.common.VoteTally; |
||||||
|
import tech.pegasys.pantheon.consensus.common.VoteType; |
||||||
|
import tech.pegasys.pantheon.consensus.ibft.VoteTallyUpdater; |
||||||
|
import tech.pegasys.pantheon.ethereum.chain.Blockchain; |
||||||
|
import tech.pegasys.pantheon.ethereum.core.Address; |
||||||
|
import tech.pegasys.pantheon.ethereum.core.BlockHeader; |
||||||
|
import tech.pegasys.pantheon.util.bytes.BytesValue; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager; |
||||||
|
import org.apache.logging.log4j.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* Provides the logic to extract vote tally state from the blockchain and update it as blocks are |
||||||
|
* added. |
||||||
|
*/ |
||||||
|
public class IbftVoteTallyUpdater implements VoteTallyUpdater { |
||||||
|
|
||||||
|
private static final Logger LOG = LogManager.getLogger(); |
||||||
|
private static final Address NO_VOTE_SUBJECT = Address.wrap(BytesValue.wrap(new byte[20])); |
||||||
|
|
||||||
|
private final EpochManager epochManager; |
||||||
|
|
||||||
|
public IbftVoteTallyUpdater(final EpochManager epochManager) { |
||||||
|
this.epochManager = epochManager; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new VoteTally based on the current blockchain state. |
||||||
|
* |
||||||
|
* @param blockchain the blockchain to load the current state from |
||||||
|
* @return a VoteTally reflecting the state of the blockchain head |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public VoteTally buildVoteTallyFromBlockchain(final Blockchain blockchain) { |
||||||
|
final long chainHeadBlockNumber = blockchain.getChainHeadBlockNumber(); |
||||||
|
final long epochBlockNumber = epochManager.getLastEpochBlock(chainHeadBlockNumber); |
||||||
|
LOG.info("Loading validator voting state starting from block {}", epochBlockNumber); |
||||||
|
final BlockHeader epochBlock = blockchain.getBlockHeader(epochBlockNumber).get(); |
||||||
|
final List<Address> initialValidators = |
||||||
|
IbftExtraData.decode(epochBlock.getExtraData()).getValidators(); |
||||||
|
final VoteTally voteTally = new VoteTally(initialValidators); |
||||||
|
for (long blockNumber = epochBlockNumber + 1; |
||||||
|
blockNumber <= chainHeadBlockNumber; |
||||||
|
blockNumber++) { |
||||||
|
updateForBlock(blockchain.getBlockHeader(blockNumber).get(), voteTally); |
||||||
|
} |
||||||
|
return voteTally; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Update the vote tally to reflect changes caused by appending a new block to the chain. |
||||||
|
* |
||||||
|
* @param header the header of the block being added |
||||||
|
* @param voteTally the vote tally to update |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void updateForBlock(final BlockHeader header, final VoteTally voteTally) { |
||||||
|
final Address candidate = header.getCoinbase(); |
||||||
|
if (epochManager.isEpochBlock(header.getNumber())) { |
||||||
|
voteTally.discardOutstandingVotes(); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (!candidate.equals(NO_VOTE_SUBJECT)) { |
||||||
|
final IbftExtraData ibftExtraData = IbftExtraData.decode(header.getExtraData()); |
||||||
|
final Address proposer = IbftBlockHashing.recoverProposerAddress(header, ibftExtraData); |
||||||
|
voteTally.addVote(proposer, candidate, VoteType.fromNonce(header.getNonce()).get()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,119 @@ |
|||||||
|
/* |
||||||
|
* 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.consensus.ibftlegacy.blockcreation; |
||||||
|
|
||||||
|
import tech.pegasys.pantheon.consensus.ibft.IbftContext; |
||||||
|
import tech.pegasys.pantheon.consensus.ibftlegacy.IbftBlockHashing; |
||||||
|
import tech.pegasys.pantheon.consensus.ibftlegacy.IbftExtraData; |
||||||
|
import tech.pegasys.pantheon.consensus.ibftlegacy.IbftHelpers; |
||||||
|
import tech.pegasys.pantheon.crypto.SECP256K1; |
||||||
|
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; |
||||||
|
import tech.pegasys.pantheon.ethereum.ProtocolContext; |
||||||
|
import tech.pegasys.pantheon.ethereum.blockcreation.AbstractBlockCreator; |
||||||
|
import tech.pegasys.pantheon.ethereum.core.Address; |
||||||
|
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.core.PendingTransactions; |
||||||
|
import tech.pegasys.pantheon.ethereum.core.SealableBlockHeader; |
||||||
|
import tech.pegasys.pantheon.ethereum.core.Util; |
||||||
|
import tech.pegasys.pantheon.ethereum.core.Wei; |
||||||
|
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; |
||||||
|
import tech.pegasys.pantheon.ethereum.mainnet.ScheduleBasedBlockHashFunction; |
||||||
|
|
||||||
|
import java.util.function.Function; |
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager; |
||||||
|
import org.apache.logging.log4j.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* Responsible for producing a Block which conforms to IBFT validation rules (other than missing |
||||||
|
* commit seals). Transactions and associated Hashes (stateroot, receipts etc.) are loaded into the |
||||||
|
* Block in the base class as part of the transaction selection process. |
||||||
|
*/ |
||||||
|
public class IbftBlockCreator extends AbstractBlockCreator<IbftContext> { |
||||||
|
|
||||||
|
private static final Logger LOG = LogManager.getLogger(); |
||||||
|
|
||||||
|
private final KeyPair nodeKeys; |
||||||
|
|
||||||
|
public IbftBlockCreator( |
||||||
|
final Address coinbase, |
||||||
|
final ExtraDataCalculator extraDataCalculator, |
||||||
|
final PendingTransactions pendingTransactions, |
||||||
|
final ProtocolContext<IbftContext> protocolContext, |
||||||
|
final ProtocolSchedule<IbftContext> protocolSchedule, |
||||||
|
final Function<Long, Long> gasLimitCalculator, |
||||||
|
final KeyPair nodeKeys, |
||||||
|
final Wei minTransactionGasPrice, |
||||||
|
final BlockHeader parentHeader) { |
||||||
|
super( |
||||||
|
coinbase, |
||||||
|
extraDataCalculator, |
||||||
|
pendingTransactions, |
||||||
|
protocolContext, |
||||||
|
protocolSchedule, |
||||||
|
gasLimitCalculator, |
||||||
|
minTransactionGasPrice, |
||||||
|
Util.publicKeyToAddress(nodeKeys.getPublicKey()), |
||||||
|
parentHeader); |
||||||
|
this.nodeKeys = nodeKeys; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Responsible for signing (hash of) the block (including MixHash and Nonce), and then injecting |
||||||
|
* the seal into the extraData. This is called after a suitable set of transactions have been |
||||||
|
* identified, and all resulting hashes have been inserted into the passed-in SealableBlockHeader. |
||||||
|
* |
||||||
|
* @param sealableBlockHeader A block header containing StateRoots, TransactionHashes etc. |
||||||
|
* @return The blockhead which is to be added to the block being proposed. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
protected BlockHeader createFinalBlockHeader(final SealableBlockHeader sealableBlockHeader) { |
||||||
|
|
||||||
|
final BlockHashFunction blockHashFunction = |
||||||
|
ScheduleBasedBlockHashFunction.create(protocolSchedule); |
||||||
|
|
||||||
|
final BlockHeaderBuilder builder = |
||||||
|
BlockHeaderBuilder.create() |
||||||
|
.populateFrom(sealableBlockHeader) |
||||||
|
.mixHash(IbftHelpers.EXPECTED_MIX_HASH) |
||||||
|
.nonce(0) |
||||||
|
.blockHashFunction(blockHashFunction); |
||||||
|
|
||||||
|
final IbftExtraData sealedExtraData = constructSignedExtraData(builder.buildBlockHeader()); |
||||||
|
|
||||||
|
// Replace the extraData in the BlockHeaderBuilder, and return header.
|
||||||
|
return builder.extraData(sealedExtraData.encode()).buildBlockHeader(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Produces an IbftExtraData object with a populated proposerSeal. The signature in the block is |
||||||
|
* generated from the Hash of the header (minus proposer and committer seals) and the nodeKeys. |
||||||
|
* |
||||||
|
* @param headerToSign An almost fully populated header (proposer and committer seals are empty) |
||||||
|
* @return Extra data containing the same vanity data and validators as extraData, however |
||||||
|
* proposerSeal will also be populated. |
||||||
|
*/ |
||||||
|
private IbftExtraData constructSignedExtraData(final BlockHeader headerToSign) { |
||||||
|
final IbftExtraData extraData = IbftExtraData.decode(headerToSign.getExtraData()); |
||||||
|
final Hash hashToSign = |
||||||
|
IbftBlockHashing.calculateDataHashForProposerSeal(headerToSign, extraData); |
||||||
|
return new IbftExtraData( |
||||||
|
extraData.getVanityData(), |
||||||
|
extraData.getSeals(), |
||||||
|
SECP256K1.sign(hashToSign, nodeKeys), |
||||||
|
extraData.getValidators()); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue