mirror of
https://github.com/vacp2p/linea-besu.git
synced 2026-01-09 23:47:57 -05:00
[PAN-2946] - changes in core JSON-RPC method to support ReTestEth (#1815)
* [PAN-2946] - changes in core JSON-RPC method to support ReTestEth Some of the methods need to have a changeable reference to stuff like blockchainqueries. For the impacted methods the solution is to wrap them in a Supplier<> interface. This includes new constructors for re-used methods. Also include the debug_accountRangeAt method as it's namespaced as debug. Some features needed for retesteth are flag controlled to preserve current behaviors. Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
This commit is contained in:
@@ -44,13 +44,13 @@ public class IbftGetValidatorsByBlockNumber extends AbstractBlockParameterMethod
|
||||
|
||||
@Override
|
||||
protected BlockParameter blockParameter(final JsonRpcRequest request) {
|
||||
return parameters().required(request.getParams(), 0, BlockParameter.class);
|
||||
return getParameters().required(request.getParams(), 0, BlockParameter.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resultByBlockNumber(final JsonRpcRequest request, final long blockNumber) {
|
||||
final Optional<BlockHeader> blockHeader =
|
||||
blockchainQueries().getBlockHeaderByNumber(blockNumber);
|
||||
getBlockchainQueries().getBlockHeaderByNumber(blockNumber);
|
||||
LOG.trace("Received RPC rpcName={} block={}", getName(), blockNumber);
|
||||
return blockHeader
|
||||
.map(
|
||||
|
||||
@@ -496,7 +496,7 @@ public class JsonRpcHttpService {
|
||||
try (final TimingContext ignored = requestTimer.labels(request.getMethod()).startTimer()) {
|
||||
return method.response(request);
|
||||
} catch (final InvalidJsonRpcParameters e) {
|
||||
LOG.debug(e);
|
||||
LOG.debug("Invalid Params", e);
|
||||
return errorResponse(id, JsonRpcError.INVALID_PARAMS);
|
||||
} catch (final RuntimeException e) {
|
||||
LOG.error("Error processing JSON-RPC request", e);
|
||||
|
||||
@@ -25,6 +25,7 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.AdminChangeLogLev
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.AdminNodeInfo;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.AdminPeers;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.AdminRemovePeer;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.DebugAccountRange;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.DebugMetrics;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.DebugStorageRangeAt;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.DebugTraceBlock;
|
||||
@@ -262,6 +263,7 @@ public class JsonRpcMethodsFactory {
|
||||
enabledMethods,
|
||||
new DebugTraceTransaction(
|
||||
blockchainQueries, new TransactionTracer(blockReplay), parameter),
|
||||
new DebugAccountRange(parameter, blockchainQueries),
|
||||
new DebugStorageRangeAt(parameter, blockchainQueries, blockReplay),
|
||||
new DebugMetrics(metricsSystem),
|
||||
new DebugTraceBlock(
|
||||
@@ -352,7 +354,7 @@ public class JsonRpcMethodsFactory {
|
||||
return enabledMethods;
|
||||
}
|
||||
|
||||
private void addMethods(
|
||||
public static void addMethods(
|
||||
final Map<String, JsonRpcMethod> methods, final JsonRpcMethod... rpcMethods) {
|
||||
for (final JsonRpcMethod rpcMethod : rpcMethods) {
|
||||
methods.put(rpcMethod.getName(), rpcMethod);
|
||||
|
||||
@@ -20,14 +20,22 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse;
|
||||
|
||||
import java.util.OptionalLong;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
|
||||
public abstract class AbstractBlockParameterMethod implements JsonRpcMethod {
|
||||
|
||||
private final BlockchainQueries blockchainQueries;
|
||||
private final Supplier<BlockchainQueries> blockchainQueries;
|
||||
private final JsonRpcParameter parameters;
|
||||
|
||||
protected AbstractBlockParameterMethod(
|
||||
final BlockchainQueries blockchainQueries, final JsonRpcParameter parameters) {
|
||||
this(Suppliers.ofInstance(blockchainQueries), parameters);
|
||||
}
|
||||
|
||||
protected AbstractBlockParameterMethod(
|
||||
final Supplier<BlockchainQueries> blockchainQueries, final JsonRpcParameter parameters) {
|
||||
this.blockchainQueries = blockchainQueries;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
@@ -36,11 +44,11 @@ public abstract class AbstractBlockParameterMethod implements JsonRpcMethod {
|
||||
|
||||
protected abstract Object resultByBlockNumber(JsonRpcRequest request, long blockNumber);
|
||||
|
||||
protected BlockchainQueries blockchainQueries() {
|
||||
return blockchainQueries;
|
||||
protected BlockchainQueries getBlockchainQueries() {
|
||||
return blockchainQueries.get();
|
||||
}
|
||||
|
||||
protected JsonRpcParameter parameters() {
|
||||
protected JsonRpcParameter getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@@ -51,7 +59,7 @@ public abstract class AbstractBlockParameterMethod implements JsonRpcMethod {
|
||||
}
|
||||
|
||||
protected Object latestResult(final JsonRpcRequest request) {
|
||||
return resultByBlockNumber(request, blockchainQueries.headBlockNumber());
|
||||
return resultByBlockNumber(request, blockchainQueries.get().headBlockNumber());
|
||||
}
|
||||
|
||||
protected Object findResultByParamType(final JsonRpcRequest request) {
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 2019 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.core.Account;
|
||||
import tech.pegasys.pantheon.ethereum.core.BlockHeader;
|
||||
import tech.pegasys.pantheon.ethereum.core.Hash;
|
||||
import tech.pegasys.pantheon.ethereum.core.MutableWorldState;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.BlockParameterOrBlockHash;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockWithMetadata;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.DebugAccountRangeAtResult;
|
||||
import tech.pegasys.pantheon.util.bytes.Bytes32;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
|
||||
public class DebugAccountRange implements JsonRpcMethod {
|
||||
|
||||
private final JsonRpcParameter parameters;
|
||||
private final Supplier<BlockchainQueries> blockchainQueries;
|
||||
|
||||
public DebugAccountRange(
|
||||
final JsonRpcParameter parameters, final BlockchainQueries blockchainQueries) {
|
||||
this(parameters, Suppliers.ofInstance(blockchainQueries));
|
||||
}
|
||||
|
||||
public DebugAccountRange(
|
||||
final JsonRpcParameter parameters, final Supplier<BlockchainQueries> blockchainQueries) {
|
||||
this.parameters = parameters;
|
||||
this.blockchainQueries = blockchainQueries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
// TODO(shemnon) 5229b899 is the last stable commit of retesteth, after this they rename the
|
||||
// method to just "debug_accountRange". Once the tool is stable we will support the new name.
|
||||
return "debug_accountRangeAt";
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonRpcResponse response(final JsonRpcRequest request) {
|
||||
final Object[] params = request.getParams();
|
||||
final BlockParameterOrBlockHash blockParameterOrBlockHash =
|
||||
parameters.required(params, 0, BlockParameterOrBlockHash.class);
|
||||
final String addressHash = parameters.required(params, 2, String.class);
|
||||
final int maxResults = parameters.required(params, 3, Integer.TYPE);
|
||||
|
||||
final Optional<Hash> blockHashOptional = hashFromParameter(blockParameterOrBlockHash);
|
||||
if (blockHashOptional.isEmpty()) {
|
||||
return emptyResponse(request);
|
||||
}
|
||||
final Hash blockHash = blockHashOptional.get();
|
||||
final Optional<BlockHeader> blockHeaderOptional =
|
||||
blockchainQueries.get().blockByHash(blockHash).map(BlockWithMetadata::getHeader);
|
||||
if (blockHeaderOptional.isEmpty()) {
|
||||
return emptyResponse(request);
|
||||
}
|
||||
|
||||
// TODO deal with mid-block locations
|
||||
|
||||
final Optional<MutableWorldState> state =
|
||||
blockchainQueries.get().getWorldState(blockHeaderOptional.get().getNumber());
|
||||
|
||||
if (state.isEmpty()) {
|
||||
return emptyResponse(request);
|
||||
} else {
|
||||
final List<Account> accounts =
|
||||
state
|
||||
.get()
|
||||
.streamAccounts(Bytes32.fromHexStringLenient(addressHash), maxResults + 1)
|
||||
.collect(Collectors.toList());
|
||||
Bytes32 nextKey = Bytes32.ZERO;
|
||||
if (accounts.size() == maxResults + 1) {
|
||||
nextKey = accounts.get(maxResults).getAddressHash();
|
||||
accounts.remove(maxResults);
|
||||
}
|
||||
|
||||
return new JsonRpcSuccessResponse(
|
||||
request.getId(),
|
||||
new DebugAccountRangeAtResult(
|
||||
accounts.stream()
|
||||
.collect(
|
||||
Collectors.toMap(
|
||||
account -> account.getAddressHash().toString(),
|
||||
account -> account.getAddress().toString())),
|
||||
nextKey.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<Hash> hashFromParameter(final BlockParameterOrBlockHash blockParameter) {
|
||||
if (blockParameter.isEarliest()) {
|
||||
return blockchainQueries.get().getBlockHashByNumber(0);
|
||||
} else if (blockParameter.isLatest() || blockParameter.isPending()) {
|
||||
return blockchainQueries
|
||||
.get()
|
||||
.latestBlockWithTxHashes()
|
||||
.map(block -> block.getHeader().getHash());
|
||||
} else if (blockParameter.isNumeric()) {
|
||||
return blockchainQueries.get().getBlockHashByNumber(blockParameter.getNumber().getAsLong());
|
||||
} else {
|
||||
return blockParameter.getHash();
|
||||
}
|
||||
}
|
||||
|
||||
private JsonRpcSuccessResponse emptyResponse(final JsonRpcRequest request) {
|
||||
return new JsonRpcSuccessResponse(
|
||||
request.getId(), new DebugAccountRangeAtResult(Collections.emptyNavigableMap(), null));
|
||||
}
|
||||
}
|
||||
@@ -15,12 +15,15 @@ package tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods;
|
||||
import tech.pegasys.pantheon.ethereum.core.Account;
|
||||
import tech.pegasys.pantheon.ethereum.core.AccountStorageEntry;
|
||||
import tech.pegasys.pantheon.ethereum.core.Address;
|
||||
import tech.pegasys.pantheon.ethereum.core.BlockHeader;
|
||||
import tech.pegasys.pantheon.ethereum.core.Hash;
|
||||
import tech.pegasys.pantheon.ethereum.core.MutableWorldState;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.RpcMethod;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.BlockParameterOrBlockHash;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.BlockReplay;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockWithMetadata;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.TransactionWithMetadata;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse;
|
||||
@@ -28,22 +31,40 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessRe
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.DebugStorageRangeAtResult;
|
||||
import tech.pegasys.pantheon.util.bytes.Bytes32;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
|
||||
public class DebugStorageRangeAt implements JsonRpcMethod {
|
||||
|
||||
private final JsonRpcParameter parameters;
|
||||
private final BlockchainQueries blockchainQueries;
|
||||
private final BlockReplay blockReplay;
|
||||
private final Supplier<BlockchainQueries> blockchainQueries;
|
||||
private final Supplier<BlockReplay> blockReplay;
|
||||
private final boolean shortValues;
|
||||
|
||||
public DebugStorageRangeAt(
|
||||
final JsonRpcParameter parameters,
|
||||
final BlockchainQueries blockchainQueries,
|
||||
final BlockReplay blockReplay) {
|
||||
this(
|
||||
parameters,
|
||||
Suppliers.ofInstance(blockchainQueries),
|
||||
Suppliers.ofInstance(blockReplay),
|
||||
false);
|
||||
}
|
||||
|
||||
public DebugStorageRangeAt(
|
||||
final JsonRpcParameter parameters,
|
||||
final Supplier<BlockchainQueries> blockchainQueries,
|
||||
final Supplier<BlockReplay> blockReplay,
|
||||
final boolean shortValues) {
|
||||
this.parameters = parameters;
|
||||
this.blockchainQueries = blockchainQueries;
|
||||
this.blockReplay = blockReplay;
|
||||
this.shortValues = shortValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -53,25 +74,63 @@ public class DebugStorageRangeAt implements JsonRpcMethod {
|
||||
|
||||
@Override
|
||||
public JsonRpcResponse response(final JsonRpcRequest request) {
|
||||
final Hash blockHash = parameters.required(request.getParams(), 0, Hash.class);
|
||||
final BlockParameterOrBlockHash blockParameterOrBlockHash =
|
||||
parameters.required(request.getParams(), 0, BlockParameterOrBlockHash.class);
|
||||
final int transactionIndex = parameters.required(request.getParams(), 1, Integer.class);
|
||||
final Address accountAddress = parameters.required(request.getParams(), 2, Address.class);
|
||||
final Hash startKey = parameters.required(request.getParams(), 3, Hash.class);
|
||||
final Hash startKey =
|
||||
Hash.fromHexStringLenient(parameters.required(request.getParams(), 3, String.class));
|
||||
final int limit = parameters.required(request.getParams(), 4, Integer.class);
|
||||
|
||||
final Optional<Hash> blockHashOptional = hashFromParameter(blockParameterOrBlockHash);
|
||||
if (blockHashOptional.isEmpty()) {
|
||||
return emptyResponse(request);
|
||||
}
|
||||
final Hash blockHash = blockHashOptional.get();
|
||||
final Optional<BlockHeader> blockHeaderOptional =
|
||||
blockchainQueries.get().blockByHash(blockHash).map(BlockWithMetadata::getHeader);
|
||||
if (blockHeaderOptional.isEmpty()) {
|
||||
return emptyResponse(request);
|
||||
}
|
||||
|
||||
final Optional<TransactionWithMetadata> optional =
|
||||
blockchainQueries.transactionByBlockHashAndIndex(blockHash, transactionIndex);
|
||||
blockchainQueries.get().transactionByBlockHashAndIndex(blockHash, transactionIndex);
|
||||
|
||||
return optional
|
||||
.map(
|
||||
transactionWithMetadata ->
|
||||
(blockReplay
|
||||
.get()
|
||||
.afterTransactionInBlock(
|
||||
blockHash,
|
||||
transactionWithMetadata.getTransaction().hash(),
|
||||
(transaction, blockHeader, blockchain, worldState, transactionProcessor) ->
|
||||
extractStorageAt(request, accountAddress, startKey, limit, worldState))
|
||||
.orElseGet(() -> new JsonRpcSuccessResponse(request.getId(), null))))
|
||||
.orElseGet(() -> new JsonRpcSuccessResponse(request.getId(), null));
|
||||
.orElseGet(() -> emptyResponse(request))))
|
||||
.orElseGet(
|
||||
() ->
|
||||
blockchainQueries
|
||||
.get()
|
||||
.getWorldState(blockHeaderOptional.get().getNumber())
|
||||
.map(
|
||||
worldState ->
|
||||
extractStorageAt(request, accountAddress, startKey, limit, worldState))
|
||||
.orElseGet(() -> emptyResponse(request)));
|
||||
}
|
||||
|
||||
private Optional<Hash> hashFromParameter(final BlockParameterOrBlockHash blockParameter) {
|
||||
if (blockParameter.isEarliest()) {
|
||||
return blockchainQueries.get().getBlockHashByNumber(0);
|
||||
} else if (blockParameter.isLatest() || blockParameter.isPending()) {
|
||||
return blockchainQueries
|
||||
.get()
|
||||
.latestBlockWithTxHashes()
|
||||
.map(block -> block.getHeader().getHash());
|
||||
} else if (blockParameter.isNumeric()) {
|
||||
return blockchainQueries.get().getBlockHashByNumber(blockParameter.getNumber().getAsLong());
|
||||
} else {
|
||||
return blockParameter.getHash();
|
||||
}
|
||||
}
|
||||
|
||||
private JsonRpcSuccessResponse extractStorageAt(
|
||||
@@ -90,6 +149,12 @@ public class DebugStorageRangeAt implements JsonRpcMethod {
|
||||
entries.remove(nextKey);
|
||||
}
|
||||
return new JsonRpcSuccessResponse(
|
||||
request.getId(), new DebugStorageRangeAtResult(entries, nextKey));
|
||||
request.getId(), new DebugStorageRangeAtResult(entries, nextKey, shortValues));
|
||||
}
|
||||
|
||||
private JsonRpcSuccessResponse emptyResponse(final JsonRpcRequest request) {
|
||||
return new JsonRpcSuccessResponse(
|
||||
request.getId(),
|
||||
new DebugStorageRangeAtResult(Collections.emptyNavigableMap(), null, shortValues));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,12 +19,23 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.Quantity;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
|
||||
public class EthBlockNumber implements JsonRpcMethod {
|
||||
|
||||
private final BlockchainQueries blockchain;
|
||||
private final Supplier<BlockchainQueries> blockchain;
|
||||
private final boolean resultAsInteger;
|
||||
|
||||
public EthBlockNumber(final BlockchainQueries blockchain) {
|
||||
this(Suppliers.ofInstance(blockchain), false);
|
||||
}
|
||||
|
||||
public EthBlockNumber(
|
||||
final Supplier<BlockchainQueries> blockchain, final boolean resultAsInteger) {
|
||||
this.blockchain = blockchain;
|
||||
this.resultAsInteger = resultAsInteger;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -34,6 +45,8 @@ public class EthBlockNumber implements JsonRpcMethod {
|
||||
|
||||
@Override
|
||||
public JsonRpcResponse response(final JsonRpcRequest req) {
|
||||
return new JsonRpcSuccessResponse(req.getId(), Quantity.create(blockchain.headBlockNumber()));
|
||||
final long value = blockchain.get().headBlockNumber();
|
||||
return new JsonRpcSuccessResponse(
|
||||
req.getId(), resultAsInteger ? value : Quantity.create(value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public class EthCall extends AbstractBlockParameterMethod {
|
||||
|
||||
@Override
|
||||
protected BlockParameter blockParameter(final JsonRpcRequest request) {
|
||||
return parameters().required(request.getParams(), 1, BlockParameter.class);
|
||||
return getParameters().required(request.getParams(), 1, BlockParameter.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -80,7 +80,7 @@ public class EthCall extends AbstractBlockParameterMethod {
|
||||
|
||||
private CallParameter validateAndGetCallParams(final JsonRpcRequest request) {
|
||||
final JsonCallParameter callParams =
|
||||
parameters().required(request.getParams(), 0, JsonCallParameter.class);
|
||||
getParameters().required(request.getParams(), 0, JsonCallParameter.class);
|
||||
if (callParams.getTo() == null) {
|
||||
throw new InvalidJsonRpcParameters("Missing \"to\" field in call arguments");
|
||||
}
|
||||
|
||||
@@ -20,9 +20,18 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParamet
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.Quantity;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
|
||||
public class EthGetBalance extends AbstractBlockParameterMethod {
|
||||
|
||||
public EthGetBalance(final BlockchainQueries blockchain, final JsonRpcParameter parameters) {
|
||||
this(Suppliers.ofInstance(blockchain), parameters);
|
||||
}
|
||||
|
||||
public EthGetBalance(
|
||||
final Supplier<BlockchainQueries> blockchain, final JsonRpcParameter parameters) {
|
||||
super(blockchain, parameters);
|
||||
}
|
||||
|
||||
@@ -33,13 +42,13 @@ public class EthGetBalance extends AbstractBlockParameterMethod {
|
||||
|
||||
@Override
|
||||
protected BlockParameter blockParameter(final JsonRpcRequest request) {
|
||||
return parameters().required(request.getParams(), 1, BlockParameter.class);
|
||||
return getParameters().required(request.getParams(), 1, BlockParameter.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String resultByBlockNumber(final JsonRpcRequest request, final long blockNumber) {
|
||||
final Address address = parameters().required(request.getParams(), 0, Address.class);
|
||||
return blockchainQueries()
|
||||
final Address address = getParameters().required(request.getParams(), 0, Address.class);
|
||||
return getBlockchainQueries()
|
||||
.accountBalance(address, blockNumber)
|
||||
.map(Quantity::create)
|
||||
.orElse(null);
|
||||
|
||||
@@ -20,16 +20,30 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.BlockResult;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.BlockResultFactory;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
|
||||
public class EthGetBlockByNumber extends AbstractBlockParameterMethod {
|
||||
|
||||
private final BlockResultFactory blockResult;
|
||||
private final boolean includeCoinbase;
|
||||
|
||||
public EthGetBlockByNumber(
|
||||
final BlockchainQueries blockchain,
|
||||
final BlockResultFactory blockResult,
|
||||
final JsonRpcParameter parameters) {
|
||||
this(Suppliers.ofInstance(blockchain), blockResult, parameters, false);
|
||||
}
|
||||
|
||||
public EthGetBlockByNumber(
|
||||
final Supplier<BlockchainQueries> blockchain,
|
||||
final BlockResultFactory blockResult,
|
||||
final JsonRpcParameter parameters,
|
||||
final boolean includeCoinbase) {
|
||||
super(blockchain, parameters);
|
||||
this.blockResult = blockResult;
|
||||
this.includeCoinbase = includeCoinbase;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -39,7 +53,7 @@ public class EthGetBlockByNumber extends AbstractBlockParameterMethod {
|
||||
|
||||
@Override
|
||||
protected BlockParameter blockParameter(final JsonRpcRequest request) {
|
||||
return parameters().required(request.getParams(), 0, BlockParameter.class);
|
||||
return getParameters().required(request.getParams(), 0, BlockParameter.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -52,20 +66,20 @@ public class EthGetBlockByNumber extends AbstractBlockParameterMethod {
|
||||
}
|
||||
|
||||
private BlockResult transactionComplete(final long blockNumber) {
|
||||
return blockchainQueries()
|
||||
return getBlockchainQueries()
|
||||
.blockByNumber(blockNumber)
|
||||
.map(tx -> blockResult.transactionComplete(tx))
|
||||
.map(tx -> blockResult.transactionComplete(tx, includeCoinbase))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private BlockResult transactionHash(final long blockNumber) {
|
||||
return blockchainQueries()
|
||||
return getBlockchainQueries()
|
||||
.blockByNumberWithTxHashes(blockNumber)
|
||||
.map(tx -> blockResult.transactionHash(tx))
|
||||
.map(tx -> blockResult.transactionHash(tx, includeCoinbase))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private boolean isCompleteTransactions(final JsonRpcRequest request) {
|
||||
return parameters().required(request.getParams(), 1, Boolean.class);
|
||||
return getParameters().required(request.getParams(), 1, Boolean.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,11 +33,14 @@ public class EthGetBlockTransactionCountByNumber extends AbstractBlockParameterM
|
||||
|
||||
@Override
|
||||
protected BlockParameter blockParameter(final JsonRpcRequest request) {
|
||||
return parameters().required(request.getParams(), 0, BlockParameter.class);
|
||||
return getParameters().required(request.getParams(), 0, BlockParameter.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String resultByBlockNumber(final JsonRpcRequest req, final long blockNumber) {
|
||||
return blockchainQueries().getTransactionCount(blockNumber).map(Quantity::create).orElse(null);
|
||||
return getBlockchainQueries()
|
||||
.getTransactionCount(blockNumber)
|
||||
.map(Quantity::create)
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,9 +20,18 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParamet
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries;
|
||||
import tech.pegasys.pantheon.util.bytes.BytesValue;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
|
||||
public class EthGetCode extends AbstractBlockParameterMethod {
|
||||
|
||||
public EthGetCode(final BlockchainQueries blockchainQueries, final JsonRpcParameter parameters) {
|
||||
super(Suppliers.ofInstance(blockchainQueries), parameters);
|
||||
}
|
||||
|
||||
public EthGetCode(
|
||||
final Supplier<BlockchainQueries> blockchainQueries, final JsonRpcParameter parameters) {
|
||||
super(blockchainQueries, parameters);
|
||||
}
|
||||
|
||||
@@ -33,12 +42,15 @@ public class EthGetCode extends AbstractBlockParameterMethod {
|
||||
|
||||
@Override
|
||||
protected BlockParameter blockParameter(final JsonRpcRequest request) {
|
||||
return parameters().required(request.getParams(), 1, BlockParameter.class);
|
||||
return getParameters().required(request.getParams(), 1, BlockParameter.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String resultByBlockNumber(final JsonRpcRequest request, final long blockNumber) {
|
||||
final Address address = parameters().required(request.getParams(), 0, Address.class);
|
||||
return blockchainQueries().getCode(address, blockNumber).map(BytesValue::toString).orElse(null);
|
||||
final Address address = getParameters().required(request.getParams(), 0, Address.class);
|
||||
return getBlockchainQueries()
|
||||
.getCode(address, blockNumber)
|
||||
.map(BytesValue::toString)
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,15 +34,15 @@ public class EthGetStorageAt extends AbstractBlockParameterMethod {
|
||||
|
||||
@Override
|
||||
protected BlockParameter blockParameter(final JsonRpcRequest request) {
|
||||
return parameters().required(request.getParams(), 2, BlockParameter.class);
|
||||
return getParameters().required(request.getParams(), 2, BlockParameter.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String resultByBlockNumber(final JsonRpcRequest request, final long blockNumber) {
|
||||
final Address address = parameters().required(request.getParams(), 0, Address.class);
|
||||
final Address address = getParameters().required(request.getParams(), 0, Address.class);
|
||||
final UInt256 position =
|
||||
parameters().required(request.getParams(), 1, UInt256Parameter.class).getValue();
|
||||
return blockchainQueries()
|
||||
getParameters().required(request.getParams(), 1, UInt256Parameter.class).getValue();
|
||||
return getBlockchainQueries()
|
||||
.storageAt(address, position, blockNumber)
|
||||
.map(UInt256::toHexString)
|
||||
.orElse(null);
|
||||
|
||||
@@ -37,15 +37,15 @@ public class EthGetTransactionByBlockNumberAndIndex extends AbstractBlockParamet
|
||||
|
||||
@Override
|
||||
protected BlockParameter blockParameter(final JsonRpcRequest request) {
|
||||
return parameters().required(request.getParams(), 0, BlockParameter.class);
|
||||
return getParameters().required(request.getParams(), 0, BlockParameter.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resultByBlockNumber(final JsonRpcRequest request, final long blockNumber) {
|
||||
final int index =
|
||||
parameters().required(request.getParams(), 1, UnsignedIntParameter.class).getValue();
|
||||
getParameters().required(request.getParams(), 1, UnsignedIntParameter.class).getValue();
|
||||
final Optional<TransactionWithMetadata> transactionWithMetadata =
|
||||
blockchainQueries().transactionByBlockNumberAndIndex(blockNumber, index);
|
||||
getBlockchainQueries().transactionByBlockNumberAndIndex(blockNumber, index);
|
||||
return transactionWithMetadata.map(TransactionCompleteResult::new).orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,17 +22,34 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.Quantity;
|
||||
|
||||
import java.util.OptionalLong;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
|
||||
public class EthGetTransactionCount extends AbstractBlockParameterMethod {
|
||||
|
||||
private final PendingTransactions pendingTransactions;
|
||||
private final Supplier<PendingTransactions> pendingTransactions;
|
||||
private final boolean resultAsDecimal;
|
||||
|
||||
public EthGetTransactionCount(
|
||||
final BlockchainQueries blockchain,
|
||||
final PendingTransactions pendingTransactions,
|
||||
final JsonRpcParameter parameters) {
|
||||
this(
|
||||
Suppliers.ofInstance(blockchain),
|
||||
Suppliers.ofInstance(pendingTransactions),
|
||||
parameters,
|
||||
false);
|
||||
}
|
||||
|
||||
public EthGetTransactionCount(
|
||||
final Supplier<BlockchainQueries> blockchain,
|
||||
final Supplier<PendingTransactions> pendingTransactions,
|
||||
final JsonRpcParameter parameters,
|
||||
final boolean resultAsDecimal) {
|
||||
super(blockchain, parameters);
|
||||
this.pendingTransactions = pendingTransactions;
|
||||
this.resultAsDecimal = resultAsDecimal;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -42,13 +59,13 @@ public class EthGetTransactionCount extends AbstractBlockParameterMethod {
|
||||
|
||||
@Override
|
||||
protected BlockParameter blockParameter(final JsonRpcRequest request) {
|
||||
return parameters().required(request.getParams(), 1, BlockParameter.class);
|
||||
return getParameters().required(request.getParams(), 1, BlockParameter.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object pendingResult(final JsonRpcRequest request) {
|
||||
final Address address = parameters().required(request.getParams(), 0, Address.class);
|
||||
final OptionalLong pendingNonce = pendingTransactions.getNextNonceForSender(address);
|
||||
final Address address = getParameters().required(request.getParams(), 0, Address.class);
|
||||
final OptionalLong pendingNonce = pendingTransactions.get().getNextNonceForSender(address);
|
||||
if (pendingNonce.isPresent()) {
|
||||
return Quantity.create(pendingNonce.getAsLong());
|
||||
} else {
|
||||
@@ -58,10 +75,11 @@ public class EthGetTransactionCount extends AbstractBlockParameterMethod {
|
||||
|
||||
@Override
|
||||
protected String resultByBlockNumber(final JsonRpcRequest request, final long blockNumber) {
|
||||
final Address address = parameters().required(request.getParams(), 0, Address.class);
|
||||
if (blockNumber > blockchainQueries().headBlockNumber()) {
|
||||
final Address address = getParameters().required(request.getParams(), 0, Address.class);
|
||||
if (blockNumber > getBlockchainQueries().headBlockNumber()) {
|
||||
return null;
|
||||
}
|
||||
return Quantity.create(blockchainQueries().getTransactionCount(address, blockNumber));
|
||||
final long transactionCount = getBlockchainQueries().getTransactionCount(address, blockNumber);
|
||||
return resultAsDecimal ? Long.toString(transactionCount) : Quantity.create(transactionCount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,14 +35,14 @@ public class EthGetUncleByBlockNumberAndIndex extends AbstractBlockParameterMeth
|
||||
|
||||
@Override
|
||||
protected BlockParameter blockParameter(final JsonRpcRequest request) {
|
||||
return parameters().required(request.getParams(), 0, BlockParameter.class);
|
||||
return getParameters().required(request.getParams(), 0, BlockParameter.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BlockResult resultByBlockNumber(final JsonRpcRequest request, final long blockNumber) {
|
||||
final int index =
|
||||
parameters().required(request.getParams(), 1, UnsignedIntParameter.class).getValue();
|
||||
return blockchainQueries()
|
||||
getParameters().required(request.getParams(), 1, UnsignedIntParameter.class).getValue();
|
||||
return getBlockchainQueries()
|
||||
.getOmmer(blockNumber, index)
|
||||
.map(UncleBlockResult::build)
|
||||
.orElse(null);
|
||||
|
||||
@@ -33,11 +33,11 @@ public class EthGetUncleCountByBlockNumber extends AbstractBlockParameterMethod
|
||||
|
||||
@Override
|
||||
protected BlockParameter blockParameter(final JsonRpcRequest request) {
|
||||
return parameters().required(request.getParams(), 0, BlockParameter.class);
|
||||
return getParameters().required(request.getParams(), 0, BlockParameter.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String resultByBlockNumber(final JsonRpcRequest request, final long blockNumber) {
|
||||
return blockchainQueries().getOmmerCount(blockNumber).map(Quantity::create).orElse(null);
|
||||
return getBlockchainQueries().getOmmerCount(blockNumber).map(Quantity::create).orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ package tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods;
|
||||
|
||||
import static tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcErrorConverter.convertTransactionInvalidReason;
|
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Hash;
|
||||
import tech.pegasys.pantheon.ethereum.core.Transaction;
|
||||
import tech.pegasys.pantheon.ethereum.eth.transactions.TransactionPool;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.RpcMethod;
|
||||
@@ -30,20 +31,32 @@ import tech.pegasys.pantheon.ethereum.rlp.RLP;
|
||||
import tech.pegasys.pantheon.ethereum.rlp.RLPException;
|
||||
import tech.pegasys.pantheon.util.bytes.BytesValue;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class EthSendRawTransaction implements JsonRpcMethod {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger();
|
||||
private final boolean sendEmptyHashOnInvalidBlock;
|
||||
|
||||
private final TransactionPool transactionPool;
|
||||
private final Supplier<TransactionPool> transactionPool;
|
||||
private final JsonRpcParameter parameters;
|
||||
|
||||
public EthSendRawTransaction(
|
||||
final TransactionPool transactionPool, final JsonRpcParameter parameters) {
|
||||
this(Suppliers.ofInstance(transactionPool), parameters, false);
|
||||
}
|
||||
|
||||
public EthSendRawTransaction(
|
||||
final Supplier<TransactionPool> transactionPool,
|
||||
final JsonRpcParameter parameters,
|
||||
final boolean sendEmptyHashOnInvalidBlock) {
|
||||
this.transactionPool = transactionPool;
|
||||
this.parameters = parameters;
|
||||
this.sendEmptyHashOnInvalidBlock = sendEmptyHashOnInvalidBlock;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,12 +79,14 @@ public class EthSendRawTransaction implements JsonRpcMethod {
|
||||
}
|
||||
|
||||
final ValidationResult<TransactionInvalidReason> validationResult =
|
||||
transactionPool.addLocalTransaction(transaction);
|
||||
transactionPool.get().addLocalTransaction(transaction);
|
||||
return validationResult.either(
|
||||
() -> new JsonRpcSuccessResponse(request.getId(), transaction.hash().toString()),
|
||||
errorReason ->
|
||||
new JsonRpcErrorResponse(
|
||||
request.getId(), convertTransactionInvalidReason(errorReason)));
|
||||
sendEmptyHashOnInvalidBlock
|
||||
? new JsonRpcSuccessResponse(request.getId(), Hash.EMPTY.toString())
|
||||
: new JsonRpcErrorResponse(
|
||||
request.getId(), convertTransactionInvalidReason(errorReason)));
|
||||
}
|
||||
|
||||
private Transaction decodeRawTransaction(final String hash)
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.parameters;
|
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.BlockHeader;
|
||||
import tech.pegasys.pantheon.ethereum.core.Hash;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalLong;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
|
||||
/**
|
||||
* Represents a block parameter that can be a special value ("pending", "earliest", "latest") or a
|
||||
* number formatted as a hex string or a block hash.
|
||||
*
|
||||
* <p>When distinguishing between a hash and a number it is presumed that a hash won't have three
|
||||
* quarters of the leading bytes as zero. This is fined for block hashes but not for precompiled
|
||||
* contracts.
|
||||
*/
|
||||
public class BlockParameterOrBlockHash {
|
||||
|
||||
private final BlockParameterType type;
|
||||
private final OptionalLong number;
|
||||
private final Optional<Hash> blockHash;
|
||||
|
||||
@JsonCreator
|
||||
public BlockParameterOrBlockHash(final String value) {
|
||||
final String normalizedValue = value.toLowerCase();
|
||||
|
||||
if (Objects.equals(normalizedValue, "earliest")) {
|
||||
type = BlockParameterType.EARLIEST;
|
||||
number = OptionalLong.of(BlockHeader.GENESIS_BLOCK_NUMBER);
|
||||
blockHash = Optional.empty();
|
||||
} else if (Objects.equals(normalizedValue, "latest")) {
|
||||
type = BlockParameterType.LATEST;
|
||||
number = OptionalLong.empty();
|
||||
blockHash = Optional.empty();
|
||||
} else if (Objects.equals(normalizedValue, "pending")) {
|
||||
type = BlockParameterType.PENDING;
|
||||
number = OptionalLong.empty();
|
||||
blockHash = Optional.empty();
|
||||
} else if (normalizedValue.length() > 16) {
|
||||
type = BlockParameterType.HASH;
|
||||
number = OptionalLong.empty();
|
||||
blockHash = Optional.of(Hash.fromHexStringLenient(normalizedValue));
|
||||
} else {
|
||||
type = BlockParameterType.NUMERIC;
|
||||
number = OptionalLong.of(Long.decode(value));
|
||||
blockHash = Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public OptionalLong getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public Optional<Hash> getHash() {
|
||||
return blockHash;
|
||||
}
|
||||
|
||||
public boolean isPending() {
|
||||
return this.type == BlockParameterType.PENDING;
|
||||
}
|
||||
|
||||
public boolean isLatest() {
|
||||
return this.type == BlockParameterType.LATEST;
|
||||
}
|
||||
|
||||
public boolean isEarliest() {
|
||||
return this.type == BlockParameterType.EARLIEST;
|
||||
}
|
||||
|
||||
public boolean isNumeric() {
|
||||
return this.type == BlockParameterType.NUMERIC;
|
||||
}
|
||||
|
||||
public boolean getBlockHash() {
|
||||
return this.type == BlockParameterType.HASH;
|
||||
}
|
||||
|
||||
private enum BlockParameterType {
|
||||
EARLIEST,
|
||||
LATEST,
|
||||
PENDING,
|
||||
NUMERIC,
|
||||
HASH
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,8 @@ import tech.pegasys.pantheon.util.uint.UInt256;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonGetter;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
@@ -63,6 +65,7 @@ public class BlockResult implements JsonRpcResult {
|
||||
private final String timestamp;
|
||||
private final List<TransactionResult> transactions;
|
||||
private final List<JsonNode> ommers;
|
||||
private final String coinbase;
|
||||
|
||||
public <T extends TransactionResult> BlockResult(
|
||||
final BlockHeader header,
|
||||
@@ -70,6 +73,16 @@ public class BlockResult implements JsonRpcResult {
|
||||
final List<JsonNode> ommers,
|
||||
final UInt256 totalDifficulty,
|
||||
final int size) {
|
||||
this(header, transactions, ommers, totalDifficulty, size, false);
|
||||
}
|
||||
|
||||
public <T extends TransactionResult> BlockResult(
|
||||
final BlockHeader header,
|
||||
final List<TransactionResult> transactions,
|
||||
final List<JsonNode> ommers,
|
||||
final UInt256 totalDifficulty,
|
||||
final int size,
|
||||
final boolean includeCoinbase) {
|
||||
this.number = Quantity.create(header.getNumber());
|
||||
this.hash = header.getHash().toString();
|
||||
this.parentHash = header.getParentHash().toString();
|
||||
@@ -89,6 +102,7 @@ public class BlockResult implements JsonRpcResult {
|
||||
this.timestamp = Quantity.create(header.getTimestamp());
|
||||
this.ommers = ommers;
|
||||
this.transactions = transactions;
|
||||
this.coinbase = includeCoinbase ? header.getCoinbase().toString() : null;
|
||||
}
|
||||
|
||||
@JsonGetter(value = "number")
|
||||
@@ -185,4 +199,10 @@ public class BlockResult implements JsonRpcResult {
|
||||
public List<TransactionResult> getTransactions() {
|
||||
return transactions;
|
||||
}
|
||||
|
||||
@JsonGetter(value = "author")
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
public String getCoinbase() {
|
||||
return coinbase;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,12 @@ public class BlockResultFactory {
|
||||
|
||||
public BlockResult transactionComplete(
|
||||
final BlockWithMetadata<TransactionWithMetadata, Hash> blockWithMetadata) {
|
||||
return transactionComplete(blockWithMetadata, false);
|
||||
}
|
||||
|
||||
public BlockResult transactionComplete(
|
||||
final BlockWithMetadata<TransactionWithMetadata, Hash> blockWithMetadata,
|
||||
final boolean includeCoinbase) {
|
||||
final List<TransactionResult> txs =
|
||||
blockWithMetadata.getTransactions().stream()
|
||||
.map(TransactionCompleteResult::new)
|
||||
@@ -40,10 +46,16 @@ public class BlockResultFactory {
|
||||
txs,
|
||||
ommers,
|
||||
blockWithMetadata.getTotalDifficulty(),
|
||||
blockWithMetadata.getSize());
|
||||
blockWithMetadata.getSize(),
|
||||
includeCoinbase);
|
||||
}
|
||||
|
||||
public BlockResult transactionHash(final BlockWithMetadata<Hash, Hash> blockWithMetadata) {
|
||||
return transactionHash(blockWithMetadata, false);
|
||||
}
|
||||
|
||||
public BlockResult transactionHash(
|
||||
final BlockWithMetadata<Hash, Hash> blockWithMetadata, final boolean includeCoinbase) {
|
||||
final List<TransactionResult> txs =
|
||||
blockWithMetadata.getTransactions().stream()
|
||||
.map(Hash::toString)
|
||||
@@ -59,6 +71,7 @@ public class BlockResultFactory {
|
||||
txs,
|
||||
ommers,
|
||||
blockWithMetadata.getTotalDifficulty(),
|
||||
blockWithMetadata.getSize());
|
||||
blockWithMetadata.getSize(),
|
||||
includeCoinbase);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.results;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonGetter;
|
||||
|
||||
public class DebugAccountRangeAtResult implements JsonRpcResult {
|
||||
|
||||
private final Map<String, String> addressMap;
|
||||
private final String nextKey;
|
||||
|
||||
public DebugAccountRangeAtResult(final Map<String, String> addressMap, final String nextKey) {
|
||||
this.addressMap = addressMap;
|
||||
this.nextKey = nextKey;
|
||||
}
|
||||
|
||||
@JsonGetter(value = "addressMap")
|
||||
public Map<String, String> getAddressMap() {
|
||||
return addressMap;
|
||||
}
|
||||
|
||||
@JsonGetter(value = "nextKey")
|
||||
public String getNextKey() {
|
||||
return nextKey;
|
||||
}
|
||||
}
|
||||
@@ -30,9 +30,37 @@ public class DebugStorageRangeAtResult implements JsonRpcResult {
|
||||
private final String nextKey;
|
||||
|
||||
public DebugStorageRangeAtResult(
|
||||
final NavigableMap<Bytes32, AccountStorageEntry> entries, final Bytes32 nextKey) {
|
||||
entries.forEach((keyHash, entry) -> storage.put(keyHash.toString(), new StorageEntry(entry)));
|
||||
this.nextKey = nextKey != null ? nextKey.toString() : null;
|
||||
final NavigableMap<Bytes32, AccountStorageEntry> entries,
|
||||
final Bytes32 nextKey,
|
||||
final boolean shortValues) {
|
||||
if (shortValues) {
|
||||
entries.forEach(
|
||||
(keyHash, entry) ->
|
||||
storage.put(
|
||||
toStrictShortHexString(keyHash.toString()),
|
||||
new StorageEntry(entry, shortValues)));
|
||||
this.nextKey = nextKey != null ? nextKey.toString() : null;
|
||||
|
||||
} else {
|
||||
entries.forEach(
|
||||
(keyHash, entry) ->
|
||||
storage.put(keyHash.toString(), new StorageEntry(entry, shortValues)));
|
||||
this.nextKey = nextKey != null ? nextKey.toString() : null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String toStrictShortHexString(final String hex) {
|
||||
// Skipping '0x'
|
||||
if (hex.charAt(2) != '0') return hex;
|
||||
|
||||
int i = 3;
|
||||
while (i < hex.length() - 1 && hex.charAt(i) == '0') {
|
||||
i++;
|
||||
}
|
||||
// Align the trim so we get full bytes, not stray nybbles.
|
||||
i = i & 0xFFFFFFFE;
|
||||
|
||||
return "0x" + hex.substring(i);
|
||||
}
|
||||
|
||||
@JsonGetter(value = "storage")
|
||||
@@ -45,14 +73,24 @@ public class DebugStorageRangeAtResult implements JsonRpcResult {
|
||||
return nextKey;
|
||||
}
|
||||
|
||||
@JsonGetter(value = "complete")
|
||||
public boolean getComplete() {
|
||||
return nextKey == null;
|
||||
}
|
||||
|
||||
@JsonPropertyOrder(value = {"key", "value"})
|
||||
public static class StorageEntry {
|
||||
private final String value;
|
||||
private final String key;
|
||||
|
||||
public StorageEntry(final AccountStorageEntry entry) {
|
||||
this.value = entry.getValue().toHexString();
|
||||
this.key = entry.getKey().map(UInt256::toHexString).orElse(null);
|
||||
public StorageEntry(final AccountStorageEntry entry, final boolean shortValues) {
|
||||
if (shortValues) {
|
||||
this.value = entry.getValue().toStrictShortHexString();
|
||||
this.key = entry.getKey().map(UInt256::toStrictShortHexString).orElse(null);
|
||||
} else {
|
||||
this.value = entry.getValue().toHexString();
|
||||
this.key = entry.getKey().map(UInt256::toHexString).orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
@JsonGetter(value = "key")
|
||||
@@ -67,7 +105,7 @@ public class DebugStorageRangeAtResult implements JsonRpcResult {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper(this).add("value", value).toString();
|
||||
return MoreObjects.toStringHelper(this).add("key", key).add("value", value).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -103,7 +103,7 @@ public abstract class AbstractEthJsonRpcHttpServiceTest {
|
||||
protected final int NETWORK_ID = 123;
|
||||
|
||||
protected static final Collection<RpcApi> JSON_RPC_APIS =
|
||||
Arrays.asList(RpcApis.ETH, RpcApis.NET, RpcApis.WEB3);
|
||||
Arrays.asList(RpcApis.ETH, RpcApis.NET, RpcApis.WEB3, RpcApis.DEBUG);
|
||||
|
||||
protected MutableBlockchain blockchain;
|
||||
|
||||
|
||||
@@ -14,10 +14,12 @@ package tech.pegasys.pantheon.ethereum.jsonrpc;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.DebugAccountRange;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.EthBlockNumber;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.EthCall;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.EthEstimateGas;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.EthGetBalance;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.EthGetBlockByNumber;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.EthGetBlockTransactionCountByHash;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.EthGetBlockTransactionCountByNumber;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.EthGetCode;
|
||||
@@ -84,6 +86,9 @@ public class EthJsonRpcHttpBySpecTest extends AbstractEthJsonRpcHttpServiceTest
|
||||
specs.put(EthGetBalance.class, "eth_getBalance_illegalRangeLessThan");
|
||||
specs.put(EthGetBalance.class, "eth_getBalance_invalidParams");
|
||||
|
||||
specs.put(EthGetBlockByNumber.class, "eth_getBlockByNumber_complete");
|
||||
specs.put(EthGetBlockByNumber.class, "eth_getBlockByNumber_hashes");
|
||||
|
||||
specs.put(EthGetStorageAt.class, "eth_getStorageAt_latest");
|
||||
specs.put(EthGetStorageAt.class, "eth_getStorageAt_invalidParams");
|
||||
specs.put(EthGetStorageAt.class, "eth_getStorageAt_illegalRangeGreaterThan");
|
||||
@@ -239,6 +244,13 @@ public class EthJsonRpcHttpBySpecTest extends AbstractEthJsonRpcHttpServiceTest
|
||||
|
||||
specs.put(EthProtocolVersion.class, "eth_protocolVersion");
|
||||
|
||||
specs.put(DebugAccountRange.class, "debug_accountRange_blockHash");
|
||||
specs.put(DebugAccountRange.class, "debug_accountRange_complete");
|
||||
specs.put(DebugAccountRange.class, "debug_accountRange_partial");
|
||||
specs.put(DebugAccountRange.class, "debug_storageRangeAt_blockHash");
|
||||
specs.put(DebugAccountRange.class, "debug_storageRangeAt_blockNumber");
|
||||
specs.put(DebugAccountRange.class, "debug_storageRangeAt_midBlock");
|
||||
|
||||
return specs.values();
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.BlockReplay;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.BlockReplay.TransactionAction;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockWithMetadata;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.TransactionWithMetadata;
|
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse;
|
||||
@@ -42,6 +43,7 @@ import tech.pegasys.pantheon.util.bytes.Bytes32;
|
||||
import tech.pegasys.pantheon.util.uint.UInt256;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.NavigableMap;
|
||||
@@ -85,9 +87,16 @@ public class DebugStorageRangeAtTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldRetrieveStorageRange() {
|
||||
public void shouldRetrieveStorageRange_fullValues() {
|
||||
final TransactionWithMetadata transactionWithMetadata =
|
||||
new TransactionWithMetadata(transaction, 12L, blockHash, TRANSACTION_INDEX);
|
||||
final BlockWithMetadata<TransactionWithMetadata, Hash> blockWithMetadata =
|
||||
new BlockWithMetadata<>(
|
||||
blockHeader,
|
||||
Collections.singletonList(transactionWithMetadata),
|
||||
Collections.emptyList(),
|
||||
UInt256.ONE,
|
||||
1);
|
||||
final JsonRpcRequest request =
|
||||
new JsonRpcRequest(
|
||||
"2.0",
|
||||
@@ -96,6 +105,7 @@ public class DebugStorageRangeAtTest {
|
||||
blockHash.toString(), TRANSACTION_INDEX, accountAddress, START_KEY_HASH.toString(), 10
|
||||
});
|
||||
|
||||
when(blockchainQueries.blockByHash(blockHash)).thenReturn(Optional.of(blockWithMetadata));
|
||||
when(blockchainQueries.transactionByBlockHashAndIndex(blockHash, TRANSACTION_INDEX))
|
||||
.thenReturn(Optional.of(transactionWithMetadata));
|
||||
when(worldState.get(accountAddress)).thenReturn(account);
|
||||
@@ -122,9 +132,9 @@ public class DebugStorageRangeAtTest {
|
||||
entries.sort(Comparator.comparing(AccountStorageEntry::getKeyHash));
|
||||
assertThat(result.getStorage())
|
||||
.containsExactly(
|
||||
entry(entries.get(0).getKeyHash().toString(), new StorageEntry(entries.get(0))),
|
||||
entry(entries.get(1).getKeyHash().toString(), new StorageEntry(entries.get(1))),
|
||||
entry(entries.get(2).getKeyHash().toString(), new StorageEntry(entries.get(2))));
|
||||
entry(entries.get(0).getKeyHash().toString(), new StorageEntry(entries.get(0), false)),
|
||||
entry(entries.get(1).getKeyHash().toString(), new StorageEntry(entries.get(1), false)),
|
||||
entry(entries.get(2).getKeyHash().toString(), new StorageEntry(entries.get(2), false)));
|
||||
}
|
||||
|
||||
private Object callAction(final InvocationOnMock invocation) {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"request": {
|
||||
"id": 415,
|
||||
"jsonrpc": "2.0",
|
||||
"method": "debug_accountRangeAt",
|
||||
"params": [
|
||||
"0xc8df1f061abb4d0c107b2b1a794ade8780b3120e681f723fe55a7be586d95ba6",
|
||||
"0x1",
|
||||
"0xbcde5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||
2
|
||||
]
|
||||
},
|
||||
"response": {
|
||||
"jsonrpc": "2.0",
|
||||
"id": 415,
|
||||
"result": {
|
||||
"addressMap": {
|
||||
"0x15b040a190663dd210787de31621bae9fb17d6b59d1cd1d319c0ed452d7a0f15": "0xbcde5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||
"0x03601462093b5945d1676df093446790fd31b20e7b12a2e8e5e09d068109616b": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"
|
||||
},
|
||||
"nextKey": "0xa32fbb2bcac38ed596cbb34ae265df4d60b832ce8077a3abc6f57b4611005cfd"
|
||||
}
|
||||
},
|
||||
"statusCode": 200
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"request": {
|
||||
"id": 414,
|
||||
"jsonrpc": "2.0",
|
||||
"method": "debug_accountRangeAt",
|
||||
"params": [
|
||||
"0x10",
|
||||
"0x1",
|
||||
"0x0",
|
||||
100
|
||||
]
|
||||
},
|
||||
"response": {
|
||||
"jsonrpc": "2.0",
|
||||
"id": 414,
|
||||
"result": {
|
||||
"addressMap": {
|
||||
"0x15b040a190663dd210787de31621bae9fb17d6b59d1cd1d319c0ed452d7a0f15" : "0xbcde5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||
"0x03601462093b5945d1676df093446790fd31b20e7b12a2e8e5e09d068109616b" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||
"0xa32fbb2bcac38ed596cbb34ae265df4d60b832ce8077a3abc6f57b4611005cfd" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
|
||||
"0xeb8ec137a2f5a74ec3a73144b552caad890b18b5f725872fa212fff6d4d565ba" : "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f"
|
||||
},
|
||||
"nextKey": "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
},
|
||||
"statusCode": 200
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"request": {
|
||||
"id": 415,
|
||||
"jsonrpc": "2.0",
|
||||
"method": "debug_accountRangeAt",
|
||||
"params": [
|
||||
"0x10",
|
||||
"0x1",
|
||||
"0xbcde5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||
2
|
||||
]
|
||||
},
|
||||
"response": {
|
||||
"jsonrpc": "2.0",
|
||||
"id": 415,
|
||||
"result": {
|
||||
"addressMap": {
|
||||
"0x15b040a190663dd210787de31621bae9fb17d6b59d1cd1d319c0ed452d7a0f15": "0xbcde5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||
"0x03601462093b5945d1676df093446790fd31b20e7b12a2e8e5e09d068109616b": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"
|
||||
},
|
||||
"nextKey": "0xa32fbb2bcac38ed596cbb34ae265df4d60b832ce8077a3abc6f57b4611005cfd"
|
||||
}
|
||||
},
|
||||
"statusCode": 200
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"request": {
|
||||
"id": 414,
|
||||
"jsonrpc": "2.0",
|
||||
"method": "debug_storageRangeAt",
|
||||
"params": [
|
||||
"0xc8df1f061abb4d0c107b2b1a794ade8780b3120e681f723fe55a7be586d95ba6",
|
||||
1,
|
||||
"0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
|
||||
"0",
|
||||
100
|
||||
]
|
||||
},
|
||||
"response": {
|
||||
"jsonrpc": "2.0",
|
||||
"id": 414,
|
||||
"result": {
|
||||
"storage": {
|
||||
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563": {
|
||||
"key": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"value": "0x000000000000000000000000000000000000000000000000000000000008fa01"
|
||||
},
|
||||
"0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace": {
|
||||
"key": "0x0000000000000000000000000000000000000000000000000000000000000002",
|
||||
"value": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee"
|
||||
},
|
||||
"0x8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b": {
|
||||
"key": "0x0000000000000000000000000000000000000000000000000000000000000004",
|
||||
"value": "0xaabbccffffffffffffffffffffffffffffffffffffffffffffffffffffffffee"
|
||||
},
|
||||
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6": {
|
||||
"key": "0x0000000000000000000000000000000000000000000000000000000000000001",
|
||||
"value": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee"
|
||||
},
|
||||
"0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b": {
|
||||
"key": "0x0000000000000000000000000000000000000000000000000000000000000003",
|
||||
"value": "0xaabbccffffffffffffffffffffffffffffffffffffffffffffffffffffffffee"
|
||||
}
|
||||
},
|
||||
"complete": true
|
||||
}
|
||||
},
|
||||
"statusCode": 200
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"request": {
|
||||
"id": 414,
|
||||
"jsonrpc": "2.0",
|
||||
"method": "debug_storageRangeAt",
|
||||
"params": [
|
||||
"0x1e",
|
||||
1,
|
||||
"0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
|
||||
"0",
|
||||
100
|
||||
]
|
||||
},
|
||||
"response": {
|
||||
"jsonrpc": "2.0",
|
||||
"id": 414,
|
||||
"result": {
|
||||
"storage": {
|
||||
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563": {
|
||||
"key": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"value": "0x000000000000000000000000000000000000000000000000000000000008fa01"
|
||||
},
|
||||
"0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace": {
|
||||
"key": "0x0000000000000000000000000000000000000000000000000000000000000002",
|
||||
"value": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee"
|
||||
},
|
||||
"0x8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b": {
|
||||
"key": "0x0000000000000000000000000000000000000000000000000000000000000004",
|
||||
"value": "0xaabbccffffffffffffffffffffffffffffffffffffffffffffffffffffffffee"
|
||||
},
|
||||
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6": {
|
||||
"key": "0x0000000000000000000000000000000000000000000000000000000000000001",
|
||||
"value": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee"
|
||||
},
|
||||
"0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b": {
|
||||
"key": "0x0000000000000000000000000000000000000000000000000000000000000003",
|
||||
"value": "0xaabbccffffffffffffffffffffffffffffffffffffffffffffffffffffffffee"
|
||||
}
|
||||
},
|
||||
"complete": true
|
||||
}
|
||||
},
|
||||
"statusCode": 200
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"request": {
|
||||
"id": 414,
|
||||
"jsonrpc": "2.0",
|
||||
"method": "debug_storageRangeAt",
|
||||
"params": [
|
||||
"0x1e",
|
||||
0,
|
||||
"0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
|
||||
"0",
|
||||
100
|
||||
]
|
||||
},
|
||||
"response": {
|
||||
"jsonrpc": "2.0",
|
||||
"id": 414,
|
||||
"result": {
|
||||
"storage": {
|
||||
"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563": {
|
||||
"key": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"value": "0x000000000000000000000000000000000000000000000000000000000008fa01"
|
||||
},
|
||||
"0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace": {
|
||||
"key": "0x0000000000000000000000000000000000000000000000000000000000000002",
|
||||
"value": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee"
|
||||
},
|
||||
"0x8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b": {
|
||||
"key": "0x0000000000000000000000000000000000000000000000000000000000000004",
|
||||
"value": "0xaabbccffffffffffffffffffffffffffffffffffffffffffffffffffffffffee"
|
||||
},
|
||||
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6": {
|
||||
"key": "0x0000000000000000000000000000000000000000000000000000000000000001",
|
||||
"value": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee"
|
||||
},
|
||||
"0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b": {
|
||||
"key": "0x0000000000000000000000000000000000000000000000000000000000000003",
|
||||
"value": "0xaabbccffffffffffffffffffffffffffffffffffffffffffffffffffffffffee"
|
||||
}
|
||||
},
|
||||
"complete": true
|
||||
}
|
||||
},
|
||||
"statusCode": 200
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"request": {
|
||||
"id": 174,
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_getBlockByNumber",
|
||||
"params": [
|
||||
"0x10",
|
||||
true
|
||||
]
|
||||
},
|
||||
"response": {
|
||||
"jsonrpc": "2.0",
|
||||
"id": 174,
|
||||
"result": {
|
||||
"number": "0x10",
|
||||
"hash": "0x1878c6f27178250f3d55186a2887b076936599f307d96dabcf331b2ff0a38f0c",
|
||||
"parentHash": "0x9dcd5e20cc30e48e3635ac3a1c398c2f45ee818fcbc232110878ddf0e936e7ea",
|
||||
"nonce": "0xdfc50ac1134d764f",
|
||||
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"transactionsRoot": "0x399a0923c02fd28a351a11cbf2fd647225c0a69a67d7e04ad1c35c9435fc7d82",
|
||||
"stateRoot": "0xf4814dce3c4230ab409f92001f88e55d63ed5a23d84c73ad3fad1222ba06cb7a",
|
||||
"receiptsRoot": "0x3e5fff5f6eaeee82841547e049b6bdb980c4e6bd8539fb072a346a30ee72a25d",
|
||||
"miner": "0x8888f1f195afa192cfee860698584c030f4c9db1",
|
||||
"difficulty": "0x203c0",
|
||||
"totalDifficulty": "0x221e00",
|
||||
"extraData": "0x",
|
||||
"size": "0x288",
|
||||
"gasLimit": "0x2fefd8",
|
||||
"gasUsed": "0xab90",
|
||||
"timestamp": "0x561bc307",
|
||||
"uncles": [],
|
||||
"transactions": [
|
||||
{
|
||||
"blockHash": "0x1878c6f27178250f3d55186a2887b076936599f307d96dabcf331b2ff0a38f0c",
|
||||
"blockNumber": "0x10",
|
||||
"from": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||
"gas": "0x4cb2f",
|
||||
"gasPrice": "0x1",
|
||||
"hash": "0x9f6a5eb65991ce483a9e1bfc57b44cd2c8ff4c26ca804240d593b4b63c3eafcd",
|
||||
"input": "0xc2b12a73aabbccffffffffffffffffffffffffffffffffffffffffffffffffffffffffee",
|
||||
"nonce": "0xf",
|
||||
"to": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
|
||||
"transactionIndex": "0x0",
|
||||
"value": "0xa",
|
||||
"v": "0x1b",
|
||||
"r": "0x394fa9c43a2469d48b98f4f7e8dfdf7bd3c7abd9eafe8c124b362594aafc5d6",
|
||||
"s": "0xecf369283eda15f4c4db09784b5226dfe48a0a80ff91e87d858f6adbb131cf9"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"statusCode": 200
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"request": {
|
||||
"id": 174,
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_getBlockByNumber",
|
||||
"params": [
|
||||
"0x10",
|
||||
false
|
||||
]
|
||||
},
|
||||
"response": {
|
||||
"jsonrpc": "2.0",
|
||||
"id": 174,
|
||||
"result": {
|
||||
"number": "0x10",
|
||||
"hash": "0x1878c6f27178250f3d55186a2887b076936599f307d96dabcf331b2ff0a38f0c",
|
||||
"parentHash": "0x9dcd5e20cc30e48e3635ac3a1c398c2f45ee818fcbc232110878ddf0e936e7ea",
|
||||
"nonce": "0xdfc50ac1134d764f",
|
||||
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"transactionsRoot": "0x399a0923c02fd28a351a11cbf2fd647225c0a69a67d7e04ad1c35c9435fc7d82",
|
||||
"stateRoot": "0xf4814dce3c4230ab409f92001f88e55d63ed5a23d84c73ad3fad1222ba06cb7a",
|
||||
"receiptsRoot": "0x3e5fff5f6eaeee82841547e049b6bdb980c4e6bd8539fb072a346a30ee72a25d",
|
||||
"miner": "0x8888f1f195afa192cfee860698584c030f4c9db1",
|
||||
"difficulty": "0x203c0",
|
||||
"totalDifficulty": "0x221e00",
|
||||
"extraData": "0x",
|
||||
"size": "0x288",
|
||||
"gasLimit": "0x2fefd8",
|
||||
"gasUsed": "0xab90",
|
||||
"timestamp": "0x561bc307",
|
||||
"uncles": [],
|
||||
"transactions": [
|
||||
"0x9f6a5eb65991ce483a9e1bfc57b44cd2c8ff4c26ca804240d593b4b63c3eafcd"
|
||||
]
|
||||
}
|
||||
},
|
||||
"statusCode": 200
|
||||
}
|
||||
Reference in New Issue
Block a user