mirror of https://github.com/hyperledger/besu
Add getPayloadBodiesByRangeV1 and getPayloadBodiesByHash engine methods (#4980)
* Add engine get payload body methods and test Signed-off-by: Zhenyang Shi <wcgcyx@gmail.com> Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Add header Signed-off-by: Zhenyang Shi <wcgcyx@gmail.com> * Update result struct & add test Signed-off-by: Zhenyang Shi <wcgcyx@gmail.com> * Change constant to use upper case Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Add PayloadBody class and withdrawals to response of methods Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Add unit tests Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Add changelog Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * spotless Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Add check to prevent returning trailing null results past the head Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Add test to check trailing null post head scenario Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Split tests into pre and post shanghai Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * spotless Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Rename methods Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Use getName() to log method name Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * spotless Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Rename variable Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Call constructor directly Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Fix ByHash json parsing Signed-off-by: Simon Dudley <simon.dudley@consensys.net> * Fix json parsing again Signed-off-by: Simon Dudley <simon.dudley@consensys.net> * Add check to prevent unnecessary queries Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Refactor method Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Add new error code for EngineGetPayloadBodies methods Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Add return error for request above the API limit Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Add constructor for empty response Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * add check for number of blocks requested and for requests of post head Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Add test to check error code when request exceeds API limits Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * add constant for max blocks allowed per request Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * spotless Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Fix some nits Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Add invalid params check Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Add tests for invalid params check Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Fix test and spotless Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Revert "Fix json parsing again" This reverts commitpull/5073/head558d325bf3
. Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Revert "Fix ByHash json parsing Signed-off-by: Simon Dudley <simon.dudley@consensys.net>" This reverts commit663e11e2
Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Use UnsignedLongParameter to cast params of the request Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Add optional withdrawals to the NewPayload log (#5021) Signed-off-by: Simon Dudley <simon.dudley@consensys.net> * kubernetes and errorprone - update versions (#5013) * update errorprone and kubernetes versions * fixed errorprone issues in prod cod * fixed errorprone issues in test code --------- Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com> * Rename JsonRpcService to EngineJsonRpcService (#5036) * rename JsonRpcService to EngineJsonRpcService Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net> * Params should be single item of array type, not outer array of strings (#5037) Signed-off-by: Simon Dudley <simon.dudley@consensys.net> * Add EIP-2537 (BLS12-381 curve precompiles) to Cancun (#5017) Add the BLS curve precompiles into the registry for cancun. All of the curve precompiles have been here since berlin, so this is just wiring them in. Signed-off-by: Danno Ferrin <danno.ferrin@swirldslabs.com> Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com> * Use UnsignedLongParameter to cast params of the request Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> * Add optional withdrawals to the NewPayload log (#5021) Signed-off-by: Simon Dudley <simon.dudley@consensys.net> * kubernetes and errorprone - update versions (#5013) * update errorprone and kubernetes versions * fixed errorprone issues in prod cod * fixed errorprone issues in test code --------- Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com> * Rename JsonRpcService to EngineJsonRpcService (#5036) * rename JsonRpcService to EngineJsonRpcService Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net> * Params should be single item of array type, not outer array of strings (#5037) Signed-off-by: Simon Dudley <simon.dudley@consensys.net> * Add EIP-2537 (BLS12-381 curve precompiles) to Cancun (#5017) Add the BLS curve precompiles into the registry for cancun. All of the curve precompiles have been here since berlin, so this is just wiring them in. Signed-off-by: Danno Ferrin <danno.ferrin@swirldslabs.com> Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com> * Convert start and count from hex to match JSON-RPC Spec standard Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> --------- Signed-off-by: Zhenyang Shi <wcgcyx@gmail.com> Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com> Signed-off-by: Simon Dudley <simon.dudley@consensys.net> Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com> Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net> Signed-off-by: Danno Ferrin <danno.ferrin@swirldslabs.com> Co-authored-by: Zhenyang Shi <wcgcyx@gmail.com> Co-authored-by: Simon Dudley <simon.dudley@consensys.net> Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com> Co-authored-by: Daniel Lehrner <daniel.lehrner@consensys.net> Co-authored-by: Danno Ferrin <danno.ferrin@swirldslabs.com>
parent
fd90643792
commit
05bf6aba6a
@ -0,0 +1,85 @@ |
||||
/* |
||||
* Copyright Hyperledger Besu Contributors. |
||||
* |
||||
* 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.engine; |
||||
|
||||
import static org.hyperledger.besu.util.Slf4jLambdaHelper.traceLambda; |
||||
|
||||
import org.hyperledger.besu.datatypes.Hash; |
||||
import org.hyperledger.besu.ethereum.ProtocolContext; |
||||
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.ExecutionEngineJsonRpcMethod; |
||||
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.results.BlockResultFactory; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetPayloadBodiesResultV1; |
||||
import org.hyperledger.besu.ethereum.chain.Blockchain; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.stream.Collectors; |
||||
|
||||
import io.vertx.core.Vertx; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
public class EngineGetPayloadBodiesByHashV1 extends ExecutionEngineJsonRpcMethod { |
||||
|
||||
private static final int MAX_REQUEST_BLOCKS = 1024; |
||||
private static final Logger LOG = LoggerFactory.getLogger(EngineGetPayloadBodiesByHashV1.class); |
||||
private final BlockResultFactory blockResultFactory; |
||||
|
||||
public EngineGetPayloadBodiesByHashV1( |
||||
final Vertx vertx, |
||||
final ProtocolContext protocolContext, |
||||
final BlockResultFactory blockResultFactory, |
||||
final EngineCallListener engineCallListener) { |
||||
super(vertx, protocolContext, engineCallListener); |
||||
this.blockResultFactory = blockResultFactory; |
||||
} |
||||
|
||||
@Override |
||||
public String getName() { |
||||
return RpcMethod.ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1.getMethodName(); |
||||
} |
||||
|
||||
@Override |
||||
public JsonRpcResponse syncResponse(final JsonRpcRequestContext request) { |
||||
engineCallListener.executionEngineCalled(); |
||||
|
||||
final Object reqId = request.getRequest().getId(); |
||||
|
||||
final Hash[] blockHashes = request.getRequiredParameter(0, Hash[].class); |
||||
|
||||
traceLambda(LOG, "{} parameters: blockHashes {}", () -> getName(), () -> blockHashes); |
||||
|
||||
if (blockHashes.length > getMaxRequestBlocks()) { |
||||
return new JsonRpcErrorResponse(reqId, JsonRpcError.INVALID_RANGE_REQUEST_TOO_LARGE); |
||||
} |
||||
|
||||
final Blockchain blockchain = protocolContext.getBlockchain(); |
||||
|
||||
final EngineGetPayloadBodiesResultV1 engineGetPayloadBodiesResultV1 = |
||||
blockResultFactory.payloadBodiesCompleteV1( |
||||
Arrays.stream(blockHashes).map(blockchain::getBlockBody).collect(Collectors.toList())); |
||||
|
||||
return new JsonRpcSuccessResponse(reqId, engineGetPayloadBodiesResultV1); |
||||
} |
||||
|
||||
protected int getMaxRequestBlocks() { |
||||
return MAX_REQUEST_BLOCKS; |
||||
} |
||||
} |
@ -0,0 +1,113 @@ |
||||
/* |
||||
* Copyright Hyperledger Besu Contributors. |
||||
* |
||||
* 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.engine; |
||||
|
||||
import static org.hyperledger.besu.util.Slf4jLambdaHelper.traceLambda; |
||||
|
||||
import org.hyperledger.besu.ethereum.ProtocolContext; |
||||
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.ExecutionEngineJsonRpcMethod; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UnsignedLongParameter; |
||||
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.results.BlockResultFactory; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetPayloadBodiesResultV1; |
||||
import org.hyperledger.besu.ethereum.chain.Blockchain; |
||||
|
||||
import java.util.stream.Collectors; |
||||
import java.util.stream.LongStream; |
||||
|
||||
import io.vertx.core.Vertx; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
public class EngineGetPayloadBodiesByRangeV1 extends ExecutionEngineJsonRpcMethod { |
||||
private static final Logger LOG = LoggerFactory.getLogger(EngineGetPayloadBodiesByRangeV1.class); |
||||
private static final int MAX_REQUEST_BLOCKS = 1024; |
||||
private final BlockResultFactory blockResultFactory; |
||||
|
||||
public EngineGetPayloadBodiesByRangeV1( |
||||
final Vertx vertx, |
||||
final ProtocolContext protocolContext, |
||||
final BlockResultFactory blockResultFactory, |
||||
final EngineCallListener engineCallListener) { |
||||
super(vertx, protocolContext, engineCallListener); |
||||
this.blockResultFactory = blockResultFactory; |
||||
} |
||||
|
||||
@Override |
||||
public String getName() { |
||||
return RpcMethod.ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1.getMethodName(); |
||||
} |
||||
|
||||
@Override |
||||
public JsonRpcResponse syncResponse(final JsonRpcRequestContext request) { |
||||
engineCallListener.executionEngineCalled(); |
||||
|
||||
final long startBlockNumber = |
||||
request.getRequiredParameter(0, UnsignedLongParameter.class).getValue(); |
||||
final long count = request.getRequiredParameter(1, UnsignedLongParameter.class).getValue(); |
||||
final Object reqId = request.getRequest().getId(); |
||||
|
||||
traceLambda( |
||||
LOG, |
||||
"{} parameters: start block number {} count {}", |
||||
() -> getName(), |
||||
() -> startBlockNumber, |
||||
() -> count); |
||||
|
||||
if (startBlockNumber < 1 || count < 1) { |
||||
return new JsonRpcErrorResponse(reqId, JsonRpcError.INVALID_PARAMS); |
||||
} |
||||
|
||||
if (count > getMaxRequestBlocks()) { |
||||
return new JsonRpcErrorResponse(reqId, JsonRpcError.INVALID_RANGE_REQUEST_TOO_LARGE); |
||||
} |
||||
|
||||
final Blockchain blockchain = protocolContext.getBlockchain(); |
||||
final long chainHeadBlockNumber = blockchain.getChainHeadBlockNumber(); |
||||
|
||||
// request startBlockNumber is beyond head of chain
|
||||
if (chainHeadBlockNumber < startBlockNumber) { |
||||
// Empty List of payloadBodies
|
||||
return new JsonRpcSuccessResponse(reqId, new EngineGetPayloadBodiesResultV1()); |
||||
} |
||||
|
||||
final long upperBound = startBlockNumber + count; |
||||
|
||||
// if we've received request from blocks beyond the head we exclude those from the query
|
||||
final long endExclusiveBlockNumber = |
||||
chainHeadBlockNumber < upperBound ? chainHeadBlockNumber + 1 : upperBound; |
||||
|
||||
EngineGetPayloadBodiesResultV1 engineGetPayloadBodiesResultV1 = |
||||
blockResultFactory.payloadBodiesCompleteV1( |
||||
LongStream.range(startBlockNumber, endExclusiveBlockNumber) |
||||
.mapToObj( |
||||
blockNumber -> |
||||
blockchain |
||||
.getBlockHashByNumber(blockNumber) |
||||
.flatMap(blockchain::getBlockBody)) |
||||
.collect(Collectors.toList())); |
||||
|
||||
return new JsonRpcSuccessResponse(reqId, engineGetPayloadBodiesResultV1); |
||||
} |
||||
|
||||
protected int getMaxRequestBlocks() { |
||||
return MAX_REQUEST_BLOCKS; |
||||
} |
||||
} |
@ -0,0 +1,79 @@ |
||||
/* |
||||
* Copyright Hyperledger Besu Contributors. |
||||
* |
||||
* 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.results; |
||||
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameter; |
||||
import org.hyperledger.besu.ethereum.core.BlockBody; |
||||
import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
import java.util.stream.Collectors; |
||||
|
||||
import com.fasterxml.jackson.annotation.JsonGetter; |
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder; |
||||
import com.fasterxml.jackson.annotation.JsonValue; |
||||
import org.apache.tuweni.bytes.Bytes; |
||||
|
||||
@JsonPropertyOrder({"payloadBodies"}) |
||||
public class EngineGetPayloadBodiesResultV1 { |
||||
|
||||
private final List<PayloadBody> payloadBodies; |
||||
|
||||
public EngineGetPayloadBodiesResultV1() { |
||||
this.payloadBodies = Collections.<PayloadBody>emptyList(); |
||||
} |
||||
|
||||
public EngineGetPayloadBodiesResultV1(final List<PayloadBody> payloadBody) { |
||||
this.payloadBodies = payloadBody; |
||||
} |
||||
|
||||
@JsonValue |
||||
public List<PayloadBody> getPayloadBodies() { |
||||
return payloadBodies; |
||||
} |
||||
|
||||
public static class PayloadBody { |
||||
private final List<String> transactions; |
||||
private final List<WithdrawalParameter> withdrawals; |
||||
|
||||
public PayloadBody(final BlockBody blockBody) { |
||||
this.transactions = |
||||
blockBody.getTransactions().stream() |
||||
.map(TransactionEncoder::encodeOpaqueBytes) |
||||
.map(Bytes::toHexString) |
||||
.collect(Collectors.toList()); |
||||
this.withdrawals = |
||||
blockBody |
||||
.getWithdrawals() |
||||
.map( |
||||
ws -> |
||||
ws.stream() |
||||
.map(WithdrawalParameter::fromWithdrawal) |
||||
.collect(Collectors.toList())) |
||||
.orElse(null); |
||||
} |
||||
|
||||
@JsonGetter(value = "transactions") |
||||
public List<String> getTransactions() { |
||||
return transactions; |
||||
} |
||||
|
||||
@JsonGetter(value = "withdrawals") |
||||
public List<WithdrawalParameter> getWithdrawals() { |
||||
return withdrawals; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,267 @@ |
||||
/* |
||||
* Copyright Hyperledger Besu Contributors. |
||||
* |
||||
* 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.engine; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INVALID_RANGE_REQUEST_TOO_LARGE; |
||||
import static org.mockito.Mockito.doReturn; |
||||
import static org.mockito.Mockito.spy; |
||||
import static org.mockito.Mockito.when; |
||||
|
||||
import org.hyperledger.besu.crypto.SignatureAlgorithm; |
||||
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; |
||||
import org.hyperledger.besu.datatypes.Address; |
||||
import org.hyperledger.besu.datatypes.GWei; |
||||
import org.hyperledger.besu.datatypes.Hash; |
||||
import org.hyperledger.besu.ethereum.ProtocolContext; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; |
||||
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.JsonRpcResponseType; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetPayloadBodiesResultV1; |
||||
import org.hyperledger.besu.ethereum.chain.MutableBlockchain; |
||||
import org.hyperledger.besu.ethereum.core.BlockBody; |
||||
import org.hyperledger.besu.ethereum.core.TransactionTestFixture; |
||||
import org.hyperledger.besu.ethereum.core.Withdrawal; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
import java.util.Optional; |
||||
|
||||
import io.vertx.core.Vertx; |
||||
import org.apache.tuweni.bytes.Bytes32; |
||||
import org.apache.tuweni.units.bigints.UInt64; |
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
import org.mockito.Mock; |
||||
import org.mockito.junit.MockitoJUnitRunner; |
||||
|
||||
@RunWith(MockitoJUnitRunner.class) |
||||
public class EngineGetPayloadBodiesByHashV1Test { |
||||
private EngineGetPayloadBodiesByHashV1 method; |
||||
private static final Vertx vertx = Vertx.vertx(); |
||||
private static final BlockResultFactory blockResultFactory = new BlockResultFactory(); |
||||
@Mock private ProtocolContext protocolContext; |
||||
@Mock private EngineCallListener engineCallListener; |
||||
@Mock private MutableBlockchain blockchain; |
||||
|
||||
@Before |
||||
public void before() { |
||||
when(protocolContext.getBlockchain()).thenReturn(blockchain); |
||||
this.method = |
||||
spy( |
||||
new EngineGetPayloadBodiesByHashV1( |
||||
vertx, protocolContext, blockResultFactory, engineCallListener)); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldReturnExpectedMethodName() { |
||||
assertThat(method.getName()).isEqualTo("engine_getPayloadBodiesByHashV1"); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldReturnEmptyPayloadBodiesWithEmptyHash() { |
||||
final var resp = resp(new Hash[] {}); |
||||
final EngineGetPayloadBodiesResultV1 result = fromSuccessResp(resp); |
||||
assertThat(result.getPayloadBodies().isEmpty()).isTrue(); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldReturnPayloadForKnownHashes() { |
||||
final SignatureAlgorithm sig = SignatureAlgorithmFactory.getInstance(); |
||||
final Hash blockHash1 = Hash.wrap(Bytes32.random()); |
||||
final Hash blockHash2 = Hash.wrap(Bytes32.random()); |
||||
final Hash blockHash3 = Hash.wrap(Bytes32.random()); |
||||
final BlockBody blockBody1 = |
||||
new BlockBody( |
||||
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), |
||||
Collections.emptyList()); |
||||
final BlockBody blockBody2 = |
||||
new BlockBody( |
||||
List.of( |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair())), |
||||
Collections.emptyList()); |
||||
final BlockBody blockBody3 = |
||||
new BlockBody( |
||||
List.of( |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair())), |
||||
Collections.emptyList()); |
||||
when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(blockBody1)); |
||||
when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(blockBody2)); |
||||
when(blockchain.getBlockBody(blockHash3)).thenReturn(Optional.of(blockBody3)); |
||||
|
||||
final var resp = resp(new Hash[] {blockHash1, blockHash2, blockHash3}); |
||||
final var result = fromSuccessResp(resp); |
||||
assertThat(result.getPayloadBodies().size()).isEqualTo(3); |
||||
assertThat(result.getPayloadBodies().get(0).getTransactions().size()).isEqualTo(1); |
||||
assertThat(result.getPayloadBodies().get(1).getTransactions().size()).isEqualTo(2); |
||||
assertThat(result.getPayloadBodies().get(2).getTransactions().size()).isEqualTo(3); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldReturnNullForUnknownHashes() { |
||||
final Hash blockHash1 = Hash.wrap(Bytes32.random()); |
||||
final Hash blockHash2 = Hash.wrap(Bytes32.random()); |
||||
final Hash blockHash3 = Hash.wrap(Bytes32.random()); |
||||
final var resp = resp(new Hash[] {blockHash1, blockHash2, blockHash3}); |
||||
final var result = fromSuccessResp(resp); |
||||
assertThat(result.getPayloadBodies().size()).isEqualTo(3); |
||||
assertThat(result.getPayloadBodies().get(0)).isNull(); |
||||
assertThat(result.getPayloadBodies().get(1)).isNull(); |
||||
assertThat(result.getPayloadBodies().get(2)).isNull(); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldReturnNullForUnknownHashAndPayloadForKnownHash() { |
||||
final SignatureAlgorithm sig = SignatureAlgorithmFactory.getInstance(); |
||||
final Hash blockHash1 = Hash.wrap(Bytes32.random()); |
||||
final Hash blockHash2 = Hash.wrap(Bytes32.random()); |
||||
final Hash blockHash3 = Hash.wrap(Bytes32.random()); |
||||
final BlockBody blockBody1 = |
||||
new BlockBody( |
||||
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), |
||||
Collections.emptyList()); |
||||
final BlockBody blockBody3 = |
||||
new BlockBody( |
||||
List.of( |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair())), |
||||
Collections.emptyList()); |
||||
when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(blockBody1)); |
||||
when(blockchain.getBlockBody(blockHash3)).thenReturn(Optional.of(blockBody3)); |
||||
|
||||
final var resp = resp(new Hash[] {blockHash1, blockHash2, blockHash3}); |
||||
final var result = fromSuccessResp(resp); |
||||
assertThat(result.getPayloadBodies().size()).isEqualTo(3); |
||||
assertThat(result.getPayloadBodies().get(0).getTransactions().size()).isEqualTo(1); |
||||
assertThat(result.getPayloadBodies().get(1)).isNull(); |
||||
assertThat(result.getPayloadBodies().get(2).getTransactions().size()).isEqualTo(3); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldReturnWithdrawalNullWhenBlockIsPreShanghai() { |
||||
final SignatureAlgorithm sig = SignatureAlgorithmFactory.getInstance(); |
||||
final Hash blockHash1 = Hash.wrap(Bytes32.random()); |
||||
final Hash blockHash2 = Hash.wrap(Bytes32.random()); |
||||
final BlockBody preShanghaiBlockBody = |
||||
new BlockBody( |
||||
List.of( |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair())), |
||||
Collections.emptyList()); |
||||
|
||||
final BlockBody preShanghaiBlockBody2 = |
||||
new BlockBody( |
||||
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), |
||||
Collections.emptyList(), |
||||
Optional.empty()); |
||||
when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(preShanghaiBlockBody)); |
||||
when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(preShanghaiBlockBody2)); |
||||
|
||||
final var resp = resp(new Hash[] {blockHash1, blockHash2}); |
||||
final var result = fromSuccessResp(resp); |
||||
assertThat(result.getPayloadBodies().size()).isEqualTo(2); |
||||
assertThat(result.getPayloadBodies().get(0).getTransactions().size()).isEqualTo(3); |
||||
assertThat(result.getPayloadBodies().get(0).getWithdrawals()).isNull(); |
||||
assertThat(result.getPayloadBodies().get(1).getTransactions().size()).isEqualTo(1); |
||||
assertThat(result.getPayloadBodies().get(1).getWithdrawals()).isNull(); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldReturnWithdrawalsWhenBlockIsPostShanghai() { |
||||
final SignatureAlgorithm sig = SignatureAlgorithmFactory.getInstance(); |
||||
final Hash blockHash1 = Hash.wrap(Bytes32.random()); |
||||
final Hash blockHash2 = Hash.wrap(Bytes32.random()); |
||||
final Withdrawal withdrawal = |
||||
new Withdrawal(UInt64.ONE, UInt64.ONE, Address.fromHexString("0x1"), GWei.ONE); |
||||
final Withdrawal withdrawal2 = |
||||
new Withdrawal(UInt64.ONE, UInt64.ONE, Address.fromHexString("0x2"), GWei.ONE); |
||||
|
||||
final BlockBody shanghaiBlockBody = |
||||
new BlockBody( |
||||
List.of( |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair())), |
||||
Collections.emptyList(), |
||||
Optional.of(List.of(withdrawal))); |
||||
|
||||
final BlockBody shanghaiBlockBody2 = |
||||
new BlockBody( |
||||
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), |
||||
Collections.emptyList(), |
||||
Optional.of(List.of(withdrawal2))); |
||||
when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(shanghaiBlockBody)); |
||||
when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(shanghaiBlockBody2)); |
||||
|
||||
final var resp = resp(new Hash[] {blockHash1, blockHash2}); |
||||
final var result = fromSuccessResp(resp); |
||||
assertThat(result.getPayloadBodies().size()).isEqualTo(2); |
||||
assertThat(result.getPayloadBodies().get(0).getTransactions().size()).isEqualTo(3); |
||||
assertThat(result.getPayloadBodies().get(0).getWithdrawals().size()).isEqualTo(1); |
||||
assertThat(result.getPayloadBodies().get(1).getTransactions().size()).isEqualTo(1); |
||||
assertThat(result.getPayloadBodies().get(1).getWithdrawals().size()).isEqualTo(1); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldReturnErrorWhenRequestExceedsPermittedNumberOfBlocks() { |
||||
final Hash blockHash1 = Hash.wrap(Bytes32.random()); |
||||
final Hash blockHash2 = Hash.wrap(Bytes32.random()); |
||||
final Hash[] hashes = new Hash[] {blockHash1, blockHash2}; |
||||
|
||||
doReturn(1).when(method).getMaxRequestBlocks(); |
||||
|
||||
final JsonRpcResponse resp = resp(hashes); |
||||
final var result = fromErrorResp(resp); |
||||
assertThat(result.getCode()).isEqualTo(INVALID_RANGE_REQUEST_TOO_LARGE.getCode()); |
||||
} |
||||
|
||||
private JsonRpcResponse resp(final Hash[] hashes) { |
||||
return method.response( |
||||
new JsonRpcRequestContext( |
||||
new JsonRpcRequest( |
||||
"2.0", |
||||
RpcMethod.ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1.getMethodName(), |
||||
new Object[] {hashes}))); |
||||
} |
||||
|
||||
private EngineGetPayloadBodiesResultV1 fromSuccessResp(final JsonRpcResponse resp) { |
||||
assertThat(resp.getType()).isEqualTo(JsonRpcResponseType.SUCCESS); |
||||
return Optional.of(resp) |
||||
.map(JsonRpcSuccessResponse.class::cast) |
||||
.map(JsonRpcSuccessResponse::getResult) |
||||
.map(EngineGetPayloadBodiesResultV1.class::cast) |
||||
.get(); |
||||
} |
||||
|
||||
private JsonRpcError fromErrorResp(final JsonRpcResponse resp) { |
||||
assertThat(resp.getType()).isEqualTo(JsonRpcResponseType.ERROR); |
||||
return Optional.of(resp) |
||||
.map(JsonRpcErrorResponse.class::cast) |
||||
.map(JsonRpcErrorResponse::getError) |
||||
.get(); |
||||
} |
||||
} |
@ -0,0 +1,352 @@ |
||||
/* |
||||
* Copyright Hyperledger Besu Contributors. |
||||
* |
||||
* 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.engine; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INVALID_PARAMS; |
||||
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INVALID_RANGE_REQUEST_TOO_LARGE; |
||||
import static org.mockito.Mockito.doReturn; |
||||
import static org.mockito.Mockito.spy; |
||||
import static org.mockito.Mockito.when; |
||||
|
||||
import org.hyperledger.besu.crypto.SignatureAlgorithm; |
||||
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; |
||||
import org.hyperledger.besu.datatypes.Address; |
||||
import org.hyperledger.besu.datatypes.GWei; |
||||
import org.hyperledger.besu.datatypes.Hash; |
||||
import org.hyperledger.besu.ethereum.ProtocolContext; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; |
||||
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.JsonRpcResponseType; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetPayloadBodiesResultV1; |
||||
import org.hyperledger.besu.ethereum.chain.MutableBlockchain; |
||||
import org.hyperledger.besu.ethereum.core.BlockBody; |
||||
import org.hyperledger.besu.ethereum.core.TransactionTestFixture; |
||||
import org.hyperledger.besu.ethereum.core.Withdrawal; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
import java.util.Optional; |
||||
|
||||
import io.vertx.core.Vertx; |
||||
import org.apache.tuweni.bytes.Bytes32; |
||||
import org.apache.tuweni.units.bigints.UInt64; |
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
import org.mockito.Mock; |
||||
import org.mockito.junit.MockitoJUnitRunner; |
||||
|
||||
@RunWith(MockitoJUnitRunner.class) |
||||
public class EngineGetPayloadBodiesByRangeV1Test { |
||||
private EngineGetPayloadBodiesByRangeV1 method; |
||||
private static final Vertx vertx = Vertx.vertx(); |
||||
private static final BlockResultFactory blockResultFactory = new BlockResultFactory(); |
||||
@Mock private ProtocolContext protocolContext; |
||||
@Mock private EngineCallListener engineCallListener; |
||||
@Mock private MutableBlockchain blockchain; |
||||
|
||||
@Before |
||||
public void before() { |
||||
when(protocolContext.getBlockchain()).thenReturn(blockchain); |
||||
this.method = |
||||
spy( |
||||
new EngineGetPayloadBodiesByRangeV1( |
||||
vertx, protocolContext, blockResultFactory, engineCallListener)); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldReturnExpectedMethodName() { |
||||
assertThat(method.getName()).isEqualTo("engine_getPayloadBodiesByRangeV1"); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldReturnPayloadForKnownNumber() { |
||||
final SignatureAlgorithm sig = SignatureAlgorithmFactory.getInstance(); |
||||
final Hash blockHash1 = Hash.wrap(Bytes32.random()); |
||||
final Hash blockHash2 = Hash.wrap(Bytes32.random()); |
||||
final Hash blockHash3 = Hash.wrap(Bytes32.random()); |
||||
final BlockBody blockBody1 = |
||||
new BlockBody( |
||||
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), |
||||
Collections.emptyList()); |
||||
final BlockBody blockBody2 = |
||||
new BlockBody( |
||||
List.of( |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair())), |
||||
Collections.emptyList()); |
||||
final BlockBody blockBody3 = |
||||
new BlockBody( |
||||
List.of( |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair())), |
||||
Collections.emptyList()); |
||||
when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(130)); |
||||
when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(blockBody1)); |
||||
when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(blockBody2)); |
||||
when(blockchain.getBlockBody(blockHash3)).thenReturn(Optional.of(blockBody3)); |
||||
when(blockchain.getBlockHashByNumber(123)).thenReturn(Optional.of(blockHash1)); |
||||
when(blockchain.getBlockHashByNumber(124)).thenReturn(Optional.of(blockHash2)); |
||||
when(blockchain.getBlockHashByNumber(125)).thenReturn(Optional.of(blockHash3)); |
||||
|
||||
final var resp = resp("0x7b", "0x3"); |
||||
final EngineGetPayloadBodiesResultV1 result = fromSuccessResp(resp); |
||||
assertThat(result.getPayloadBodies().size()).isEqualTo(3); |
||||
assertThat(result.getPayloadBodies().get(0).getTransactions().size()).isEqualTo(1); |
||||
assertThat(result.getPayloadBodies().get(1).getTransactions().size()).isEqualTo(2); |
||||
assertThat(result.getPayloadBodies().get(2).getTransactions().size()).isEqualTo(3); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldReturnNullForUnknownNumber() { |
||||
when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(130)); |
||||
final var resp = resp("0x7b", "0x3"); |
||||
final EngineGetPayloadBodiesResultV1 result = fromSuccessResp(resp); |
||||
assertThat(result.getPayloadBodies().size()).isEqualTo(3); |
||||
assertThat(result.getPayloadBodies().get(0)).isNull(); |
||||
assertThat(result.getPayloadBodies().get(1)).isNull(); |
||||
assertThat(result.getPayloadBodies().get(2)).isNull(); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldReturnNullForUnknownNumberAndPayloadForKnownNumber() { |
||||
final SignatureAlgorithm sig = SignatureAlgorithmFactory.getInstance(); |
||||
final Hash blockHash1 = Hash.wrap(Bytes32.random()); |
||||
final Hash blockHash3 = Hash.wrap(Bytes32.random()); |
||||
final BlockBody blockBody1 = |
||||
new BlockBody( |
||||
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), |
||||
Collections.emptyList()); |
||||
final BlockBody blockBody3 = |
||||
new BlockBody( |
||||
List.of( |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair())), |
||||
Collections.emptyList()); |
||||
when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(130)); |
||||
when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(blockBody1)); |
||||
when(blockchain.getBlockBody(blockHash3)).thenReturn(Optional.of(blockBody3)); |
||||
when(blockchain.getBlockHashByNumber(123)).thenReturn(Optional.of(blockHash1)); |
||||
when(blockchain.getBlockHashByNumber(125)).thenReturn(Optional.of(blockHash3)); |
||||
|
||||
final var resp = resp("0x7b", "0x3"); |
||||
final var result = fromSuccessResp(resp); |
||||
assertThat(result.getPayloadBodies().size()).isEqualTo(3); |
||||
assertThat(result.getPayloadBodies().get(0).getTransactions().size()).isEqualTo(1); |
||||
assertThat(result.getPayloadBodies().get(1)).isNull(); |
||||
assertThat(result.getPayloadBodies().get(2).getTransactions().size()).isEqualTo(3); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldReturnNullForWithdrawalsWhenBlockIsPreShanghai() { |
||||
final SignatureAlgorithm sig = SignatureAlgorithmFactory.getInstance(); |
||||
final Hash blockHash1 = Hash.wrap(Bytes32.random()); |
||||
final Hash blockHash2 = Hash.wrap(Bytes32.random()); |
||||
|
||||
final BlockBody preShanghaiBlockBody = |
||||
new BlockBody( |
||||
List.of( |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair())), |
||||
Collections.emptyList()); |
||||
|
||||
final BlockBody preShanghaiBlockBody2 = |
||||
new BlockBody( |
||||
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), |
||||
Collections.emptyList(), |
||||
Optional.empty()); |
||||
when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(130)); |
||||
when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(preShanghaiBlockBody)); |
||||
when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(preShanghaiBlockBody2)); |
||||
when(blockchain.getBlockHashByNumber(123)).thenReturn(Optional.of(blockHash1)); |
||||
when(blockchain.getBlockHashByNumber(124)).thenReturn(Optional.of(blockHash2)); |
||||
|
||||
final var resp = resp("0x7b", "0x2"); |
||||
final var result = fromSuccessResp(resp); |
||||
assertThat(result.getPayloadBodies().size()).isEqualTo(2); |
||||
assertThat(result.getPayloadBodies().get(0).getTransactions().size()).isEqualTo(3); |
||||
assertThat(result.getPayloadBodies().get(0).getWithdrawals()).isNull(); |
||||
assertThat(result.getPayloadBodies().get(1).getTransactions().size()).isEqualTo(1); |
||||
assertThat(result.getPayloadBodies().get(1).getWithdrawals()).isNull(); |
||||
; |
||||
} |
||||
|
||||
@Test |
||||
public void shouldReturnWithdrawalsWhenBlockIsPostShanghai() { |
||||
final SignatureAlgorithm sig = SignatureAlgorithmFactory.getInstance(); |
||||
final Hash blockHash1 = Hash.wrap(Bytes32.random()); |
||||
final Hash blockHash2 = Hash.wrap(Bytes32.random()); |
||||
final Withdrawal withdrawal = |
||||
new Withdrawal(UInt64.ONE, UInt64.ONE, Address.fromHexString("0x1"), GWei.ONE); |
||||
final Withdrawal withdrawal2 = |
||||
new Withdrawal(UInt64.ONE, UInt64.ONE, Address.fromHexString("0x2"), GWei.ONE); |
||||
|
||||
final BlockBody shanghaiBlockBody = |
||||
new BlockBody( |
||||
List.of( |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair())), |
||||
Collections.emptyList(), |
||||
Optional.of(List.of(withdrawal))); |
||||
|
||||
final BlockBody shanghaiBlockBody2 = |
||||
new BlockBody( |
||||
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), |
||||
Collections.emptyList(), |
||||
Optional.of(List.of(withdrawal2))); |
||||
when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(130)); |
||||
when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(shanghaiBlockBody)); |
||||
when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(shanghaiBlockBody2)); |
||||
when(blockchain.getBlockHashByNumber(123)).thenReturn(Optional.of(blockHash1)); |
||||
when(blockchain.getBlockHashByNumber(124)).thenReturn(Optional.of(blockHash2)); |
||||
|
||||
final var resp = resp("0x7b", "0x2"); |
||||
final var result = fromSuccessResp(resp); |
||||
assertThat(result.getPayloadBodies().size()).isEqualTo(2); |
||||
assertThat(result.getPayloadBodies().get(0).getTransactions().size()).isEqualTo(3); |
||||
assertThat(result.getPayloadBodies().get(0).getWithdrawals().size()).isEqualTo(1); |
||||
assertThat(result.getPayloadBodies().get(1).getTransactions().size()).isEqualTo(1); |
||||
assertThat(result.getPayloadBodies().get(1).getWithdrawals().size()).isEqualTo(1); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldNotContainTrailingNullForBlocksPastTheCurrentHead() { |
||||
final SignatureAlgorithm sig = SignatureAlgorithmFactory.getInstance(); |
||||
final Hash blockHash1 = Hash.wrap(Bytes32.random()); |
||||
final Withdrawal withdrawal = |
||||
new Withdrawal(UInt64.ONE, UInt64.ONE, Address.fromHexString("0x1"), GWei.ONE); |
||||
|
||||
final BlockBody shanghaiBlockBody = |
||||
new BlockBody( |
||||
List.of( |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), |
||||
new TransactionTestFixture().createTransaction(sig.generateKeyPair())), |
||||
Collections.emptyList(), |
||||
Optional.of(List.of(withdrawal))); |
||||
when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(123)); |
||||
when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(shanghaiBlockBody)); |
||||
when(blockchain.getBlockHashByNumber(123)).thenReturn(Optional.of(blockHash1)); |
||||
|
||||
final var resp = resp("0x7b", "0x3"); |
||||
final var result = fromSuccessResp(resp); |
||||
assertThat(result.getPayloadBodies().size()).isEqualTo(1); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldReturnUpUntilHeadWhenStartBlockPlusCountEqualsHeadNumber() { |
||||
final SignatureAlgorithm sig = SignatureAlgorithmFactory.getInstance(); |
||||
final Hash blockHash1 = Hash.wrap(Bytes32.random()); |
||||
final Hash blockHash2 = Hash.wrap(Bytes32.random()); |
||||
final Hash blockHash3 = Hash.wrap(Bytes32.random()); |
||||
final Withdrawal withdrawal = |
||||
new Withdrawal(UInt64.ONE, UInt64.ONE, Address.fromHexString("0x1"), GWei.ONE); |
||||
|
||||
final BlockBody shanghaiBlockBody = |
||||
new BlockBody( |
||||
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), |
||||
Collections.emptyList(), |
||||
Optional.of(List.of(withdrawal))); |
||||
final BlockBody shanghaiBlockBody2 = |
||||
new BlockBody( |
||||
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), |
||||
Collections.emptyList(), |
||||
Optional.of(List.of(withdrawal))); |
||||
final BlockBody shanghaiBlockBody3 = |
||||
new BlockBody( |
||||
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), |
||||
Collections.emptyList(), |
||||
Optional.of(List.of(withdrawal))); |
||||
when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(125)); |
||||
when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(shanghaiBlockBody)); |
||||
when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(shanghaiBlockBody2)); |
||||
when(blockchain.getBlockBody(blockHash3)).thenReturn(Optional.of(shanghaiBlockBody3)); |
||||
when(blockchain.getBlockHashByNumber(123)).thenReturn(Optional.of(blockHash1)); |
||||
when(blockchain.getBlockHashByNumber(124)).thenReturn(Optional.of(blockHash2)); |
||||
when(blockchain.getBlockHashByNumber(125)).thenReturn(Optional.of(blockHash3)); |
||||
|
||||
final var resp = resp("0x7b", "0x3"); |
||||
final var result = fromSuccessResp(resp); |
||||
assertThat(result.getPayloadBodies().size()).isEqualTo(3); |
||||
} |
||||
|
||||
@Test |
||||
public void ShouldReturnEmptyPayloadForRequestsPastCurrentHead() { |
||||
|
||||
when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(123)); |
||||
final JsonRpcResponse resp = resp("0x7d", "0x3"); |
||||
final var result = fromSuccessResp(resp); |
||||
assertThat(result.getPayloadBodies()).isEqualTo(Collections.EMPTY_LIST); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldReturnErrorWhenRequestExceedsPermittedNumberOfBlocks() { |
||||
doReturn(3).when(method).getMaxRequestBlocks(); |
||||
final JsonRpcResponse resp = resp("0x539", "0x4"); |
||||
final var result = fromErrorResp(resp); |
||||
assertThat(result.getCode()).isEqualTo(INVALID_RANGE_REQUEST_TOO_LARGE.getCode()); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldReturnInvalidParamsIfStartIsZero() { |
||||
final JsonRpcResponse resp = resp("0x0", "0x539"); |
||||
final var result = fromErrorResp(resp); |
||||
assertThat(result.getCode()).isEqualTo(INVALID_PARAMS.getCode()); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldReturnInvalidParamsIfCountIsZero() { |
||||
final JsonRpcResponse resp = resp("0x539", "0x0"); |
||||
final var result = fromErrorResp(resp); |
||||
assertThat(result.getCode()).isEqualTo(INVALID_PARAMS.getCode()); |
||||
} |
||||
|
||||
private JsonRpcResponse resp(final String startBlockNumber, final String range) { |
||||
return method.response( |
||||
new JsonRpcRequestContext( |
||||
new JsonRpcRequest( |
||||
"2.0", |
||||
RpcMethod.ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1.getMethodName(), |
||||
new Object[] {startBlockNumber, range}))); |
||||
} |
||||
|
||||
private EngineGetPayloadBodiesResultV1 fromSuccessResp(final JsonRpcResponse resp) { |
||||
assertThat(resp.getType()).isEqualTo(JsonRpcResponseType.SUCCESS); |
||||
return Optional.of(resp) |
||||
.map(JsonRpcSuccessResponse.class::cast) |
||||
.map(JsonRpcSuccessResponse::getResult) |
||||
.map(EngineGetPayloadBodiesResultV1.class::cast) |
||||
.get(); |
||||
} |
||||
|
||||
private JsonRpcError fromErrorResp(final JsonRpcResponse resp) { |
||||
assertThat(resp.getType()).isEqualTo(JsonRpcResponseType.ERROR); |
||||
return Optional.of(resp) |
||||
.map(JsonRpcErrorResponse.class::cast) |
||||
.map(JsonRpcErrorResponse::getError) |
||||
.get(); |
||||
} |
||||
} |
Loading…
Reference in new issue