From 2148116b3216a874e1d0f68f29c5d558d7837395 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta <45264458+abdelhamidbakhta@users.noreply.github.com> Date: Fri, 3 Apr 2020 10:40:00 +0200 Subject: [PATCH] [EIP-1559] Step 1 - Apply block structure modification (#619) * Added changelog entries for PR: - https://github.com/hyperledger/besu/pull/430 - https://github.com/hyperledger/besu/pull/440 Signed-off-by: Abdelhamid Bakhta * ### Description BlockHeader object needs to be modified in order to add the new field (baseFee) as specified in the EIP. We should take care about the RLP encoding/decoding of this structure since it has to include or not the new fields depending on whether we are pre fork or post fork. - Update `core.BlockHeader.java` - Add `baseFee` - Update `readFrom` method for RLP decoding - Update `writeTo` method for RLP encoding - Update `plugin.data.BlockHeader.java` - Add `getBaseFee` method Signed-off-by: Abdelhamid Bakhta * TODO Add CLI command line flag `--Xeip1559-enabled`. Signed-off-by: Abdelhamid Bakhta * TODO Add CLI command line flag `--Xeip1559-enabled`. Signed-off-by: Abdelhamid Bakhta * Added unstable annotation for getBaseFee. Moved from long to `Optional` Signed-off-by: Abdelhamid Bakhta * Spotless apply Signed-off-by: Abdelhamid Bakhta * Fixed error Signed-off-by: Abdelhamid Bakhta * fix plugin API hash Signed-off-by: Abdelhamid Bakhta * RLP encoding / decoding operations are guarded with the feature flag. Signed-off-by: Abdelhamid Bakhta * spotless apply Signed-off-by: Abdelhamid Bakhta --- .../besu/tests/acceptance/dsl/BlockUtils.java | 1 + .../besu/services/BesuEventsImplTest.java | 2 +- .../api/jsonrpc/JsonRpcResponseKey.java | 3 +- .../api/jsonrpc/JsonRpcResponseUtils.java | 3 + .../query/BlockchainQueriesLogCacheTest.java | 1 + .../besu/ethereum/core/BlockHeader.java | 67 +++++++++++++------ .../ethereum/core/BlockHeaderBuilder.java | 12 +++- .../ethereum/core/SealableBlockHeader.java | 16 ++++- .../besu/ethereum/core/BlockHeaderMock.java | 1 + .../vm/BlockchainReferenceTestCaseSpec.java | 2 + plugin-api/build.gradle | 2 +- .../besu/plugin/data/BlockHeader.java | 14 ++++ 12 files changed, 98 insertions(+), 26 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 ab686920b34..076b61d90c7 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 @@ -48,6 +48,7 @@ public static BlockHeader createBlockHeader( block.getGasUsed().longValue(), block.getTimestamp().longValue(), Bytes.fromHexString(block.getExtraData()), + null, mixHash, block.getNonce().longValue(), blockHeaderFunctions); diff --git a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java index 589249bcaf9..6c4428fea0a 100644 --- a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java +++ b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java @@ -180,7 +180,7 @@ private void setSyncTarget() { syncState.setSyncTarget( mock(EthPeer.class), new org.hyperledger.besu.ethereum.core.BlockHeader( - null, null, null, null, null, null, null, null, 1, 1, 1, 1, null, null, 1, null)); + null, null, null, null, null, null, null, null, 1, 1, 1, 1, null, null, null, 1, null)); } private void clearSyncTarget() { diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseKey.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseKey.java index 3149b9742ed..278c6f1a5d7 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseKey.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseKey.java @@ -31,5 +31,6 @@ public enum JsonRpcResponseKey { STATE_ROOT, TIMESTAMP, TOTAL_DIFFICULTY, - TRANSACTION_ROOT + TRANSACTION_ROOT, + BASEFEE } diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java index f98f4814531..6257bcdfcca 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc; +import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseKey.BASEFEE; import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseKey.COINBASE; import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseKey.DIFFICULTY; import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseKey.EXTRA_DATA; @@ -91,6 +92,7 @@ public JsonRpcResponse response( final long gasUsed = unsignedLong(values.get(GAS_USED)); final long timestamp = unsignedLong(values.get(TIMESTAMP)); final long nonce = unsignedLong(values.get(NONCE)); + final Long baseFee = values.containsKey(BASEFEE) ? unsignedLong(values.get(BASEFEE)) : null; final Difficulty totalDifficulty = Difficulty.of(unsignedInt256(values.get(TOTAL_DIFFICULTY))); final int size = unsignedInt(values.get(SIZE)); @@ -111,6 +113,7 @@ public JsonRpcResponse response( gasUsed, timestamp, extraData, + baseFee, mixHash, nonce, blockHeaderFunctions); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesLogCacheTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesLogCacheTest.java index f81d7d94ffe..fb857886a4e 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesLogCacheTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesLogCacheTest.java @@ -107,6 +107,7 @@ public void setup() { 0, 0, Bytes.EMPTY, + null, Hash.EMPTY, 0, new MainnetBlockHeaderFunctions()); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java index 3d374af116e..124e13399c5 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.ethereum.core; +import org.hyperledger.besu.config.experimental.ExperimentalEIPs; import org.hyperledger.besu.ethereum.rlp.RLPInput; import org.hyperledger.besu.ethereum.rlp.RLPOutput; @@ -53,6 +54,7 @@ public BlockHeader( final long gasUsed, final long timestamp, final Bytes extraData, + final Long baseFee, final Hash mixHash, final long nonce, final BlockHeaderFunctions blockHeaderFunctions) { @@ -69,7 +71,8 @@ public BlockHeader( gasLimit, gasUsed, timestamp, - extraData); + extraData, + baseFee); this.mixHash = mixHash; this.nonce = nonce; this.hash = Suppliers.memoize(() -> blockHeaderFunctions.hash(this)); @@ -142,33 +145,53 @@ public void writeTo(final RLPOutput out) { out.writeBytes(extraData); out.writeBytes(mixHash); out.writeLong(nonce); - + if (ExperimentalEIPs.eip1559Enabled && baseFee != null) { + out.writeLongScalar(baseFee); + } out.endList(); } public static BlockHeader readFrom( final RLPInput input, final BlockHeaderFunctions blockHeaderFunctions) { input.enterList(); - final BlockHeader blockHeader = - new BlockHeader( - Hash.wrap(input.readBytes32()), - Hash.wrap(input.readBytes32()), - Address.readFrom(input), - Hash.wrap(input.readBytes32()), - Hash.wrap(input.readBytes32()), - Hash.wrap(input.readBytes32()), - LogsBloomFilter.readFrom(input), - Difficulty.of(input.readUInt256Scalar()), - input.readLongScalar(), - input.readLongScalar(), - input.readLongScalar(), - input.readLongScalar(), - input.readBytes(), - Hash.wrap(input.readBytes32()), - input.readLong(), - blockHeaderFunctions); + final Hash parentHash = Hash.wrap(input.readBytes32()); + final Hash ommersHash = Hash.wrap(input.readBytes32()); + final Address coinbase = Address.readFrom(input); + final Hash stateRoot = Hash.wrap(input.readBytes32()); + final Hash transactionsRoot = Hash.wrap(input.readBytes32()); + final Hash receiptsRoot = Hash.wrap(input.readBytes32()); + final LogsBloomFilter logsBloom = LogsBloomFilter.readFrom(input); + final Difficulty difficulty = Difficulty.of(input.readUInt256Scalar()); + final long number = input.readLongScalar(); + final long gasLimit = input.readLongScalar(); + final long gasUsed = input.readLongScalar(); + final long timestamp = input.readLongScalar(); + final Bytes extraData = input.readBytes(); + final Hash mixHash = Hash.wrap(input.readBytes32()); + final long nonce = input.readLong(); + final Long baseFee = + ExperimentalEIPs.eip1559Enabled && !input.isEndOfCurrentList() + ? input.readLongScalar() + : null; input.leaveList(); - return blockHeader; + return new BlockHeader( + parentHash, + ommersHash, + coinbase, + stateRoot, + transactionsRoot, + receiptsRoot, + logsBloom, + difficulty, + number, + gasLimit, + gasUsed, + timestamp, + extraData, + baseFee, + mixHash, + nonce, + blockHeaderFunctions); } @Override @@ -206,6 +229,7 @@ public String toString() { sb.append("gasUsed=").append(gasUsed).append(", "); sb.append("timestamp=").append(timestamp).append(", "); sb.append("extraData=").append(extraData).append(", "); + sb.append("baseFee=").append(baseFee).append(", "); sb.append("mixHash=").append(mixHash).append(", "); sb.append("nonce=").append(nonce); return sb.append("}").toString(); @@ -229,6 +253,7 @@ public static org.hyperledger.besu.ethereum.core.BlockHeader convertPluginBlockH pluginBlockHeader.getGasUsed(), pluginBlockHeader.getTimestamp(), pluginBlockHeader.getExtraData(), + pluginBlockHeader.getBaseFee().orElse(null), Hash.fromHexString(pluginBlockHeader.getMixHash().toHexString()), pluginBlockHeader.getNonce(), blockHeaderFunctions); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java index 28179b08437..6a14c2b9bad 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java @@ -52,6 +52,8 @@ public class BlockHeaderBuilder { private Bytes extraData; + private Long baseFee = null; + private Hash mixHash; private BlockHeaderFunctions blockHeaderFunctions; @@ -79,6 +81,7 @@ public static BlockHeaderBuilder fromHeader(final BlockHeader header) { .gasUsed(header.getGasUsed()) .timestamp(header.getTimestamp()) .extraData(header.getExtraData()) + .baseFee(header.getBaseFee().orElse(null)) .mixHash(header.getMixHash()) .nonce(header.getNonce()); } @@ -122,6 +125,7 @@ public BlockHeader buildBlockHeader() { gasUsed, timestamp < 0 ? Instant.now().getEpochSecond() : timestamp, extraData, + baseFee, mixHash, nonce.getAsLong(), blockHeaderFunctions); @@ -150,7 +154,8 @@ public SealableBlockHeader buildSealableBlockHeader() { gasLimit, gasUsed, timestamp, - extraData); + extraData, + baseFee); } private void validateBlockHeader() { @@ -303,4 +308,9 @@ public BlockHeaderBuilder blockHeaderFunctions(final BlockHeaderFunctions blockH this.blockHeaderFunctions = blockHeaderFunctions; return this; } + + public BlockHeaderBuilder baseFee(final Long baseFee) { + this.baseFee = baseFee; + return this; + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SealableBlockHeader.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SealableBlockHeader.java index da55cab0ec4..b501c3f528e 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SealableBlockHeader.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SealableBlockHeader.java @@ -14,6 +14,8 @@ */ package org.hyperledger.besu.ethereum.core; +import java.util.Optional; + import org.apache.tuweni.bytes.Bytes; /** A block header capable of being sealed. */ @@ -31,6 +33,7 @@ public class SealableBlockHeader extends ProcessableBlockHeader { protected final long gasUsed; protected final Bytes extraData; + protected final Long baseFee; protected SealableBlockHeader( final Hash parentHash, @@ -45,7 +48,8 @@ protected SealableBlockHeader( final long gasLimit, final long gasUsed, final long timestamp, - final Bytes extraData) { + final Bytes extraData, + final Long baseFee) { super(parentHash, coinbase, difficulty, number, gasLimit, timestamp); this.ommersHash = ommersHash; this.stateRoot = stateRoot; @@ -54,6 +58,7 @@ protected SealableBlockHeader( this.logsBloom = logsBloom; this.gasUsed = gasUsed; this.extraData = extraData; + this.baseFee = baseFee; } /** @@ -118,4 +123,13 @@ public long getGasUsed() { public Bytes getExtraData() { return extraData; } + + /** + * Returns the basefee of the block. + * + * @return the raw bytes of the extra data field + */ + public Optional getBaseFee() { + return Optional.ofNullable(baseFee); + } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/BlockHeaderMock.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/BlockHeaderMock.java index 0e911b7e021..41da9f84aaf 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/BlockHeaderMock.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/BlockHeaderMock.java @@ -54,6 +54,7 @@ public BlockHeaderMock( 0L, Long.decode(timestamp), Bytes.EMPTY, + 0L, Hash.ZERO, 0L, new MainnetBlockHeaderFunctions()); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTestCaseSpec.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTestCaseSpec.java index abcc45a31ae..93a1506f90c 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTestCaseSpec.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTestCaseSpec.java @@ -152,6 +152,7 @@ public BlockHeaderMock( @JsonProperty("gasUsed") final String gasUsed, @JsonProperty("timestamp") final String timestamp, @JsonProperty("extraData") final String extraData, + @JsonProperty("baseFee") final String baseFee, @JsonProperty("mixHash") final String mixHash, @JsonProperty("nonce") final String nonce, @JsonProperty("hash") final String hash) { @@ -169,6 +170,7 @@ public BlockHeaderMock( Long.decode(gasUsed), // gasUsed Long.decode(timestamp), // timestamp Bytes.fromHexString(extraData), // extraData + baseFee != null ? Long.decode(baseFee) : null, // baseFee Hash.fromHexString(mixHash), // mixHash Bytes.fromHexString(nonce).getLong(0), new BlockHeaderFunctions() { diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index 643e9d93a2e..b7f76de86a9 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -65,7 +65,7 @@ Calculated : ${currentHash} tasks.register('checkAPIChanges', FileStateChecker) { description = "Checks that the API for the Plugin-API project does not change without deliberate thought" files = sourceSets.main.allJava.files - knownHash = 'fL4EQBDRXnw1hiUIUMscLxRG/uWznpZSNJGSIp9+mFo=' + knownHash = 'nUbCiB6FbQJavvvmlnnZBAPWErD7aKyxR+Qpk24ZtrE=' } check.dependsOn('checkAPIChanges') diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockHeader.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockHeader.java index 1cf28920884..12a4a51d8cf 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockHeader.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockHeader.java @@ -14,6 +14,10 @@ */ package org.hyperledger.besu.plugin.data; +import org.hyperledger.besu.plugin.Unstable; + +import java.util.Optional; + import org.apache.tuweni.bytes.Bytes; /** @@ -154,4 +158,14 @@ public interface BlockHeader { * @return The Keccak 256-bit hash of this header. */ Hash getBlockHash(); + + /** + * The BASEFEE of this header. + * + * @return TheBASEFEE of this header. + */ + @Unstable + default Optional getBaseFee() { + return Optional.empty(); + } }