From d373496ccbfe332ebc268a19af1ac3591859dde2 Mon Sep 17 00:00:00 2001 From: Karim TAAM Date: Sat, 20 Jul 2019 20:33:29 +0200 Subject: [PATCH] implement eth_submitHashrate --- .../blockcreation/EthHashBlockCreator.java | 4 ++ .../blockcreation/EthHashBlockMiner.java | 4 ++ .../EthHashMiningCoordinator.java | 9 +++ .../blockcreation/MiningCoordinator.java | 5 ++ .../ethereum/mainnet/EthHashSolver.java | 19 ++++++- .../pantheon/ethereum/jsonrpc/RpcMethod.java | 1 + .../internal/methods/EthSubmitHashrate.java | 57 +++++++++++++++++++ 7 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthSubmitHashrate.java diff --git a/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockCreator.java b/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockCreator.java index 2658cb3081..9e3c1234ba 100644 --- a/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockCreator.java +++ b/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockCreator.java @@ -103,6 +103,10 @@ public boolean submitWork(final EthHashSolution solution) { return nonceSolver.submitSolution(solution); } + public boolean submitHashesPerSecond(final String remoteMinerId, final long hashrate) { + return nonceSolver.submitHashesPerSecond(remoteMinerId, hashrate); + } + @Override public void cancel() { super.cancel(); diff --git a/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockMiner.java b/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockMiner.java index fdfea0e89e..109c366642 100644 --- a/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockMiner.java +++ b/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockMiner.java @@ -52,4 +52,8 @@ public Optional getHashesPerSecond() { public boolean submitWork(final EthHashSolution solution) { return blockCreator.submitWork(solution); } + + public boolean submitHashesPerSecond(final String remoteMinerId, final long hashrate) { + return blockCreator.submitHashesPerSecond(remoteMinerId, hashrate); + } } diff --git a/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashMiningCoordinator.java b/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashMiningCoordinator.java index 2de4449715..cfefa2bd93 100644 --- a/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashMiningCoordinator.java +++ b/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashMiningCoordinator.java @@ -73,6 +73,15 @@ public boolean submitWork(final EthHashSolution solution) { } } + @Override + public boolean submitHashesPerSecond(final String remoteMinerId, final long hashrate) { + synchronized (this) { + return currentRunningMiner + .map(miner -> miner.submitHashesPerSecond(remoteMinerId, hashrate)) + .orElse(false); + } + } + @Override protected void haltCurrentMiningOperation() { currentRunningMiner.ifPresent( diff --git a/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/MiningCoordinator.java b/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/MiningCoordinator.java index 6d46e26b6b..c2478118eb 100644 --- a/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/MiningCoordinator.java +++ b/ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/MiningCoordinator.java @@ -47,6 +47,11 @@ default Optional hashesPerSecond() { "Current consensus mechanism prevents querying of hashrate."); } + default boolean submitHashesPerSecond(final String remoteMinerId, final long hashrate) { + throw new UnsupportedOperationException( + "Current consensus mechanism prevents submitting hashrate."); + } + default Optional getWorkDefinition() { throw new UnsupportedOperationException( "Current consensus mechanism prevents querying work definition."); diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/EthHashSolver.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/EthHashSolver.java index 72fd4d183d..6c84e75c28 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/EthHashSolver.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/EthHashSolver.java @@ -18,10 +18,13 @@ import tech.pegasys.pantheon.util.uint.UInt256; import java.util.Arrays; +import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; import com.google.common.base.Stopwatch; @@ -72,6 +75,7 @@ public EthHashSolution getSolution() throws InterruptedException, ExecutionExcep private final Iterable nonceGenerator; private final EthHasher ethHasher; private volatile long hashesPerSecond = NO_MINING_CONDUCTED; + private final Map hashPerSecondOfRemoteMiners = new ConcurrentHashMap<>(); private volatile Optional currentJob = Optional.empty(); @@ -129,10 +133,16 @@ public Optional getWorkDefinition() { } public Optional hashesPerSecond() { - if (hashesPerSecond == NO_MINING_CONDUCTED) { + if (hashesPerSecond == NO_MINING_CONDUCTED && hashPerSecondOfRemoteMiners.isEmpty()) { return Optional.empty(); } - return Optional.of(hashesPerSecond); + + AtomicLong totalHashrate = new AtomicLong(hashesPerSecond); + // add remote miners hashes per second if present + totalHashrate.addAndGet( + hashPerSecondOfRemoteMiners.values().stream().mapToLong(Long::longValue).sum()); + + return Optional.of(totalHashrate.longValue()); } public boolean submitSolution(final EthHashSolution solution) { @@ -156,4 +166,9 @@ public boolean submitSolution(final EthHashSolution solution) { } return false; } + + public boolean submitHashesPerSecond(final String remoteMinerId, final long hashesPerSecond) { + hashPerSecondOfRemoteMiners.put(remoteMinerId, hashesPerSecond); + return true; + } } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/RpcMethod.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/RpcMethod.java index bd6bc2a664..2b2725bf35 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/RpcMethod.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/RpcMethod.java @@ -69,6 +69,7 @@ public enum RpcMethod { ETH_GET_UNCLE_COUNT_BY_BLOCK_NUMBER("eth_getUncleCountByBlockNumber"), ETH_GET_WORK("eth_getWork"), ETH_HASHRATE("eth_hashrate"), + ETH_SUBMIT_HASHRATE("eth_submitHashrate"), ETH_MINING("eth_mining"), ETH_NEW_BLOCK_FILTER("eth_newBlockFilter"), ETH_NEW_FILTER("eth_newFilter"), diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthSubmitHashrate.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthSubmitHashrate.java new file mode 100644 index 0000000000..1e7868af3b --- /dev/null +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthSubmitHashrate.java @@ -0,0 +1,57 @@ +/* + * 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 tech.pegasys.pantheon.ethereum.blockcreation.MiningCoordinator; +import tech.pegasys.pantheon.ethereum.jsonrpc.RpcMethod; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcError; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcErrorResponse; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse; + +public class EthSubmitHashrate implements JsonRpcMethod { + + private final MiningCoordinator miningCoordinator; + private final JsonRpcParameter parameters; + + public EthSubmitHashrate( + final MiningCoordinator miningCoordinator, final JsonRpcParameter parameters) { + this.miningCoordinator = miningCoordinator; + this.parameters = parameters; + } + + @Override + public String getName() { + return RpcMethod.ETH_SUBMIT_HASHRATE.getMethodName(); + } + + @Override + public JsonRpcResponse response(final JsonRpcRequest req) { + try { + + if (req.getParamLength() != 2) { + return new JsonRpcErrorResponse(req.getId(), JsonRpcError.INVALID_PARAMS); + } + + final long hashrate = parameters.required(req.getParams(), 0, long.class); + final String remoteMinerId = parameters.required(req.getParams(), 1, String.class); + + return new JsonRpcSuccessResponse( + req.getId(), miningCoordinator.submitHashesPerSecond(remoteMinerId, hashrate)); + } catch (final UnsupportedOperationException ex) { + return new JsonRpcErrorResponse(req.getId(), JsonRpcError.INVALID_REQUEST); + } + } +}