Add eth_getBlockReceipts() JSON/RPC method (#5771)

* Initial commit with new JSON/RPC method

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* Update CHANGELOG.md

Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>
Signed-off-by: Matt Whitehead <matthew1001@hotmail.com>

* Update unit tests to check receipts against generated blockchain transactions at runtime. Add getEthSerializedType() utility to TransactionType.

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* Add spec JSON/RPC tests

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

---------

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>
Signed-off-by: Matt Whitehead <matthew1001@gmail.com>
Signed-off-by: Matt Whitehead <matthew1001@hotmail.com>
Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>
Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>
This commit is contained in:
Matt Whitehead
2023-08-24 02:59:40 +01:00
committed by GitHub
parent 6bd3135713
commit 9a0f35c1fe
16 changed files with 564 additions and 5 deletions

View File

@@ -6,13 +6,13 @@
- Add new methods to `OperationTracer` to capture contexts enter/exit [#5756](https://github.com/hyperledger/besu/pull/5756)
### Breaking Changes
- Add ABI-decoded revert reason to `eth_call` and `eth_estimateGas` responses [#5705](https://github.com/hyperledger/besu/issues/5705)
### Additions and Improvements
- Add missing methods to the `Transaction` interface [#5732](https://github.com/hyperledger/besu/pull/5732)
- Added `benchmark` subcommand to `evmtool` [#5754](https://github.com/hyperledger/besu/issues/5754)
- Add `benchmark` subcommand to `evmtool` [#5754](https://github.com/hyperledger/besu/issues/5754)
- JSON output is now compact by default. This can be overridden by the new `--json-pretty-print-enabled` CLI option. [#5766](https://github.com/hyperledger/besu/pull/5766)
- New `eth_getBlockReceipts` JSON-RPC method to retrieve all transaction receipts for a block in a single call [#5771](https://github.com/hyperledger/besu/pull/5771)
- Add new methods to `OperationTracer` to capture contexts enter/exit [#5756](https://github.com/hyperledger/besu/pull/5756)
### Bug Fixes

View File

@@ -50,6 +50,17 @@ public enum TransactionType {
return (byte) this.typeValue;
}
/**
* Gets serialized type for returning in an eth transaction result, factoring in the special case
* for FRONTIER transactions which have enum type 0xf8 but are represented as 0x00 in transaction
* results.
*
* @return the serialized type
*/
public byte getEthSerializedType() {
return (this == FRONTIER ? 0x00 : this.getSerializedType());
}
/**
* Compare to serialized type.
*

View File

@@ -98,6 +98,7 @@ public enum RpcMethod {
ETH_GET_BALANCE("eth_getBalance"),
ETH_GET_BLOCK_BY_HASH("eth_getBlockByHash"),
ETH_GET_BLOCK_BY_NUMBER("eth_getBlockByNumber"),
ETH_GET_BLOCK_RECEIPTS("eth_getBlockReceipts"),
ETH_GET_BLOCK_TRANSACTION_COUNT_BY_HASH("eth_getBlockTransactionCountByHash"),
ETH_GET_BLOCK_TRANSACTION_COUNT_BY_NUMBER("eth_getBlockTransactionCountByNumber"),
ETH_GET_CODE("eth_getCode"),

View File

@@ -0,0 +1,96 @@
/*
* 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;
import org.hyperledger.besu.datatypes.Hash;
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.parameters.BlockParameterOrBlockHash;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockReceiptsResult;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionReceiptResult;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionReceiptRootResult;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionReceiptStatusResult;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata;
import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.TransactionReceiptType;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import com.google.common.base.Suppliers;
public class EthGetBlockReceipts extends AbstractBlockParameterOrBlockHashMethod {
private final ProtocolSchedule protocolSchedule;
public EthGetBlockReceipts(
final BlockchainQueries blockchain, final ProtocolSchedule protocolSchedule) {
super(Suppliers.ofInstance(blockchain));
this.protocolSchedule = protocolSchedule;
}
@Override
public String getName() {
return RpcMethod.ETH_GET_BLOCK_RECEIPTS.getMethodName();
}
@Override
protected BlockParameterOrBlockHash blockParameterOrBlockHash(
final JsonRpcRequestContext request) {
return request.getRequiredParameter(0, BlockParameterOrBlockHash.class);
}
@Override
protected Object resultByBlockHash(final JsonRpcRequestContext request, final Hash blockHash) {
return getBlockReceiptsResult(blockHash);
}
/*
* For a given transaction, get its receipt and if it exists, wrap in a transaction receipt of the correct type
*/
private Optional<TransactionReceiptResult> txReceipt(final TransactionWithMetadata tx) {
Optional<TransactionReceiptWithMetadata> receipt =
blockchainQueries
.get()
.transactionReceiptByTransactionHash(tx.getTransaction().getHash(), protocolSchedule);
if (receipt.isPresent()) {
if (receipt.get().getReceipt().getTransactionReceiptType() == TransactionReceiptType.ROOT) {
return Optional.of(new TransactionReceiptRootResult(receipt.get()));
} else {
return Optional.of(new TransactionReceiptStatusResult(receipt.get()));
}
}
return Optional.empty();
}
private BlockReceiptsResult getBlockReceiptsResult(final Hash blockHash) {
final List<TransactionReceiptResult> receiptList =
blockchainQueries
.get()
.blockByHash(blockHash)
.map(
block ->
block.getTransactions().stream()
.map(tx -> txReceipt(tx).get())
.collect(Collectors.toList()))
.orElse(new ArrayList<>());
return new BlockReceiptsResult(receiptList);
}
}

View File

@@ -0,0 +1,34 @@
/*
* 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 java.util.List;
import com.fasterxml.jackson.annotation.JsonValue;
/** The result set from querying the receipts for a given block. */
public class BlockReceiptsResult {
private final List<TransactionReceiptResult> results;
public BlockReceiptsResult(final List<TransactionReceiptResult> receipts) {
results = receipts;
}
@JsonValue
public List<TransactionReceiptResult> getResults() {
return results;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright ConsenSys AG.
* 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
@@ -28,6 +28,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGasPrice;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetBalance;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetBlockByHash;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetBlockByNumber;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetBlockReceipts;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetBlockTransactionCountByHash;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetBlockTransactionCountByNumber;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetCode;
@@ -119,6 +120,7 @@ public class EthJsonRpcMethods extends ApiGroupJsonRpcMethods {
new EthGetBalance(blockchainQueries),
new EthGetBlockByHash(blockchainQueries, blockResult),
new EthGetBlockByNumber(blockchainQueries, blockResult, synchronizer),
new EthGetBlockReceipts(blockchainQueries, protocolSchedule),
new EthGetBlockTransactionCountByNumber(blockchainQueries),
new EthGetBlockTransactionCountByHash(blockchainQueries),
new EthCall(

View File

@@ -0,0 +1,195 @@
/*
* 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;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryBlockchain;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import org.hyperledger.besu.datatypes.Hash;
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.exception.InvalidJsonRpcParameters;
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.api.jsonrpc.internal.results.BlockReceiptsResult;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionReceiptResult;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class EthGetBlockReceiptsTest {
private static final int BLOCKCHAIN_LENGTH = 5;
private static final String ZERO_HASH = String.valueOf(Hash.ZERO);
private static final String HASH_63_CHARS_LONG =
"0xd3d3d1340c085e1b14182e01fd0b7cc5b585dca77f809f78fcca3e1a165b189";
private static final String ETH_METHOD = "eth_getBlockReceipts";
private static final String JSON_RPC_VERSION = "2.0";
@Mock private BlockchainQueries blockchainQueries;
@Mock private WorldStateArchive worldStateArchive;
private MutableBlockchain blockchain;
private static final BlockDataGenerator blockDataGenerator = new BlockDataGenerator();
private EthGetBlockReceipts method;
private ProtocolSchedule protocolSchedule;
final JsonRpcResponse blockNotFoundResponse =
new JsonRpcErrorResponse(null, RpcErrorType.BLOCK_NOT_FOUND);
@BeforeEach
public void setUp() {
blockchain = createInMemoryBlockchain(blockDataGenerator.genesisBlock());
for (int i = 1; i < BLOCKCHAIN_LENGTH; i++) {
final BlockDataGenerator.BlockOptions options =
new BlockDataGenerator.BlockOptions()
.setBlockNumber(i)
.setParentHash(blockchain.getBlockHashByNumber(i - 1).orElseThrow());
final Block block = blockDataGenerator.block(options);
final List<TransactionReceipt> receipts = blockDataGenerator.receipts(block);
blockchain.appendBlock(block, receipts);
}
blockchainQueries = spy(new BlockchainQueries(blockchain, worldStateArchive));
protocolSchedule = mock(ProtocolSchedule.class);
method = new EthGetBlockReceipts(blockchainQueries, protocolSchedule);
}
@Test
public void returnsCorrectMethodName() {
assertThat(method.getName()).isEqualTo(ETH_METHOD);
}
@Test
public void exceptionWhenNoParamsSupplied() {
assertThatThrownBy(() -> method.response(requestWithParams()))
.isInstanceOf(InvalidJsonRpcParameters.class)
.hasMessage("Missing required json rpc parameter at index 0");
verifyNoMoreInteractions(blockchainQueries);
}
@Test
public void exceptionWhenBlockNumberTooLarge() {
assertThatThrownBy(() -> method.response(requestWithParams("0x1212121212121212121212")))
.isInstanceOf(InvalidJsonRpcParameters.class);
verifyNoMoreInteractions(blockchainQueries);
}
@Test
public void twoReceiptsForLatestBlock() {
// Read expected transactions from the generated blockchain
final Transaction expectedTx1 =
blockchain.getBlockByNumber(BLOCKCHAIN_LENGTH - 1).get().getBody().getTransactions().get(0);
final Transaction expectedTx2 =
blockchain.getBlockByNumber(BLOCKCHAIN_LENGTH - 1).get().getBody().getTransactions().get(1);
/* Block generator defaults to 2 transactions per mocked block */
JsonRpcResponse actualResponse = method.response(requestWithParams("latest"));
assertThat(actualResponse).isInstanceOf(JsonRpcSuccessResponse.class);
final BlockReceiptsResult result =
(BlockReceiptsResult) ((JsonRpcSuccessResponse) actualResponse).getResult();
assertThat(result.getResults().size()).isEqualTo(2);
// Check TX1 receipt is correct
TransactionReceiptResult tx1 = result.getResults().get(0);
assertThat(tx1.getBlockNumber()).isEqualTo("0x" + (BLOCKCHAIN_LENGTH - 1));
assertThat(tx1.getEffectiveGasPrice()).isNotEmpty();
assertThat(tx1.getTo()).isEqualTo(expectedTx1.getTo().get().toString());
assertThat(tx1.getType())
.isEqualTo(String.format("0x%X", expectedTx1.getType().getEthSerializedType()));
// Check TX2 receipt is correct
TransactionReceiptResult tx2 = result.getResults().get(1);
assertThat(tx2.getBlockNumber()).isEqualTo("0x" + (BLOCKCHAIN_LENGTH - 1));
assertThat(tx2.getEffectiveGasPrice()).isNotEmpty();
assertThat(tx2.getTo()).isEqualTo(expectedTx2.getTo().get().toString());
assertThat(tx2.getType())
.isEqualTo(String.format("0x%X", expectedTx2.getType().getEthSerializedType()));
}
@Test
public void twoReceiptsForBlockOne() {
// Read expected transactions from the generated blockchain
final Transaction expectedTx1 =
blockchain.getBlockByNumber(1).get().getBody().getTransactions().get(0);
final Transaction expectedTx2 =
blockchain.getBlockByNumber(1).get().getBody().getTransactions().get(1);
/* Block generator defaults to 2 transactions per block */
JsonRpcResponse actualResponse = method.response(requestWithParams("0x01"));
assertThat(actualResponse).isInstanceOf(JsonRpcSuccessResponse.class);
final BlockReceiptsResult result =
(BlockReceiptsResult) ((JsonRpcSuccessResponse) actualResponse).getResult();
assertThat(result.getResults().size()).isEqualTo(2);
// Check TX1 receipt is correct
TransactionReceiptResult tx1 = result.getResults().get(0);
assertThat(tx1.getBlockNumber()).isEqualTo("0x1");
assertThat(tx1.getEffectiveGasPrice()).isNotEmpty();
assertThat(tx1.getTo()).isEqualTo(expectedTx1.getTo().get().toString());
assertThat(tx1.getType())
.isEqualTo(String.format("0x%X", expectedTx1.getType().getEthSerializedType()));
// Check TX2 receipt is correct
TransactionReceiptResult tx2 = result.getResults().get(1);
assertThat(tx2.getBlockNumber()).isEqualTo("0x1");
assertThat(tx2.getEffectiveGasPrice()).isNotEmpty();
assertThat(tx2.getTo()).isEqualTo(expectedTx2.getTo().get().toString());
assertThat(tx2.getType())
.isEqualTo(String.format("0x%X", expectedTx2.getType().getEthSerializedType()));
}
@Test
public void blockNotFoundWhenHash63CharsLong() {
/* Valid hash with 63 chars in - should result in block not found */
JsonRpcResponse actualResponse = method.response(requestWithParams(HASH_63_CHARS_LONG));
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(blockNotFoundResponse);
}
@Test
public void blockNotFoundForZeroHash() {
/* Zero hash - should result in block not found */
JsonRpcResponse actualResponse = method.response(requestWithParams(ZERO_HASH));
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(blockNotFoundResponse);
}
private JsonRpcRequestContext requestWithParams(final Object... params) {
return new JsonRpcRequestContext(new JsonRpcRequest(JSON_RPC_VERSION, ETH_METHOD, params));
}
}

View File

@@ -0,0 +1,31 @@
{
"request": {
"id": 302,
"jsonrpc": "2.0",
"method": "eth_getBlockReceipts",
"params": [
"0x1878c6f27178250f3d55186a2887b076936599f307d96dabcf331b2ff0a38f0c"
]
},
"response": {
"jsonrpc": "2.0",
"id": 302,
"result": [ {
"blockHash" : "0x1878c6f27178250f3d55186a2887b076936599f307d96dabcf331b2ff0a38f0c",
"blockNumber" : "0x10",
"contractAddress" : null,
"cumulativeGasUsed" : "0xab90",
"from" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"gasUsed" : "0xab90",
"effectiveGasPrice" : "0x1",
"logs" : [ ],
"logsBloom" : "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"root" : "0xed8541244d07552bed21ab19a7a26bc9f6ac0826d91c20fed11961a746270af0",
"to" : "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
"transactionHash" : "0x9f6a5eb65991ce483a9e1bfc57b44cd2c8ff4c26ca804240d593b4b63c3eafcd",
"transactionIndex" : "0x0",
"type" : "0x0"
} ]
},
"statusCode": 200
}

View File

@@ -0,0 +1,19 @@
{
"request": {
"id": 303,
"jsonrpc": "2.0",
"method": "eth_getBlockReceipts",
"params": [
"0x0000000000000000000000000000000000000000000000000000000000000000"
]
},
"response": {
"jsonrpc": "2.0",
"id": 303,
"error" : {
"code" : -32000,
"message" : "Block not found"
}
},
"statusCode": 200
}

View File

@@ -0,0 +1,31 @@
{
"request": {
"id": 304,
"jsonrpc": "2.0",
"method": "eth_getBlockReceipts",
"params": [
"0x1"
]
},
"response": {
"jsonrpc": "2.0",
"id": 304,
"result": [ {
"blockHash" : "0x10aaf14a53caf27552325374429d3558398a36d3682ede6603c2c6511896e9f9",
"blockNumber" : "0x1",
"contractAddress" : "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
"cumulativeGasUsed" : "0x78674",
"from" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"gasUsed" : "0x78674",
"effectiveGasPrice" : "0x1",
"logs" : [ ],
"logsBloom" : "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"root" : "0x6a59608add7cee26032d1c5c3923b91d0b50e6103f61b2137b68229bcdc87395",
"to" : null,
"transactionHash" : "0x812742182a79a8e67733edc58cfa3767aa2d7ad06439d156ddbbb33e3403b4ed",
"transactionIndex" : "0x0",
"type" : "0x0"
} ]
},
"statusCode": 200
}

View File

@@ -0,0 +1,41 @@
{
"request": {
"id": 305,
"jsonrpc": "2.0",
"method": "eth_getBlockReceipts",
"params": [
"0x20"
]
},
"response": {
"jsonrpc": "2.0",
"id": 305,
"result": [ {
"blockHash" : "0x71d59849ddd98543bdfbe8548f5eed559b07b8aaf196369f39134500eab68e53",
"blockNumber" : "0x20",
"contractAddress" : null,
"cumulativeGasUsed" : "0x5c99",
"from" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"gasUsed" : "0x5c99",
"effectiveGasPrice" : "0x1",
"logs" : [ {
"address" : "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
"topics" : [ "0x0000000000000000000000000000000000000000000000000000000000000001", "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ],
"data" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe9000000000000000000000000000000000000000000000000000000000000002a",
"blockNumber" : "0x20",
"transactionHash" : "0xcef53f2311d7c80e9086d661e69ac11a5f3d081e28e02a9ba9b66749407ac310",
"transactionIndex" : "0x0",
"blockHash" : "0x71d59849ddd98543bdfbe8548f5eed559b07b8aaf196369f39134500eab68e53",
"logIndex" : "0x0",
"removed" : false
} ],
"logsBloom" : "0x00000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000080000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000400000000000000000200000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000800000000040000000000000000000000000000000000000000010000000000000000000000000",
"root" : "0x6d54fb51c667e4cc4bd8f2633b675f831b35d7784a70b5df91cd58f593c5286e",
"to" : "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
"transactionHash" : "0xcef53f2311d7c80e9086d661e69ac11a5f3d081e28e02a9ba9b66749407ac310",
"transactionIndex" : "0x0",
"type" : "0x0"
} ]
},
"statusCode": 200
}

View File

@@ -0,0 +1,19 @@
{
"request": {
"id": 306,
"jsonrpc": "2.0",
"method": "eth_getBlockReceipts",
"params": [
"0x20202020202020"
]
},
"response": {
"jsonrpc": "2.0",
"id": 306,
"error" : {
"code" : -32000,
"message" : "Block not found"
}
},
"statusCode": 200
}

View File

@@ -0,0 +1,41 @@
{
"request": {
"id": 307,
"jsonrpc": "2.0",
"method": "eth_getBlockReceipts",
"params": [
"latest"
]
},
"response": {
"jsonrpc": "2.0",
"id": 307,
"result": [ {
"blockHash" : "0x71d59849ddd98543bdfbe8548f5eed559b07b8aaf196369f39134500eab68e53",
"blockNumber" : "0x20",
"contractAddress" : null,
"cumulativeGasUsed" : "0x5c99",
"from" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"gasUsed" : "0x5c99",
"effectiveGasPrice" : "0x1",
"logs" : [ {
"address" : "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
"topics" : [ "0x0000000000000000000000000000000000000000000000000000000000000001", "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ],
"data" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe9000000000000000000000000000000000000000000000000000000000000002a",
"blockNumber" : "0x20",
"transactionHash" : "0xcef53f2311d7c80e9086d661e69ac11a5f3d081e28e02a9ba9b66749407ac310",
"transactionIndex" : "0x0",
"blockHash" : "0x71d59849ddd98543bdfbe8548f5eed559b07b8aaf196369f39134500eab68e53",
"logIndex" : "0x0",
"removed" : false
} ],
"logsBloom" : "0x00000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000080000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000400000000000000000200000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000800000000040000000000000000000000000000000000000000010000000000000000000000000",
"root" : "0x6d54fb51c667e4cc4bd8f2633b675f831b35d7784a70b5df91cd58f593c5286e",
"to" : "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
"transactionHash" : "0xcef53f2311d7c80e9086d661e69ac11a5f3d081e28e02a9ba9b66749407ac310",
"transactionIndex" : "0x0",
"type" : "0x0"
} ]
},
"statusCode": 200
}

View File

@@ -0,0 +1,19 @@
{
"request": {
"id": 300,
"jsonrpc": "2.0",
"method": "eth_getBlockReceipts",
"params": [
"0x02020202020202020202020202"
]
},
"response": {
"jsonrpc": "2.0",
"id": 300,
"error" : {
"code" : -32602,
"message" : "Invalid params"
}
},
"statusCode": 200
}

View File

@@ -0,0 +1,19 @@
{
"request": {
"id": 301,
"jsonrpc": "2.0",
"method": "eth_getBlockReceipts",
"params": [
"invalidtag"
]
},
"response": {
"jsonrpc": "2.0",
"id": 301,
"error" : {
"code" : -32602,
"message" : "Invalid params"
}
},
"statusCode": 200
}

View File

@@ -81,7 +81,7 @@ public class TransactionAnnouncementEncoder {
for (int i = 0; i < transactions.size(); i++) {
final TransactionType type = transactions.get(i).getType();
types[i] = type == TransactionType.FRONTIER ? 0x00 : type.getSerializedType();
types[i] = type.getEthSerializedType();
sizes.add(transactions.get(i).getSize());
hashes.add(transactions.get(i).getHash());
}
@@ -96,7 +96,7 @@ public class TransactionAnnouncementEncoder {
final byte[] byteTypes = new byte[types.size()];
for (int i = 0; i < types.size(); i++) {
final TransactionType type = types.get(i);
byteTypes[i] = type == TransactionType.FRONTIER ? 0x00 : type.getSerializedType();
byteTypes[i] = type.getEthSerializedType();
}
return encodeForEth68(byteTypes, sizes, hashes);
}