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)
Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>pull/2/head
parent
ceec103c29
commit
bb7b5423f6
@ -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