mirror of https://github.com/hyperledger/besu
New RPC methods `miner_setExtraData` and `miner_getExtraData` (#7078)
* New RPC methods to set and get block extra data Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net> * Remove redundant methods to set the extra data Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net> * miner_getExtraData unit tests Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net> * Add CHANGELOG Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net> * Apply suggestions from code review Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com> Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net> --------- Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net> Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>pull/7083/head
parent
b4b6adcf99
commit
40cfc800f7
@ -0,0 +1,41 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu. |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner; |
||||
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; |
||||
import org.hyperledger.besu.ethereum.core.MiningParameters; |
||||
|
||||
public class MinerGetExtraData implements JsonRpcMethod { |
||||
private final MiningParameters miningParameters; |
||||
|
||||
public MinerGetExtraData(final MiningParameters miningParameters) { |
||||
this.miningParameters = miningParameters; |
||||
} |
||||
|
||||
@Override |
||||
public String getName() { |
||||
return RpcMethod.MINER_GET_EXTRA_DATA.getMethodName(); |
||||
} |
||||
|
||||
@Override |
||||
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { |
||||
return new JsonRpcSuccessResponse( |
||||
requestContext.getRequest().getId(), miningParameters.getExtraData().toShortHexString()); |
||||
} |
||||
} |
@ -0,0 +1,69 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu. |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner; |
||||
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; |
||||
import org.hyperledger.besu.ethereum.core.MiningParameters; |
||||
|
||||
import java.nio.charset.StandardCharsets; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes; |
||||
import org.apache.tuweni.bytes.Bytes32; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
public class MinerSetExtraData implements JsonRpcMethod { |
||||
private static final Logger LOG = LoggerFactory.getLogger(MinerSetExtraData.class); |
||||
|
||||
private final MiningParameters miningParameters; |
||||
|
||||
public MinerSetExtraData(final MiningParameters miningParameters) { |
||||
this.miningParameters = miningParameters; |
||||
} |
||||
|
||||
@Override |
||||
public String getName() { |
||||
return RpcMethod.MINER_SET_EXTRA_DATA.getMethodName(); |
||||
} |
||||
|
||||
@Override |
||||
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { |
||||
try { |
||||
final String rawParam = requestContext.getRequiredParameter(0, String.class); |
||||
Bytes32.fromHexStringLenient( |
||||
rawParam); // done for validation, we want a hex string and max 32 bytes
|
||||
final var extraData = Bytes.fromHexStringLenient(rawParam); |
||||
miningParameters.setExtraData(extraData); |
||||
LOG.atDebug() |
||||
.setMessage("set extra data, raw=[{}] parsed=[{}], UTF-8=[{}]") |
||||
.addArgument(rawParam) |
||||
.addArgument(extraData::toHexString) |
||||
.addArgument(() -> new String(extraData.toArray(), StandardCharsets.UTF_8)) |
||||
.log(); |
||||
return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), true); |
||||
} catch (final IllegalArgumentException invalidJsonRpcParameters) { |
||||
return new JsonRpcErrorResponse( |
||||
requestContext.getRequest().getId(), |
||||
new JsonRpcError(RpcErrorType.INVALID_PARAMS, invalidJsonRpcParameters.getMessage())); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,62 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu. |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; |
||||
import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; |
||||
import org.hyperledger.besu.ethereum.core.MiningParameters; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
public class MinerGetExtraDataTest { |
||||
|
||||
@Test |
||||
public void shouldReturnDefaultExtraData() { |
||||
final MiningParameters miningParameters = ImmutableMiningParameters.newDefault(); |
||||
final MinerGetExtraData method = new MinerGetExtraData(miningParameters); |
||||
final JsonRpcRequestContext request = |
||||
new JsonRpcRequestContext(new JsonRpcRequest("2.0", method.getName(), new Object[] {})); |
||||
|
||||
final JsonRpcResponse expected = new JsonRpcSuccessResponse(request.getRequest().getId(), "0x"); |
||||
|
||||
final JsonRpcResponse actual = method.response(request); |
||||
assertThat(actual).usingRecursiveComparison().isEqualTo(expected); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldReturnSetAtRuntimeExtraData() { |
||||
final MiningParameters miningParameters = ImmutableMiningParameters.newDefault(); |
||||
final MinerGetExtraData method = new MinerGetExtraData(miningParameters); |
||||
final var extraData = "0x123456"; |
||||
final Bytes extraDataAtRuntime = Bytes.fromHexString(extraData); |
||||
|
||||
miningParameters.setExtraData(extraDataAtRuntime); |
||||
|
||||
final JsonRpcRequestContext request = |
||||
new JsonRpcRequestContext(new JsonRpcRequest("2.0", method.getName(), new Object[] {})); |
||||
|
||||
final JsonRpcResponse expected = |
||||
new JsonRpcSuccessResponse(request.getRequest().getId(), extraData); |
||||
|
||||
final JsonRpcResponse actual = method.response(request); |
||||
assertThat(actual).usingRecursiveComparison().isEqualTo(expected); |
||||
} |
||||
} |
@ -0,0 +1,109 @@ |
||||
/* |
||||
* Copyright contributors to Hyperledger Besu. |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; |
||||
import org.hyperledger.besu.ethereum.core.MiningParameters; |
||||
|
||||
import java.nio.charset.StandardCharsets; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes; |
||||
import org.junit.jupiter.api.BeforeEach; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
public class MinerSetExtraDataTest { |
||||
MiningParameters miningParameters = MiningParameters.newDefault(); |
||||
private MinerSetExtraData method; |
||||
|
||||
@BeforeEach |
||||
public void setUp() { |
||||
method = new MinerSetExtraData(miningParameters); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldChangeExtraData() { |
||||
final String newExtraData = " pippo 🐐 | "; |
||||
final var request = |
||||
request(Bytes.wrap(newExtraData.getBytes(StandardCharsets.UTF_8)).toHexString()); |
||||
final JsonRpcResponse expected = new JsonRpcSuccessResponse(request.getRequest().getId(), true); |
||||
|
||||
final JsonRpcResponse actual = method.response(request); |
||||
assertThat(actual).usingRecursiveComparison().isEqualTo(expected); |
||||
final var currExtraData = miningParameters.getExtraData(); |
||||
assertThat(new String(currExtraData.toArray(), StandardCharsets.UTF_8)).isEqualTo(newExtraData); |
||||
} |
||||
|
||||
private JsonRpcRequestContext request(final String newExtraData) { |
||||
return new JsonRpcRequestContext( |
||||
new JsonRpcRequest("2.0", method.getName(), new Object[] {newExtraData})); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldNotTrimLeadingZeros() { |
||||
final var zeroPrefixedExtraData = "0010203"; |
||||
final var request = request(zeroPrefixedExtraData); |
||||
|
||||
final JsonRpcResponse expected = new JsonRpcSuccessResponse(request.getRequest().getId(), true); |
||||
|
||||
final JsonRpcResponse actual = method.response(request); |
||||
assertThat(actual).usingRecursiveComparison().isEqualTo(expected); |
||||
final var currExtraData = miningParameters.getExtraData(); |
||||
assertThat(new String(currExtraData.toArray(), StandardCharsets.UTF_8)) |
||||
.isEqualTo( |
||||
new String( |
||||
Bytes.fromHexStringLenient(zeroPrefixedExtraData).toArray(), |
||||
StandardCharsets.UTF_8)); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldReturnErrorWhenExtraDataNotHex() { |
||||
final var request = request("not hex string"); |
||||
|
||||
final JsonRpcResponse expected = |
||||
new JsonRpcErrorResponse( |
||||
request.getRequest().getId(), |
||||
new JsonRpcError( |
||||
RpcErrorType.INVALID_PARAMS, |
||||
"Illegal character 'n' found at index 0 in hex binary representation")); |
||||
|
||||
final JsonRpcResponse actual = method.response(request); |
||||
assertThat(actual).usingRecursiveComparison().isEqualTo(expected); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldReturnErrorWhenExtraDataTooLong() { |
||||
final var tooLongExtraData = "shouldReturnFalseWhenExtraDataTooLong"; |
||||
final var request = |
||||
request(Bytes.wrap(tooLongExtraData.getBytes(StandardCharsets.UTF_8)).toHexString()); |
||||
|
||||
final JsonRpcResponse expected = |
||||
new JsonRpcErrorResponse( |
||||
request.getRequest().getId(), |
||||
new JsonRpcError( |
||||
RpcErrorType.INVALID_PARAMS, |
||||
"Hex value is too large: expected at most 32 bytes but got 37")); |
||||
|
||||
final JsonRpcResponse actual = method.response(request); |
||||
assertThat(actual).usingRecursiveComparison().isEqualTo(expected); |
||||
} |
||||
} |
Loading…
Reference in new issue