diff --git a/GPU-MINING.md b/GPU-MINING.md new file mode 100644 index 0000000000..a3eb6f5288 --- /dev/null +++ b/GPU-MINING.md @@ -0,0 +1,51 @@ +# Pantheon Ethereum Client + +## Mining Software + +EthMiner is recommended. You can [download EthMiner from Github](https://github.com/ethereum-mining/ethminer), available for Windows, Linux, and MacOS. + +## GPU Mining with Pantheon + +To mine with EthMiner, start Pantheon with HTTP RPC enabled, setting cors to the IP of the miners you want mining from Pantheon. + +If running in a development environment, the starting flags would be the following: + +``` +./bin/pantheon --network=dev --gpu-mining-enabled --rpc-http-enabled --rpc-http-cors-origins=all +``` + +This starts Pantheon in a developer network with JSON RPC available at localhost:8545, with cors set to all IPs. + +Once initiated, you must wait until work is available before starting EthMiner. Once work is availabe, start EthMiner pointing to the JSON RPC endpoint. From the directory containing EthMiner: + +``` + -P http://@: +``` + +An example on Windows would look like the following: + +``` +ethminer.exe -P http://0xBBAac64b4E4499aa40DB238FaA8Ac00BAc50811B@127.0.0.1:8545 +``` + +Other computers can mine to this Pantheon node if cors allows it, by setting the host to the IP of the computer/server running Pantheon, or the hostname of the server running Pantheon. + +You can test when work is available using CURL in a command line: + +``` +curl -X POST --data "{"jsonrpc":"2.0","method":"eth_getWork","params":[],"id":73}" localhost:8545 +``` + +From Windows Command Prompt, qoutes are special characters. + +``` +curl -X POST --data "{\"jsonrpc\":\"2.0\",\"method\":\"eth_getWork\",\"params\":[],\"id\":73}" localhost:8545 +``` + +If work is available for mining, you should see a response similar to the following: + +``` +{"jsonrpc":"2.0","id":73,"result":["0xc9a815cfff9186b3b1ebb286ff71156b2605c4ca45e2413418c8054688011706","0x0000000000000000000000000000000000000000000000000000000000000000","0x028f5c28f5c28f5c28f5c28f5c28f5c28f5c28f5c28f5c28f5c28f5c28f5c28f"]} +``` + +If EthMiner disappears after building or downloading, check with your anti-virus software, allow EthMiner to run, and redownload. \ No newline at end of file diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpService.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpService.java index dd6921f080..7691e2fde4 100755 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpService.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpService.java @@ -408,7 +408,7 @@ private String serialise(final JsonRpcResponse response) { return EMPTY_RESPONSE; } - return Json.encodePrettily(response); + return Json.encode(response); } @SuppressWarnings("rawtypes") diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java index 6558e185dd..8fe4ba9381 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java @@ -72,6 +72,7 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.EthSendTransaction; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.EthSyncing; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.EthUninstallFilter; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.EthSubmitLogin; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.JsonRpcMethod; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.NetEnode; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.NetListening; @@ -260,6 +261,7 @@ public Map methods( new EthProtocolVersion(supportedCapabilities), new EthGasPrice(miningCoordinator), new EthGetWork(miningCoordinator), + new EthSubmitLogin(), new EthHashrate(miningCoordinator), new EthChainId(protocolSchedule.getChainId())); } 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 f84ad42206..cf76eb70e9 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 @@ -79,6 +79,7 @@ public enum RpcMethod { ETH_SEND_RAW_TRANSACTION("eth_sendRawTransaction"), ETH_SEND_TRANSACTION("eth_sendTransaction"), ETH_SUBSCRIBE("eth_subscribe"), + ETH_SUBMIT_LOGIN("eth_submitLogin"), ETH_SYNCING("eth_syncing"), ETH_UNINSTALL_FILTER("eth_uninstallFilter"), ETH_UNSUBSCRIBE("eth_unsubscribe"), diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthGetWork.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthGetWork.java index 8e97ea20e6..fe80e9cf1e 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthGetWork.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthGetWork.java @@ -33,6 +33,8 @@ public class EthGetWork implements JsonRpcMethod { private final MiningCoordinator miner; private static final Logger LOG = getLogger(); + private Boolean solverWasPresent = false; + private String[] storedResult; public EthGetWork(final MiningCoordinator miner) { this.miner = miner; @@ -54,7 +56,11 @@ public JsonRpcResponse response(final JsonRpcRequest req) { "0x" + BaseEncoding.base16().lowerCase().encode(dagSeed), rawResult.getTarget().toHexString() }; + solverWasPresent = true; + storedResult = result; return new JsonRpcSuccessResponse(req.getId(), result); + } else if (solverWasPresent) { + return new JsonRpcSuccessResponse(req.getId(), storedResult); } else { LOG.trace("Mining is not operational, eth_getWork request cannot be processed"); return new JsonRpcErrorResponse(req.getId(), JsonRpcError.NO_MINING_WORK_FOUND); diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthSubmitLogin.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthSubmitLogin.java new file mode 100644 index 0000000000..23832cec04 --- /dev/null +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthSubmitLogin.java @@ -0,0 +1,33 @@ +/* + * 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.jsonrpc.RpcMethod; +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; + +public class EthSubmitLogin implements JsonRpcMethod { + + @Override + public String getName() { + return RpcMethod.ETH_SUBMIT_LOGIN.getMethodName(); + } + + @Override + public JsonRpcResponse response(final JsonRpcRequest req) { + // Confirm login request + boolean result = true; + return new JsonRpcSuccessResponse(req.getId(), result); + } +} 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 bd333c67eb..1c06effd00 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java @@ -524,6 +524,11 @@ void setBannedNodeIds(final List values) { description = "Set if node will perform mining (default: ${DEFAULT-VALUE})") private final Boolean isMiningEnabled = false; + @Option( + names = {"--gpu-mining-enabled"}, + description = "Set if node supports GPU mining software (default: ${DEFAULT-VALUE})") + private final Boolean isGpuMiningEnabled = false; + @Option( names = {"--miner-coinbase"}, description = @@ -846,6 +851,13 @@ private PantheonCommand checkOptions() { !isMiningEnabled, asList("--miner-coinbase", "--min-gas-price", "--miner-extra-data")); + checkOptionDependencies( + logger, + commandLine, + "--gpu-mining-enabled", + !isGpuMiningEnabled, + asList("--rpc-http-cors-origins", "--rpc-http-enabled")); + checkOptionDependencies( logger, commandLine, @@ -867,6 +879,12 @@ private PantheonCommand checkOptions() { "Unable to mine without a valid coinbase. Either disable mining (remove --miner-enabled)" + "or specify the beneficiary of mining (via --miner-coinbase
)"); } + // noinspection ConstantConditions + if (isGpuMiningEnabled && isRpcHttpEnabled == null) { + throw new ParameterException( + this.commandLine, + "GPU mining requires RPC to be enabled, and CORS to be set to allow your miner's IP address"); + } return this; } @@ -929,22 +947,41 @@ public PantheonController buildController() { public PantheonControllerBuilder getControllerBuilder() { try { - return controllerBuilderFactory - .fromEthNetworkConfig(updateNetworkConfig(getNetwork())) - .synchronizerConfiguration(buildSyncConfig()) - .ethProtocolConfiguration(ethProtocolOptions.toDomainObject()) - .rocksDbConfiguration(buildRocksDbConfiguration()) - .dataDirectory(dataDir()) - .miningParameters( - new MiningParameters(coinbase, minTransactionGasPrice, extraData, isMiningEnabled)) - .transactionPoolConfiguration(buildTransactionPoolConfiguration()) - .nodePrivateKeyFile(nodePrivateKeyFile()) - .metricsSystem(metricsSystem.get()) - .privacyParameters(privacyParameters()) - .clock(Clock.systemUTC()) - .isRevertReasonEnabled(isRevertReasonEnabled) - .isPruningEnabled(isPruningEnabled) - .pruningConfiguration(buildPruningConfiguration()); + if (isGpuMiningEnabled) { + return controllerBuilderFactory + .fromEthNetworkConfig(updateNetworkConfig(getNetwork())) + .synchronizerConfiguration(buildSyncConfig()) + .ethProtocolConfiguration(ethProtocolOptions.toDomainObject()) + .rocksDbConfiguration(buildRocksDbConfiguration()) + .dataDirectory(dataDir()) + .miningParameters( + new MiningParameters(Address.ZERO, minTransactionGasPrice, extraData, isGpuMiningEnabled)) + .transactionPoolConfiguration(buildTransactionPoolConfiguration()) + .nodePrivateKeyFile(nodePrivateKeyFile()) + .metricsSystem(metricsSystem.get()) + .privacyParameters(privacyParameters()) + .clock(Clock.systemUTC()) + .isRevertReasonEnabled(isRevertReasonEnabled) + .isPruningEnabled(isPruningEnabled) + .pruningConfiguration(buildPruningConfiguration()); + } else { + return controllerBuilderFactory + .fromEthNetworkConfig(updateNetworkConfig(getNetwork())) + .synchronizerConfiguration(buildSyncConfig()) + .ethProtocolConfiguration(ethProtocolOptions.toDomainObject()) + .rocksDbConfiguration(buildRocksDbConfiguration()) + .dataDirectory(dataDir()) + .miningParameters( + new MiningParameters(coinbase, minTransactionGasPrice, extraData, isMiningEnabled)) + .transactionPoolConfiguration(buildTransactionPoolConfiguration()) + .nodePrivateKeyFile(nodePrivateKeyFile()) + .metricsSystem(metricsSystem.get()) + .privacyParameters(privacyParameters()) + .clock(Clock.systemUTC()) + .isRevertReasonEnabled(isRevertReasonEnabled) + .isPruningEnabled(isPruningEnabled) + .pruningConfiguration(buildPruningConfiguration()); + } } catch (final IOException e) { throw new ExecutionException(this.commandLine, "Invalid path", e); }