From ac53e3d9536d0c13a6f0071d965b931d3e33dc45 Mon Sep 17 00:00:00 2001 From: Jason Frame Date: Wed, 24 Apr 2019 22:05:09 +1000 Subject: [PATCH] Allow use of large chain ids (#1289) --- .../pegasys/pantheon/config/ConfigUtil.java | 20 ++++++ .../pantheon/config/GenesisConfigOptions.java | 4 +- .../config/JsonGenesisConfigOptions.java | 12 ++-- .../config/StubGenesisConfigOptions.java | 12 ++-- .../config/GenesisConfigFileTest.java | 16 ++++- .../config/GenesisConfigOptionsTest.java | 6 +- .../clique/CliqueProtocolSchedule.java | 4 +- .../consensus/ibft/IbftProtocolSchedule.java | 2 +- .../ibftlegacy/IbftProtocolSchedule.java | 2 +- .../blockcreation/BlockMinerTest.java | 6 +- .../BlockTransactionSelectorTest.java | 3 +- .../EthHashBlockCreatorTest.java | 3 +- .../pantheon/ethereum/core/Transaction.java | 64 ++++++++++--------- .../FixedDifficultyProtocolSchedule.java | 3 - .../mainnet/MainnetProtocolSchedule.java | 3 +- .../mainnet/MainnetProtocolSpecs.java | 15 +++-- .../mainnet/MainnetTransactionValidator.java | 20 ++---- .../mainnet/MutableProtocolSchedule.java | 8 ++- .../ethereum/mainnet/ProtocolSchedule.java | 5 +- .../mainnet/ProtocolScheduleBuilder.java | 26 ++++++-- .../ethereum/core/BlockDataGenerator.java | 7 +- .../core/ExecutionContextTestFixture.java | 3 +- .../ethereum/core/TransactionTestFixture.java | 9 +-- .../core/TransactionIntegrationTest.java | 23 ++++++- .../MainnetTransactionValidatorTest.java | 30 +++++---- .../mainnet/ProtocolScheduleTest.java | 5 +- .../PrivateTransactionHandlerTest.java | 2 +- .../vm/ReferenceTestProtocolSchedules.java | 3 +- .../pantheon/ethereum/vm/VMReferenceTest.java | 4 +- .../jsonrpc/JsonRpcResponseUtils.java | 2 +- .../EthGetFilterChangesIntegrationTest.java | 3 +- .../jsonrpc/internal/methods/EthChainId.java | 9 ++- .../jsonrpc/internal/methods/NetVersion.java | 7 +- .../jsonrpc/internal/results/Quantity.java | 4 ++ .../JsonRpcHttpServiceHostWhitelistTest.java | 5 +- .../jsonrpc/JsonRpcHttpServiceLoginTest.java | 5 +- .../jsonrpc/JsonRpcHttpServiceTest.java | 4 +- .../internal/methods/AdminNodeInfoTest.java | 3 +- .../internal/methods/EthChainIdTest.java | 22 +++++-- .../internal/methods/NetVersionTest.java | 64 +++++++++++++++++++ .../privacy/EeaGetTransactionReceiptTest.java | 2 +- .../privacy/EeaSendRawTransactionTest.java | 2 +- .../pegasys/pantheon/cli/PantheonCommand.java | 6 ++ .../pantheon/cli/PantheonCommandTest.java | 2 +- 44 files changed, 334 insertions(+), 126 deletions(-) create mode 100644 ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/NetVersionTest.java diff --git a/config/src/main/java/tech/pegasys/pantheon/config/ConfigUtil.java b/config/src/main/java/tech/pegasys/pantheon/config/ConfigUtil.java index d8ff3a6f6b..64c40a1e4b 100644 --- a/config/src/main/java/tech/pegasys/pantheon/config/ConfigUtil.java +++ b/config/src/main/java/tech/pegasys/pantheon/config/ConfigUtil.java @@ -12,6 +12,8 @@ */ package tech.pegasys.pantheon.config; +import java.math.BigInteger; +import java.util.Optional; import java.util.OptionalLong; import io.vertx.core.json.JsonObject; @@ -22,4 +24,22 @@ public static OptionalLong getOptionalLong(final JsonObject jsonObject, final St ? OptionalLong.of(jsonObject.getLong(key)) : OptionalLong.empty(); } + + public static Optional getOptionalBigInteger( + final JsonObject jsonObject, final String key) { + return jsonObject.containsKey(key) + ? Optional.ofNullable(getBigInteger(jsonObject, key)) + : Optional.empty(); + } + + private static BigInteger getBigInteger(final JsonObject jsonObject, final String key) { + final Number value = (Number) jsonObject.getMap().get(key); + if (value == null) { + return null; + } else if (value instanceof BigInteger) { + return (BigInteger) value; + } else { + return BigInteger.valueOf(value.longValue()); + } + } } diff --git a/config/src/main/java/tech/pegasys/pantheon/config/GenesisConfigOptions.java b/config/src/main/java/tech/pegasys/pantheon/config/GenesisConfigOptions.java index 302c29c728..3ea897eafe 100644 --- a/config/src/main/java/tech/pegasys/pantheon/config/GenesisConfigOptions.java +++ b/config/src/main/java/tech/pegasys/pantheon/config/GenesisConfigOptions.java @@ -12,7 +12,9 @@ */ package tech.pegasys.pantheon.config; +import java.math.BigInteger; import java.util.Map; +import java.util.Optional; import java.util.OptionalInt; import java.util.OptionalLong; @@ -48,7 +50,7 @@ public interface GenesisConfigOptions { OptionalLong getConstantinopleFixBlockNumber(); - OptionalInt getChainId(); + Optional getChainId(); OptionalInt getContractSizeLimit(); diff --git a/config/src/main/java/tech/pegasys/pantheon/config/JsonGenesisConfigOptions.java b/config/src/main/java/tech/pegasys/pantheon/config/JsonGenesisConfigOptions.java index 745989fa41..7034ba0933 100644 --- a/config/src/main/java/tech/pegasys/pantheon/config/JsonGenesisConfigOptions.java +++ b/config/src/main/java/tech/pegasys/pantheon/config/JsonGenesisConfigOptions.java @@ -12,7 +12,11 @@ */ package tech.pegasys.pantheon.config; +import static tech.pegasys.pantheon.config.ConfigUtil.getOptionalBigInteger; + +import java.math.BigInteger; import java.util.Map; +import java.util.Optional; import java.util.OptionalInt; import java.util.OptionalLong; @@ -119,10 +123,8 @@ public OptionalLong getConstantinopleFixBlockNumber() { } @Override - public OptionalInt getChainId() { - return configRoot.containsKey("chainid") - ? OptionalInt.of(configRoot.getInteger("chainid")) - : OptionalInt.empty(); + public Optional getChainId() { + return getOptionalBigInteger(configRoot, "chainid"); } @Override @@ -135,7 +137,7 @@ public OptionalInt getContractSizeLimit() { @Override public Map asMap() { final ImmutableMap.Builder builder = ImmutableMap.builder(); - builder.put("chainId", getChainId().getAsInt()); + getChainId().ifPresent(chainId -> builder.put("chainId", chainId)); getHomesteadBlockNumber().ifPresent(l -> builder.put("homesteadBlock", l)); getDaoForkBlock() .ifPresent( diff --git a/config/src/test-support/java/tech/pegasys/pantheon/config/StubGenesisConfigOptions.java b/config/src/test-support/java/tech/pegasys/pantheon/config/StubGenesisConfigOptions.java index 0e58ef3b50..e06543dd76 100644 --- a/config/src/test-support/java/tech/pegasys/pantheon/config/StubGenesisConfigOptions.java +++ b/config/src/test-support/java/tech/pegasys/pantheon/config/StubGenesisConfigOptions.java @@ -12,7 +12,9 @@ */ package tech.pegasys.pantheon.config; +import java.math.BigInteger; import java.util.Map; +import java.util.Optional; import java.util.OptionalInt; import java.util.OptionalLong; @@ -27,7 +29,7 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions { private OptionalLong byzantiumBlockNumber = OptionalLong.empty(); private OptionalLong constantinopleBlockNumber = OptionalLong.empty(); private OptionalLong constantinopleFixBlockNumber = OptionalLong.empty(); - private OptionalInt chainId = OptionalInt.empty(); + private Optional chainId = Optional.empty(); private OptionalInt contractSizeLimit = OptionalInt.empty(); @Override @@ -111,14 +113,14 @@ public OptionalInt getContractSizeLimit() { } @Override - public OptionalInt getChainId() { + public Optional getChainId() { return chainId; } @Override public Map asMap() { final ImmutableMap.Builder builder = ImmutableMap.builder(); - builder.put("chainId", getChainId().getAsInt()); + getChainId().ifPresent(chainId -> builder.put("chainId", chainId)); getHomesteadBlockNumber().ifPresent(l -> builder.put("homesteadBlock", l)); getDaoForkBlock() .ifPresent( @@ -187,8 +189,8 @@ public StubGenesisConfigOptions constantinopleFixBlock(final long blockNumber) { return this; } - public StubGenesisConfigOptions chainId(final int chainId) { - this.chainId = OptionalInt.of(chainId); + public StubGenesisConfigOptions chainId(final BigInteger chainId) { + this.chainId = Optional.ofNullable(chainId); return this; } diff --git a/config/src/test/java/tech/pegasys/pantheon/config/GenesisConfigFileTest.java b/config/src/test/java/tech/pegasys/pantheon/config/GenesisConfigFileTest.java index e58ab8517b..fcfc757306 100644 --- a/config/src/test/java/tech/pegasys/pantheon/config/GenesisConfigFileTest.java +++ b/config/src/test/java/tech/pegasys/pantheon/config/GenesisConfigFileTest.java @@ -16,6 +16,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.entry; +import java.math.BigInteger; import java.util.Map; import java.util.stream.Collectors; @@ -24,8 +25,8 @@ public class GenesisConfigFileTest { - private static final int MAINNET_CHAIN_ID = 1; - private static final int DEVELOPMENT_CHAIN_ID = 2018; + private static final BigInteger MAINNET_CHAIN_ID = BigInteger.ONE; + private static final BigInteger DEVELOPMENT_CHAIN_ID = BigInteger.valueOf(2018); private static final GenesisConfigFile EMPTY_CONFIG = GenesisConfigFile.fromConfig("{}"); @Test @@ -170,6 +171,17 @@ public void shouldGetEmptyAllocationsWhenAllocNotPresent() { assertThat(config.getAllocations()).isEmpty(); } + @Test + public void shouldGetLargeChainId() { + final GenesisConfigFile config = + GenesisConfigFile.fromConfig( + "{\"config\": { \"chainId\": 31415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095 }}"); + assertThat(config.getConfigOptions().getChainId()) + .contains( + new BigInteger( + "31415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095")); + } + private GenesisConfigFile configWithProperty(final String key, final String value) { return GenesisConfigFile.fromConfig("{\"" + key + "\":\"" + value + "\"}"); } diff --git a/config/src/test/java/tech/pegasys/pantheon/config/GenesisConfigOptionsTest.java b/config/src/test/java/tech/pegasys/pantheon/config/GenesisConfigOptionsTest.java index ba039b7795..fb72260af2 100644 --- a/config/src/test/java/tech/pegasys/pantheon/config/GenesisConfigOptionsTest.java +++ b/config/src/test/java/tech/pegasys/pantheon/config/GenesisConfigOptionsTest.java @@ -16,6 +16,7 @@ import static java.util.Collections.singletonMap; import static org.assertj.core.api.Assertions.assertThat; +import java.math.BigInteger; import java.util.Collections; import java.util.Map; @@ -128,8 +129,9 @@ public void shouldNotReturnEmptyOptionalWhenBlockNumberNotSpecified() { @Test public void shouldGetChainIdWhenSpecified() { - final GenesisConfigOptions config = fromConfigOptions(singletonMap("chainId", 32)); - assertThat(config.getChainId()).hasValue(32); + final GenesisConfigOptions config = + fromConfigOptions(singletonMap("chainId", BigInteger.valueOf(32))); + assertThat(config.getChainId()).hasValue(BigInteger.valueOf(32)); } @Test diff --git a/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolSchedule.java b/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolSchedule.java index eb96d72a1a..68b2159d6f 100644 --- a/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolSchedule.java +++ b/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolSchedule.java @@ -29,10 +29,12 @@ import tech.pegasys.pantheon.ethereum.mainnet.ProtocolScheduleBuilder; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpecBuilder; +import java.math.BigInteger; + /** Defines the protocol behaviours for a blockchain using Clique. */ public class CliqueProtocolSchedule { - private static final int DEFAULT_CHAIN_ID = 4; + private static final BigInteger DEFAULT_CHAIN_ID = BigInteger.valueOf(4); public static ProtocolSchedule create( final GenesisConfigOptions config, diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftProtocolSchedule.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftProtocolSchedule.java index 269f857a6e..4ed451415d 100644 --- a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftProtocolSchedule.java +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/IbftProtocolSchedule.java @@ -30,7 +30,7 @@ /** Defines the protocol behaviours for a blockchain using IBFT. */ public class IbftProtocolSchedule { - private static final int DEFAULT_CHAIN_ID = 1; + private static final BigInteger DEFAULT_CHAIN_ID = BigInteger.ONE; public static ProtocolSchedule create( final GenesisConfigOptions config, final PrivacyParameters privacyParameters) { diff --git a/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftProtocolSchedule.java b/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftProtocolSchedule.java index ec7064d074..3bdfe84043 100644 --- a/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftProtocolSchedule.java +++ b/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftProtocolSchedule.java @@ -31,7 +31,7 @@ /** Defines the protocol behaviours for a blockchain using IBFT. */ public class IbftProtocolSchedule { - private static final int DEFAULT_CHAIN_ID = 1; + private static final BigInteger DEFAULT_CHAIN_ID = BigInteger.ONE; public static ProtocolSchedule create( final GenesisConfigOptions config, final PrivacyParameters privacyParameters) { diff --git a/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/BlockMinerTest.java b/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/BlockMinerTest.java index aa4d10a210..e1b18a9741 100644 --- a/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/BlockMinerTest.java +++ b/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/BlockMinerTest.java @@ -31,6 +31,9 @@ import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpec; import tech.pegasys.pantheon.util.Subscribers; +import java.math.BigInteger; +import java.util.Optional; + import com.google.common.collect.Lists; import org.junit.Test; @@ -124,7 +127,8 @@ private static Subscribers subscribersContaining( } private ProtocolSchedule singleSpecSchedule(final ProtocolSpec protocolSpec) { - final MutableProtocolSchedule protocolSchedule = new MutableProtocolSchedule<>(1234); + final MutableProtocolSchedule protocolSchedule = + new MutableProtocolSchedule<>(Optional.of(BigInteger.valueOf(1234))); protocolSchedule.putMilestone(0, protocolSpec); return protocolSchedule; } diff --git a/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/BlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/BlockTransactionSelectorTest.java index 91d7bc7285..b32f2046ed 100644 --- a/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/BlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/BlockTransactionSelectorTest.java @@ -52,6 +52,7 @@ import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.uint.UInt256; +import java.math.BigInteger; import java.time.Instant; import java.util.List; import java.util.function.Supplier; @@ -567,7 +568,7 @@ private Transaction createTransaction(final int transactionNumber) { .to(Address.ID) .value(Wei.of(transactionNumber)) .sender(Address.ID) - .chainId(1) + .chainId(BigInteger.ONE) .signAndBuild(keyPair); } diff --git a/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockCreatorTest.java b/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockCreatorTest.java index 6384bf4354..447cf23e61 100644 --- a/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockCreatorTest.java +++ b/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockCreatorTest.java @@ -29,6 +29,7 @@ import tech.pegasys.pantheon.util.bytes.BytesValue; import java.io.IOException; +import java.math.BigInteger; import java.util.function.Function; import com.google.common.collect.Lists; @@ -53,7 +54,7 @@ public class EthHashBlockCreatorTest { .protocolSchedule( new ProtocolScheduleBuilder<>( GenesisConfigFile.DEFAULT.getConfigOptions(), - 42, + BigInteger.valueOf(42), Function.identity(), PrivacyParameters.DEFAULT) .createProtocolSchedule()) diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Transaction.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Transaction.java index 4fa9b700fc..c403908c1c 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Transaction.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Transaction.java @@ -28,20 +28,22 @@ import java.math.BigInteger; import java.util.Objects; import java.util.Optional; -import java.util.OptionalInt; /** An operation submitted by an external actor to be applied to the system. */ public class Transaction { // Used for transactions that are not tied to a specific chain // (e.g. does not have a chain id associated with it). - private static final int REPLAY_UNPROTECTED_V_BASE = 27; + private static final BigInteger REPLAY_UNPROTECTED_V_BASE = BigInteger.valueOf(27); + private static final BigInteger REPLAY_UNPROTECTED_V_BASE_PLUS_1 = BigInteger.valueOf(28); - private static final int REPLAY_PROTECTED_V_BASE = 35; + private static final BigInteger REPLAY_PROTECTED_V_BASE = BigInteger.valueOf(35); // The v signature parameter starts at 36 because 1 is the first valid chainId so: // chainId > 1 implies that 2 * chainId + V_BASE > 36. - private static final int REPLAY_PROTECTED_V_MIN = 36; + private static final BigInteger REPLAY_PROTECTED_V_MIN = BigInteger.valueOf(36); + + private static final BigInteger TWO = BigInteger.valueOf(2); private final long nonce; @@ -57,7 +59,7 @@ public class Transaction { private final BytesValue payload; - private final OptionalInt chainId; + private final Optional chainId; // Caches a "hash" of a portion of the transaction used for sender recovery. // Note that this hash does not include the transaction signature so it does not @@ -87,14 +89,14 @@ public static Transaction readFrom(final RLPInput input) throws RLPException { .value(input.readUInt256Scalar(Wei::wrap)) .payload(input.readBytesValue()); - final int v = input.readIntScalar(); + final BigInteger v = input.readBigIntegerScalar(); final byte recId; - int chainId = -1; - if (v == REPLAY_UNPROTECTED_V_BASE || v == REPLAY_UNPROTECTED_V_BASE + 1) { - recId = (byte) (v - REPLAY_UNPROTECTED_V_BASE); - } else if (v > REPLAY_PROTECTED_V_MIN) { - chainId = (v - REPLAY_PROTECTED_V_BASE) / 2; - recId = (byte) (v - (2 * chainId + REPLAY_PROTECTED_V_BASE)); + Optional chainId = Optional.empty(); + if (v.equals(REPLAY_UNPROTECTED_V_BASE) || v.equals(REPLAY_UNPROTECTED_V_BASE_PLUS_1)) { + recId = v.subtract(REPLAY_UNPROTECTED_V_BASE).byteValueExact(); + } else if (v.compareTo(REPLAY_PROTECTED_V_MIN) > 0) { + chainId = Optional.of(v.subtract(REPLAY_PROTECTED_V_BASE).divide(TWO)); + recId = v.subtract(TWO.multiply(chainId.get()).add(REPLAY_PROTECTED_V_BASE)).byteValueExact(); } else { throw new RuntimeException( String.format("An unsupported encoded `v` value of %s was found", v)); @@ -105,7 +107,8 @@ public static Transaction readFrom(final RLPInput input) throws RLPException { input.leaveList(); - return builder.chainId(chainId).signature(signature).build(); + chainId.ifPresent(builder::chainId); + return builder.signature(signature).build(); } /** @@ -134,7 +137,7 @@ public Transaction( final SECP256K1.Signature signature, final BytesValue payload, final Address sender, - final int chainId) { + final Optional chainId) { this.nonce = nonce; this.gasPrice = gasPrice; this.gasLimit = gasLimit; @@ -143,7 +146,7 @@ public Transaction( this.signature = signature; this.payload = payload; this.sender = sender; - this.chainId = chainId > 0 ? OptionalInt.of(chainId) : OptionalInt.empty(); + this.chainId = chainId; } /** @@ -220,7 +223,7 @@ public BytesValue getPayload() { * * @return the transaction chain id if it exists; otherwise {@code OptionalInt.empty()} */ - public OptionalInt getChainId() { + public Optional getChainId() { return chainId; } @@ -246,7 +249,7 @@ private Bytes32 getOrComputeSenderRecoveryHash() { if (hashNoSignature == null) { hashNoSignature = computeSenderRecoveryHash( - nonce, gasPrice, gasLimit, to.isPresent() ? to.get() : null, value, payload, chainId); + nonce, gasPrice, gasLimit, to.orElse(null), value, payload, chainId); } return hashNoSignature; } @@ -271,7 +274,7 @@ public void writeTo(final RLPOutput out) { } private void writeSignature(final RLPOutput out) { - out.writeIntScalar(getV()); + out.writeBigIntegerScalar(getV()); out.writeBigIntegerScalar(getSignature().getR()); out.writeBigIntegerScalar(getSignature().getS()); } @@ -284,12 +287,13 @@ public BigInteger getS() { return signature.getS(); } - public int getV() { - final int v; + public BigInteger getV() { + final BigInteger v; + final BigInteger recId = BigInteger.valueOf(signature.getRecId()); if (!chainId.isPresent()) { - v = signature.getRecId() + REPLAY_UNPROTECTED_V_BASE; + v = recId.add(REPLAY_UNPROTECTED_V_BASE); } else { - v = (getSignature().getRecId() + REPLAY_PROTECTED_V_BASE + 2 * chainId.getAsInt()); + v = recId.add(REPLAY_PROTECTED_V_BASE).add(TWO.multiply(chainId.get())); } return v; } @@ -345,7 +349,7 @@ private static Bytes32 computeSenderRecoveryHash( final Address to, final Wei value, final BytesValue payload, - final OptionalInt chainId) { + final Optional chainId) { return keccak256( RLP.encode( out -> { @@ -357,7 +361,7 @@ private static Bytes32 computeSenderRecoveryHash( out.writeUInt256Scalar(value); out.writeBytesValue(payload); if (chainId.isPresent()) { - out.writeIntScalar(chainId.getAsInt()); + out.writeBigIntegerScalar(chainId.get()); out.writeUInt256Scalar(UInt256.ZERO); out.writeUInt256Scalar(UInt256.ZERO); } @@ -396,7 +400,7 @@ public String toString() { if (getTo().isPresent()) sb.append("to=").append(getTo().get()).append(", "); sb.append("value=").append(getValue()).append(", "); sb.append("sig=").append(getSignature()).append(", "); - if (chainId.isPresent()) sb.append("chainId=").append(getChainId().getAsInt()).append(", "); + if (chainId.isPresent()) sb.append("chainId=").append(getChainId().get()).append(", "); sb.append("payload=").append(getPayload()); return sb.append("}").toString(); } @@ -426,10 +430,10 @@ public static class Builder { protected Address sender; - protected int chainId = -1; + protected Optional chainId = Optional.empty(); - public Builder chainId(final int chainId) { - this.chainId = chainId; + public Builder chainId(final BigInteger chainId) { + this.chainId = Optional.of(chainId); return this; } @@ -495,10 +499,8 @@ public Transaction signAndBuild(final SECP256K1.KeyPair keys) { } protected SECP256K1.Signature computeSignature(final SECP256K1.KeyPair keys) { - final OptionalInt optionalChainId = - chainId > 0 ? OptionalInt.of(chainId) : OptionalInt.empty(); final Bytes32 hash = - computeSenderRecoveryHash(nonce, gasPrice, gasLimit, to, value, payload, optionalChainId); + computeSenderRecoveryHash(nonce, gasPrice, gasLimit, to, value, payload, chainId); return SECP256K1.sign(hash, keys); } } diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/difficulty/fixed/FixedDifficultyProtocolSchedule.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/difficulty/fixed/FixedDifficultyProtocolSchedule.java index 50ab59dc63..24a30ab34b 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/difficulty/fixed/FixedDifficultyProtocolSchedule.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/difficulty/fixed/FixedDifficultyProtocolSchedule.java @@ -12,8 +12,6 @@ */ package tech.pegasys.pantheon.ethereum.difficulty.fixed; -import static tech.pegasys.pantheon.ethereum.mainnet.MainnetTransactionValidator.NO_CHAIN_ID; - import tech.pegasys.pantheon.config.GenesisConfigOptions; import tech.pegasys.pantheon.ethereum.core.PrivacyParameters; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; @@ -26,7 +24,6 @@ public static ProtocolSchedule create( final GenesisConfigOptions config, final PrivacyParameters privacyParameters) { return new ProtocolScheduleBuilder<>( config, - NO_CHAIN_ID, builder -> builder.difficultyCalculator(FixedDifficultyCalculators.calculator(config)), privacyParameters) .createProtocolSchedule(); diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSchedule.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSchedule.java index 7a4d1a9209..cb0005f985 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSchedule.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSchedule.java @@ -18,12 +18,13 @@ import tech.pegasys.pantheon.ethereum.difficulty.fixed.FixedDifficultyCalculators; import tech.pegasys.pantheon.ethereum.difficulty.fixed.FixedDifficultyProtocolSchedule; +import java.math.BigInteger; import java.util.function.Function; /** Provides {@link ProtocolSpec} lookups for mainnet hard forks. */ public class MainnetProtocolSchedule { - public static final int DEFAULT_CHAIN_ID = 1; + public static final BigInteger DEFAULT_CHAIN_ID = BigInteger.ONE; public static ProtocolSchedule create() { return fromConfig(GenesisConfigFile.mainnet().getConfigOptions(), PrivacyParameters.DEFAULT); diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSpecs.java index 96f45d326b..fe96d6cf51 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSpecs.java @@ -26,8 +26,10 @@ import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionProcessor; import java.io.IOException; +import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.Optional; import java.util.OptionalInt; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -73,7 +75,8 @@ public static ProtocolSpecBuilder frontierDefinition( new MainnetContractCreationProcessor( gasCalculator, evm, false, contractSizeLimit, 0)) .transactionValidatorBuilder( - gasCalculator -> new MainnetTransactionValidator(gasCalculator, false)) + gasCalculator -> + new MainnetTransactionValidator(gasCalculator, false, Optional.empty())) .transactionProcessorBuilder( (gasCalculator, transactionValidator, @@ -122,7 +125,7 @@ public static ProtocolSpecBuilder homesteadDefinition( new MainnetContractCreationProcessor( gasCalculator, evm, true, contractSizeLimit, 0)) .transactionValidatorBuilder( - gasCalculator -> new MainnetTransactionValidator(gasCalculator, true)) + gasCalculator -> new MainnetTransactionValidator(gasCalculator, true, Optional.empty())) .difficultyCalculator(MainnetDifficultyCalculators.HOMESTEAD) .name("Homestead"); } @@ -160,7 +163,7 @@ public static ProtocolSpecBuilder tangerineWhistleDefinition( } public static ProtocolSpecBuilder spuriousDragonDefinition( - final int chainId, final OptionalInt configContractSizeLimit) { + final Optional chainId, final OptionalInt configContractSizeLimit) { final int contractSizeLimit = configContractSizeLimit.orElse(SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT); return tangerineWhistleDefinition(OptionalInt.empty()) @@ -208,7 +211,7 @@ public static ProtocolSpecBuilder spuriousDragonDefinition( } public static ProtocolSpecBuilder byzantiumDefinition( - final int chainId, final OptionalInt contractSizeLimit) { + final Optional chainId, final OptionalInt contractSizeLimit) { return spuriousDragonDefinition(chainId, contractSizeLimit) .evmBuilder(MainnetEvmRegistries::byzantium) .precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::byzantium) @@ -220,7 +223,7 @@ public static ProtocolSpecBuilder byzantiumDefinition( } public static ProtocolSpecBuilder constantinopleDefinition( - final int chainId, final OptionalInt contractSizeLimit) { + final Optional chainId, final OptionalInt contractSizeLimit) { return byzantiumDefinition(chainId, contractSizeLimit) .difficultyCalculator(MainnetDifficultyCalculators.CONSTANTINOPLE) .gasCalculator(ConstantinopleGasCalculator::new) @@ -230,7 +233,7 @@ public static ProtocolSpecBuilder constantinopleDefinition( } public static ProtocolSpecBuilder constantinopleFixDefinition( - final int chainId, final OptionalInt contractSizeLimit) { + final Optional chainId, final OptionalInt contractSizeLimit) { return constantinopleDefinition(chainId, contractSizeLimit) .gasCalculator(ConstantinopleFixGasCalculator::new) .name("ConstantinopleFix"); diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetTransactionValidator.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetTransactionValidator.java index f90a53ad2f..4c6f608937 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetTransactionValidator.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetTransactionValidator.java @@ -27,7 +27,8 @@ import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.vm.GasCalculator; -import java.util.OptionalInt; +import java.math.BigInteger; +import java.util.Optional; /** * Validates a transaction based on Frontier protocol runtime requirements. @@ -37,30 +38,23 @@ */ public class MainnetTransactionValidator implements TransactionValidator { - public static final int NO_CHAIN_ID = -1; - public static MainnetTransactionValidator create() { - return new MainnetTransactionValidator(new FrontierGasCalculator(), false); + return new MainnetTransactionValidator(new FrontierGasCalculator(), false, Optional.empty()); } private final GasCalculator gasCalculator; private final boolean disallowSignatureMalleability; - private final OptionalInt chainId; - - public MainnetTransactionValidator( - final GasCalculator gasCalculator, final boolean checkSignatureMalleability) { - this(gasCalculator, checkSignatureMalleability, NO_CHAIN_ID); - } + private final Optional chainId; public MainnetTransactionValidator( final GasCalculator gasCalculator, final boolean checkSignatureMalleability, - final int chainId) { + final Optional chainId) { this.gasCalculator = gasCalculator; this.disallowSignatureMalleability = checkSignatureMalleability; - this.chainId = chainId > 0 ? OptionalInt.of(chainId) : OptionalInt.empty(); + this.chainId = chainId; } @Override @@ -130,7 +124,7 @@ public ValidationResult validateTransactionSignature( WRONG_CHAIN_ID, String.format( "transaction was meant for chain id %s and not this chain id %s", - transaction.getChainId().getAsInt(), chainId.getAsInt())); + transaction.getChainId().get(), chainId.get())); } if (!chainId.isPresent() && transaction.getChainId().isPresent()) { diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MutableProtocolSchedule.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MutableProtocolSchedule.java index 6a52b490a2..ee195947bd 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MutableProtocolSchedule.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MutableProtocolSchedule.java @@ -14,8 +14,10 @@ import static com.google.common.base.Preconditions.checkArgument; +import java.math.BigInteger; import java.util.Comparator; import java.util.NavigableSet; +import java.util.Optional; import java.util.TreeSet; import java.util.stream.Collectors; @@ -25,14 +27,14 @@ public class MutableProtocolSchedule implements ProtocolSchedule { new TreeSet<>( Comparator., Long>comparing(ScheduledProtocolSpec::getBlock) .reversed()); - private final int chainId; + private final Optional chainId; - public MutableProtocolSchedule(final int chainId) { + public MutableProtocolSchedule(final Optional chainId) { this.chainId = chainId; } @Override - public int getChainId() { + public Optional getChainId() { return chainId; } diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolSchedule.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolSchedule.java index 6d53b22d30..12f0e71b9e 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolSchedule.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolSchedule.java @@ -12,9 +12,12 @@ */ package tech.pegasys.pantheon.ethereum.mainnet; +import java.math.BigInteger; +import java.util.Optional; + public interface ProtocolSchedule { ProtocolSpec getByBlockNumber(long number); - int getChainId(); + Optional getChainId(); } diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolScheduleBuilder.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolScheduleBuilder.java index 292342d404..fa691d3f39 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolScheduleBuilder.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolScheduleBuilder.java @@ -15,6 +15,8 @@ import tech.pegasys.pantheon.config.GenesisConfigOptions; import tech.pegasys.pantheon.ethereum.core.PrivacyParameters; +import java.math.BigInteger; +import java.util.Optional; import java.util.OptionalLong; import java.util.function.Function; @@ -25,22 +27,38 @@ public class ProtocolScheduleBuilder { private static final Logger LOG = LogManager.getLogger(); private final GenesisConfigOptions config; private final Function, ProtocolSpecBuilder> protocolSpecAdapter; - private final int defaultChainId; + private final Optional defaultChainId; private final PrivacyParameters privacyParameters; public ProtocolScheduleBuilder( final GenesisConfigOptions config, - final int defaultChainId, + final BigInteger defaultChainId, + final Function, ProtocolSpecBuilder> protocolSpecAdapter, + final PrivacyParameters privacyParameters) { + this(config, Optional.of(defaultChainId), protocolSpecAdapter, privacyParameters); + } + + public ProtocolScheduleBuilder( + final GenesisConfigOptions config, + final Function, ProtocolSpecBuilder> protocolSpecAdapter, + final PrivacyParameters privacyParameters) { + this(config, Optional.empty(), protocolSpecAdapter, privacyParameters); + } + + private ProtocolScheduleBuilder( + final GenesisConfigOptions config, + final Optional defaultChainId, final Function, ProtocolSpecBuilder> protocolSpecAdapter, final PrivacyParameters privacyParameters) { this.config = config; - this.protocolSpecAdapter = protocolSpecAdapter; this.defaultChainId = defaultChainId; + this.protocolSpecAdapter = protocolSpecAdapter; this.privacyParameters = privacyParameters; } public ProtocolSchedule createProtocolSchedule() { - final int chainId = config.getChainId().orElse(defaultChainId); + final Optional chainId = + config.getChainId().map(Optional::of).orElse(defaultChainId); final MutableProtocolSchedule protocolSchedule = new MutableProtocolSchedule<>(chainId); validateForkOrdering(); diff --git a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/BlockDataGenerator.java b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/BlockDataGenerator.java index 2a0c404589..c3a4171766 100644 --- a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/BlockDataGenerator.java +++ b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/BlockDataGenerator.java @@ -23,6 +23,7 @@ import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.uint.UInt256; +import java.math.BigInteger; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.ArrayList; @@ -252,7 +253,7 @@ public Transaction transaction(final BytesValue payload) { .to(address()) .value(Wei.wrap(bytes32())) .payload(payload) - .chainId(1) + .chainId(BigInteger.ONE) .signAndBuild(SECP256K1.KeyPair.generate()); } @@ -264,7 +265,7 @@ public Transaction transaction() { .to(address()) .value(Wei.wrap(bytes32())) .payload(bytes32()) - .chainId(1) + .chainId(BigInteger.ONE) .signAndBuild(SECP256K1.KeyPair.generate()); } @@ -291,7 +292,7 @@ public Set transactions(final int n) { signature, payload, to, - chainId)) + Optional.of(BigInteger.valueOf(chainId)))) .collect(toSet()); return txs; } diff --git a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java index 073e45fd02..2626bffe22 100644 --- a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java +++ b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java @@ -28,6 +28,7 @@ import tech.pegasys.pantheon.services.kvstore.InMemoryKeyValueStorage; import tech.pegasys.pantheon.services.kvstore.KeyValueStorage; +import java.math.BigInteger; import java.util.function.Function; public class ExecutionContextTestFixture { @@ -111,7 +112,7 @@ public ExecutionContextTestFixture build() { protocolSchedule = new ProtocolScheduleBuilder<>( new StubGenesisConfigOptions().constantinopleFixBlock(0), - 42, + BigInteger.valueOf(42), Function.identity(), new PrivacyParameters()) .createProtocolSchedule(); diff --git a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/TransactionTestFixture.java b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/TransactionTestFixture.java index 8855c7f7c1..dd14d0f912 100644 --- a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/TransactionTestFixture.java +++ b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/TransactionTestFixture.java @@ -15,6 +15,7 @@ import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.util.bytes.BytesValue; +import java.math.BigInteger; import java.util.Optional; public class TransactionTestFixture { @@ -32,7 +33,7 @@ public class TransactionTestFixture { private BytesValue payload = BytesValue.EMPTY; - private int chainId = 2018; + private Optional chainId = Optional.of(BigInteger.valueOf(2018)); public Transaction createTransaction(final KeyPair keys) { final Transaction.Builder builder = Transaction.builder(); @@ -42,10 +43,10 @@ public Transaction createTransaction(final KeyPair keys) { .nonce(nonce) .payload(payload) .value(value) - .sender(sender) - .chainId(chainId); + .sender(sender); to.ifPresent(builder::to); + chainId.ifPresent(builder::chainId); return builder.signAndBuild(keys); } @@ -85,7 +86,7 @@ public TransactionTestFixture payload(final BytesValue payload) { return this; } - public TransactionTestFixture chainId(final int chainId) { + public TransactionTestFixture chainId(final Optional chainId) { this.chainId = chainId; return this; } diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/core/TransactionIntegrationTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/core/TransactionIntegrationTest.java index 5563c818c8..96983f4e13 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/core/TransactionIntegrationTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/core/TransactionIntegrationTest.java @@ -13,6 +13,7 @@ package tech.pegasys.pantheon.ethereum.core; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -21,6 +22,8 @@ import tech.pegasys.pantheon.ethereum.rlp.RLPInput; import tech.pegasys.pantheon.util.bytes.BytesValue; +import java.math.BigInteger; + import org.junit.Test; public class TransactionIntegrationTest { @@ -35,7 +38,7 @@ public class TransactionIntegrationTest { final Transaction transaction = Transaction.readFrom(input); assertNotNull(transaction); assertTrue(transaction.isContractCreation()); - assertEquals(2018, transaction.getChainId().getAsInt()); + assertEquals(BigInteger.valueOf(2018), transaction.getChainId().get()); assertEquals( Address.fromHexString("0xfe3b557e8fb62b89f4916b721be55ceb828dbd73"), transaction.getSender()); @@ -52,4 +55,22 @@ public void shouldDecodeAndEncodeTransactionCorrectly() { transaction.writeTo(output); assertEquals(encodedString, output.encoded().toString()); } + + @Test + public void shouldDecodeTransactionWithLargeChainId() { + final String encodedString = + "0xf86a018609184e72a0008276c094d30c3d13b07029deba00de1da369cd69a02c20560180850100000021a07d344f26d7329e8932d2878b99f07b12752bbd13a0b3b822644dbf9600fe718da01d6e6b6c66e1aadf4e33e318a7eef03d3bd3602de52662f0cb5af5b372d44dcd"; + final BytesValue encoded = BytesValue.fromHexString(encodedString); + final RLPInput input = RLP.input(encoded); + final Transaction transaction = Transaction.readFrom(input); + assertNotNull(transaction); + assertFalse(transaction.isContractCreation()); + assertEquals(BigInteger.valueOf(2147483647), transaction.getChainId().get()); + assertEquals( + Address.fromHexString("0xdf664d0d2270ef97b48f222e3187bd14c8ca9428"), + transaction.getSender()); + assertEquals( + Address.fromHexString("0xd30c3d13b07029deba00de1da369cd69a02c2056"), + transaction.getTo().get()); + } } diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetTransactionValidatorTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetTransactionValidatorTest.java index 51794408d9..0f84ad6f18 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetTransactionValidatorTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetTransactionValidatorTest.java @@ -31,6 +31,9 @@ import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.vm.GasCalculator; +import java.math.BigInteger; +import java.util.Optional; + import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -44,14 +47,19 @@ public class MainnetTransactionValidatorTest { @Mock private GasCalculator gasCalculator; private final Transaction basicTransaction = - new TransactionTestFixture().chainId(1).createTransaction(senderKeys); + new TransactionTestFixture() + .chainId(Optional.of(BigInteger.ONE)) + .createTransaction(senderKeys); @Test public void shouldRejectTransactionIfIntrinsicGasExceedsGasLimit() { final MainnetTransactionValidator validator = - new MainnetTransactionValidator(gasCalculator, false); + new MainnetTransactionValidator(gasCalculator, false, Optional.empty()); final Transaction transaction = - new TransactionTestFixture().gasLimit(10).chainId(0).createTransaction(senderKeys); + new TransactionTestFixture() + .gasLimit(10) + .chainId(Optional.empty()) + .createTransaction(senderKeys); when(gasCalculator.transactionIntrinsicGasCost(transaction)).thenReturn(Gas.of(50)); assertThat(validator.validate(transaction)) @@ -61,7 +69,7 @@ public void shouldRejectTransactionIfIntrinsicGasExceedsGasLimit() { @Test public void shouldRejectTransactionWhenTransactionHasChainIdAndValidatorDoesNot() { final MainnetTransactionValidator validator = - new MainnetTransactionValidator(gasCalculator, false); + new MainnetTransactionValidator(gasCalculator, false, Optional.empty()); assertThat(validator.validate(basicTransaction)) .isEqualTo(ValidationResult.invalid(REPLAY_PROTECTED_SIGNATURES_NOT_SUPPORTED)); } @@ -69,7 +77,7 @@ public void shouldRejectTransactionWhenTransactionHasChainIdAndValidatorDoesNot( @Test public void shouldRejectTransactionWhenTransactionHasIncorrectChainId() { final MainnetTransactionValidator validator = - new MainnetTransactionValidator(gasCalculator, false, 2); + new MainnetTransactionValidator(gasCalculator, false, Optional.of(BigInteger.valueOf(2))); assertThat(validator.validate(basicTransaction)) .isEqualTo(ValidationResult.invalid(WRONG_CHAIN_ID)); } @@ -77,7 +85,7 @@ public void shouldRejectTransactionWhenTransactionHasIncorrectChainId() { @Test public void shouldRejectTransactionWhenSenderAccountDoesNotExist() { final MainnetTransactionValidator validator = - new MainnetTransactionValidator(gasCalculator, false, 1); + new MainnetTransactionValidator(gasCalculator, false, Optional.of(BigInteger.ONE)); assertThat(validator.validateForSender(basicTransaction, null, false)) .isEqualTo(ValidationResult.invalid(UPFRONT_COST_EXCEEDS_BALANCE)); } @@ -85,7 +93,7 @@ public void shouldRejectTransactionWhenSenderAccountDoesNotExist() { @Test public void shouldRejectTransactionWhenTransactionNonceBelowAccountNonce() { final MainnetTransactionValidator validator = - new MainnetTransactionValidator(gasCalculator, false, 1); + new MainnetTransactionValidator(gasCalculator, false, Optional.of(BigInteger.ONE)); final Account account = accountWithNonce(basicTransaction.getNonce() + 1); assertThat(validator.validateForSender(basicTransaction, account, false)) @@ -96,7 +104,7 @@ public void shouldRejectTransactionWhenTransactionNonceBelowAccountNonce() { public void shouldRejectTransactionWhenTransactionNonceAboveAccountNonceAndFutureNonceIsNotAllowed() { final MainnetTransactionValidator validator = - new MainnetTransactionValidator(gasCalculator, false, 1); + new MainnetTransactionValidator(gasCalculator, false, Optional.of(BigInteger.ONE)); final Account account = accountWithNonce(basicTransaction.getNonce() - 1); assertThat(validator.validateForSender(basicTransaction, account, false)) @@ -107,7 +115,7 @@ public void shouldRejectTransactionWhenTransactionNonceBelowAccountNonce() { public void shouldAcceptTransactionWhenTransactionNonceAboveAccountNonceAndFutureNonceIsAllowed() { final MainnetTransactionValidator validator = - new MainnetTransactionValidator(gasCalculator, false, 1); + new MainnetTransactionValidator(gasCalculator, false, Optional.of(BigInteger.ONE)); final Account account = accountWithNonce(basicTransaction.getNonce() - 1); assertThat(validator.validateForSender(basicTransaction, account, true)) @@ -117,7 +125,7 @@ public void shouldRejectTransactionWhenTransactionNonceBelowAccountNonce() { @Test public void shouldRejectTransactionWhenNonceExceedsMaximumAllowedNonce() { final MainnetTransactionValidator validator = - new MainnetTransactionValidator(gasCalculator, false, 1); + new MainnetTransactionValidator(gasCalculator, false, Optional.of(BigInteger.ONE)); final Transaction transaction = new TransactionTestFixture().nonce(11).createTransaction(senderKeys); @@ -130,7 +138,7 @@ public void shouldRejectTransactionWhenNonceExceedsMaximumAllowedNonce() { @Test public void transactionWithNullSenderCanBeValidIfGasPriceAndValueIsZero() { final MainnetTransactionValidator validator = - new MainnetTransactionValidator(gasCalculator, false, 1); + new MainnetTransactionValidator(gasCalculator, false, Optional.of(BigInteger.ONE)); final TransactionTestFixture builder = new TransactionTestFixture(); final KeyPair senderKeyPair = KeyPair.generate(); diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolScheduleTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolScheduleTest.java index 6b1871690a..0ef7734730 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolScheduleTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolScheduleTest.java @@ -15,12 +15,15 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; +import java.math.BigInteger; +import java.util.Optional; + import org.assertj.core.api.Assertions; import org.junit.Test; public class ProtocolScheduleTest { - private static final int CHAIN_ID = 1; + private static final Optional CHAIN_ID = Optional.of(BigInteger.ONE); @SuppressWarnings("unchecked") @Test diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionHandlerTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionHandlerTest.java index 2ef696d0e1..2ca11c629e 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionHandlerTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionHandlerTest.java @@ -79,7 +79,7 @@ public class PrivateTransactionHandlerTest { .value(Wei.ZERO) .payload(BytesValue.wrap(TRANSACTION_KEY.getBytes(Charsets.UTF_8))) .sender(Address.fromHexString("0xfe3b557e8fb62b89f4916b721be55ceb828dbd73")) - .chainId(2018) + .chainId(BigInteger.valueOf(2018)) .signAndBuild(KEY_PAIR); Enclave mockEnclave() throws IOException { diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/ReferenceTestProtocolSchedules.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/ReferenceTestProtocolSchedules.java index 952cce7ff3..d7ee5ae2d4 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/ReferenceTestProtocolSchedules.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/ReferenceTestProtocolSchedules.java @@ -18,6 +18,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolScheduleBuilder; +import java.math.BigInteger; import java.util.Map; import java.util.function.Function; @@ -25,7 +26,7 @@ public class ReferenceTestProtocolSchedules { - private static final int CHAIN_ID = 1; + private static final BigInteger CHAIN_ID = BigInteger.ONE; public static ReferenceTestProtocolSchedules create() { final ImmutableMap.Builder> builder = ImmutableMap.builder(); diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/VMReferenceTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/VMReferenceTest.java index d2e093bb6b..c22f2b5d8a 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/VMReferenceTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/VMReferenceTest.java @@ -28,8 +28,10 @@ import tech.pegasys.pantheon.ethereum.worldstate.DefaultMutableWorldState; import tech.pegasys.pantheon.testutil.JsonTestParameters; +import java.math.BigInteger; import java.util.ArrayDeque; import java.util.Collection; +import java.util.Optional; import java.util.OptionalInt; import org.junit.runner.RunWith; @@ -92,7 +94,7 @@ public class VMReferenceTest extends AbstractRetryingTest { "CallToPrecompiledContract", "createNameRegistrator" }; - private static final int CHAIN_ID = 1; + private static final Optional CHAIN_ID = Optional.of(BigInteger.ONE); private final String name; private final VMReferenceTestCaseSpec spec; diff --git a/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcResponseUtils.java b/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcResponseUtils.java index 99aab20978..239c35ab01 100644 --- a/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcResponseUtils.java +++ b/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcResponseUtils.java @@ -155,7 +155,7 @@ public TransactionResult transaction( final Transaction transaction = mock(Transaction.class); when(transaction.getGasPrice()).thenReturn(Wei.fromHexString(gasPrice)); when(transaction.getNonce()).thenReturn(unsignedLong(nonce)); - when(transaction.getV()).thenReturn(bigInteger(v).intValue()); + when(transaction.getV()).thenReturn(bigInteger(v)); when(transaction.getR()).thenReturn(bigInteger(r)); when(transaction.getS()).thenReturn(bigInteger(s)); when(transaction.hash()).thenReturn(hash(hash)); diff --git a/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/methods/EthGetFilterChangesIntegrationTest.java b/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/methods/EthGetFilterChangesIntegrationTest.java index 7cccfeb43c..e4b8734b08 100644 --- a/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/methods/EthGetFilterChangesIntegrationTest.java +++ b/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/methods/EthGetFilterChangesIntegrationTest.java @@ -55,6 +55,7 @@ import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.uint.UInt256; +import java.math.BigInteger; import java.util.List; import org.assertj.core.util.Lists; @@ -282,7 +283,7 @@ private Transaction createTransaction(final int transactionNumber) { .to(Address.ID) .value(Wei.of(transactionNumber)) .sender(Address.ID) - .chainId(1) + .chainId(BigInteger.ONE) .signAndBuild(keyPair); } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthChainId.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthChainId.java index 6ed0d39bb2..a54ce0909d 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthChainId.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthChainId.java @@ -17,11 +17,14 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.Quantity; +import java.math.BigInteger; +import java.util.Optional; + public class EthChainId implements JsonRpcMethod { - private final int chainId; + private final Optional chainId; - public EthChainId(final int chainId) { + public EthChainId(final Optional chainId) { this.chainId = chainId; } @@ -32,6 +35,6 @@ public String getName() { @Override public JsonRpcResponse response(final JsonRpcRequest req) { - return new JsonRpcSuccessResponse(req.getId(), Quantity.create(chainId)); + return new JsonRpcSuccessResponse(req.getId(), chainId.map(Quantity::create).orElse(null)); } } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/NetVersion.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/NetVersion.java index ca71ca8a3c..27c8a5b8d6 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/NetVersion.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/NetVersion.java @@ -16,6 +16,9 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse; +import java.math.BigInteger; +import java.util.Optional; + /** * In Consensys' client, net_version maps to the network id, as specified in * * https://github.com/ethereum/wiki/wiki/JSON-RPC#net_version @@ -25,8 +28,8 @@ public class NetVersion implements JsonRpcMethod { private final String chainId; - public NetVersion(final int chainId) { - this.chainId = String.valueOf(chainId); + public NetVersion(final Optional chainId) { + this.chainId = String.valueOf(chainId.orElse(null)); } @Override diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/Quantity.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/Quantity.java index 136c0a6c65..96b5f29058 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/Quantity.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/Quantity.java @@ -48,6 +48,10 @@ public static String create(final long value) { return uint256ToHex(UInt256.of(value)); } + public static String create(final BigInteger value) { + return uint256ToHex(UInt256.of(value)); + } + public static String format(final BigInteger input) { return formatMinimalValue(input.toString(16)); } diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceHostWhitelistTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceHostWhitelistTest.java index f0fb519a6d..dacdee5f3a 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceHostWhitelistTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceHostWhitelistTest.java @@ -35,6 +35,7 @@ import tech.pegasys.pantheon.metrics.prometheus.MetricsConfiguration; import java.io.IOException; +import java.math.BigInteger; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -95,7 +96,9 @@ public void initServerAndClient() throws Exception { blockchainQueries, synchronizer, MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions().constantinopleBlock(0).chainId(CHAIN_ID)), + new StubGenesisConfigOptions() + .constantinopleBlock(0) + .chainId(BigInteger.valueOf(CHAIN_ID))), mock(FilterManager.class), mock(TransactionPool.class), mock(EthHashMiningCoordinator.class), diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceLoginTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceLoginTest.java index 74dfbae340..282aa94d91 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceLoginTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceLoginTest.java @@ -41,6 +41,7 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.math.BigInteger; import java.nio.file.Paths; import java.security.KeyStore; import java.security.KeyStoreException; @@ -114,7 +115,7 @@ public static void initServerAndClient() throws Exception { supportedCapabilities.add(EthProtocol.ETH63); final StubGenesisConfigOptions genesisConfigOptions = - new StubGenesisConfigOptions().constantinopleBlock(0).chainId(CHAIN_ID); + new StubGenesisConfigOptions().constantinopleBlock(0).chainId(BigInteger.valueOf(CHAIN_ID)); rpcMethods = spy( new JsonRpcMethodsFactory() @@ -388,7 +389,7 @@ public void checkJsonRpcMethodsAvailableWithGoodCredentialsAndPermissions() thro assertThat(token).isNotNull(); JsonRpcMethod ethAccounts = new EthAccounts(); - JsonRpcMethod netVersion = new NetVersion(123); + JsonRpcMethod netVersion = new NetVersion(Optional.of(BigInteger.valueOf(123))); JsonRpcMethod ethBlockNumber = new EthBlockNumber(blockchainQueries); JsonRpcMethod web3Sha3 = new Web3Sha3(); JsonRpcMethod web3ClientVersion = new Web3ClientVersion("777"); diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceTest.java index 732fb3183b..ddcbfd491a 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceTest.java @@ -123,7 +123,9 @@ public static void initServerAndClient() throws Exception { blockchainQueries, synchronizer, MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions().constantinopleBlock(0).chainId(CHAIN_ID)), + new StubGenesisConfigOptions() + .constantinopleBlock(0) + .chainId(BigInteger.valueOf(CHAIN_ID))), mock(FilterManager.class), mock(TransactionPool.class), mock(EthHashMiningCoordinator.class), diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/AdminNodeInfoTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/AdminNodeInfoTest.java index cb4c23486c..48c7ffd148 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/AdminNodeInfoTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/AdminNodeInfoTest.java @@ -32,6 +32,7 @@ import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.uint.UInt256; +import java.math.BigInteger; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -57,7 +58,7 @@ public class AdminNodeInfoTest { "0x0f1b319e32017c3fcb221841f0f978701b4e9513fe6a567a2db43d43381a9c7e3dfe7cae13cbc2f56943400bacaf9082576ab087cd51983b17d729ae796f6807"); private final ChainHead testChainHead = new ChainHead(Hash.EMPTY, UInt256.ONE); private final GenesisConfigOptions genesisConfigOptions = - new StubGenesisConfigOptions().chainId(2019); + new StubGenesisConfigOptions().chainId(BigInteger.valueOf(2019)); private final DefaultPeer defaultPeer = new DefaultPeer(nodeId, "1.2.3.4", 7890, 30303); @Before diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthChainIdTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthChainIdTest.java index d6bfffd9d1..9984f4ed10 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthChainIdTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthChainIdTest.java @@ -19,17 +19,20 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.Quantity; +import java.math.BigInteger; +import java.util.Optional; + import org.junit.Before; import org.junit.Test; public class EthChainIdTest { private EthChainId method; - private final int CHAIN_ID = 1; + private final BigInteger CHAIN_ID = BigInteger.ONE; @Before public void setUp() { - method = new EthChainId(CHAIN_ID); + method = new EthChainId(Optional.of(CHAIN_ID)); } @Test @@ -39,9 +42,20 @@ public void shouldReturnCorrectMethodName() { @Test public void shouldReturnChainId() { - JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, Quantity.create(CHAIN_ID)); + final JsonRpcResponse expectedResponse = + new JsonRpcSuccessResponse(null, Quantity.create(CHAIN_ID)); + + final JsonRpcResponse response = method.response(request()); + + assertThat(response).isEqualToComparingFieldByField(expectedResponse); + } + + @Test + public void shouldReturnNullWhenNoChainId() { + method = new EthChainId(Optional.empty()); + final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, null); - JsonRpcResponse response = method.response(request()); + final JsonRpcResponse response = method.response(request()); assertThat(response).isEqualToComparingFieldByField(expectedResponse); } diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/NetVersionTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/NetVersionTest.java new file mode 100644 index 0000000000..7013081e4b --- /dev/null +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/NetVersionTest.java @@ -0,0 +1,64 @@ +/* + * 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.jsonrpc.internal.methods; + +import static org.assertj.core.api.Assertions.assertThat; + +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse; + +import java.math.BigInteger; +import java.util.Optional; + +import org.junit.Before; +import org.junit.Test; + +public class NetVersionTest { + + private NetVersion method; + private final BigInteger CHAIN_ID = BigInteger.ONE; + + @Before + public void setUp() { + method = new NetVersion(Optional.of(CHAIN_ID)); + } + + @Test + public void shouldReturnCorrectMethodName() { + assertThat(method.getName()).isEqualTo("net_version"); + } + + @Test + public void shouldReturnChainId() { + final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, CHAIN_ID.toString()); + + final JsonRpcResponse response = method.response(request()); + + assertThat(response).isEqualToComparingFieldByField(expectedResponse); + } + + @Test + public void shouldReturnNullWhenNoChainId() { + method = new NetVersion(Optional.empty()); + final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, "null"); + + final JsonRpcResponse response = method.response(request()); + + assertThat(response).isEqualToComparingFieldByField(expectedResponse); + } + + private JsonRpcRequest request() { + return new JsonRpcRequest(null, "net_version", null); + } +} diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/privacy/EeaGetTransactionReceiptTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/privacy/EeaGetTransactionReceiptTest.java index 5038276dd2..6af7246910 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/privacy/EeaGetTransactionReceiptTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/privacy/EeaGetTransactionReceiptTest.java @@ -109,7 +109,7 @@ public class EeaGetTransactionReceiptTest { .value(Wei.ZERO) .payload(BytesValue.wrap("EnclaveKey".getBytes(UTF_8))) .sender(Address.fromHexString("0xfe3b557e8fb62b89f4916b721be55ceb828dbd73")) - .chainId(2018) + .chainId(BigInteger.valueOf(2018)) .signAndBuild(KEY_PAIR); private final Hash mockTransactionHash = diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/privacy/EeaSendRawTransactionTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/privacy/EeaSendRawTransactionTest.java index 9bcfbb40c6..8f025e843c 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/privacy/EeaSendRawTransactionTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/privacy/EeaSendRawTransactionTest.java @@ -84,7 +84,7 @@ public class EeaSendRawTransactionTest { Byte.valueOf("0")), BytesValue.fromHexString("0x"), Address.wrap(BytesValue.fromHexString("0x8411b12666f68ef74cace3615c9d5a377729d03f")), - 0); + Optional.empty()); @Mock private TransactionPool transactionPool; diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java b/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java index 0252eb5f27..a795d5863a 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java @@ -1054,10 +1054,16 @@ private EthNetworkConfig updateNetworkConfig(final NetworkName network) { genesisConfigFile .getConfigOptions() .getChainId() + .map(BigInteger::intValueExact) .orElse(EthNetworkConfig.getNetworkConfig(MAINNET).getNetworkId())); } catch (final DecodeException e) { throw new ParameterException( this.commandLine, String.format("Unable to parse genesis file %s.", genesisFile), e); + } catch (final ArithmeticException e) { + throw new ParameterException( + this.commandLine, + "No networkId specified and chainId in " + + "genesis file is too large to be used as a networkId"); } } diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java index 7cb97baa71..2c52baddb5 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java @@ -811,7 +811,7 @@ public void predefinedNetworkIdsMustBeEqualToChainIds() { final GenesisConfigFile genesisConfigFile = GenesisConfigFile.fromConfig(EthNetworkConfig.getNetworkConfig(MAINNET).getGenesisConfig()); assertThat(genesisConfigFile.getConfigOptions().getChainId().isPresent()).isTrue(); - assertThat(genesisConfigFile.getConfigOptions().getChainId().getAsInt()) + assertThat(genesisConfigFile.getConfigOptions().getChainId().get().intValueExact()) .isEqualTo(EthNetworkConfig.getNetworkConfig(MAINNET).getNetworkId()); }