[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:
Danno Ferrin
2019-08-02 15:23:57 -06:00
committed by GitHub
parent 3df37ead00
commit f1f7b69dfd
34 changed files with 893 additions and 72 deletions

View File

@@ -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(

View File

@@ -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);

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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));
}
}

View File

@@ -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));
}
}

View File

@@ -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));
}
}

View File

@@ -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");
}

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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)

View File

@@ -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
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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) {

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}