-
Notifications
You must be signed in to change notification settings - Fork 130
Conversation
and eth_getBlockByNumber
`./retesteth/retesteth -t BlockchainTests/bcStateTests -- --testpath ../../tests/ --clients pantheon` I suspect DebugStorageRangeAt is most of the problem.
Use GenesisState to do a lot of what was done by hand.
* Add header validation mode based on seal engine * rework account storage range, input is in decimal, so use existing super class * catch another invalid RLP
us from istanbul's chainId requirement.
* set the timestamp of the system (requires a genesis rebuild) * add a raw transaction * then mine the blocks.
# Conflicts: # ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolScheduleBuilder.java
All tests run. Not all tests pass. There's some stuff relating to mining and protocol schedules I need to fix.
I nede to intercept several classes to get the block reward change everywhere it needs to be.
# Conflicts: # ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/DebuggableMutableWorldState.java # ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/WorldStateArchive.java # ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/DebugStorageRangeAtResult.java # ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/DebugStorageRangeAtTest.java
# Conflicts: # ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldState.java
# Conflicts: # ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockCreator.java # ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/headervalidationrules/ProofOfWorkValidationRule.java
# Conflicts: # util/src/main/java/tech/pegasys/pantheon/util/uint/UInt256Value.java
# Conflicts: # ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/AbstractBlockCreator.java # ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetBlockProcessor.java
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. Also, rename the getter methods to align with standards.
# Conflicts: # ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockCreatorTest.java
* restore missing spec tests * rename to debig_accountRange * make sure stack trace come with invalidjsonrpcparams catch
# Conflicts: # ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/chain/DefaultMutableBlockchain.java # ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/DebugAccountRange.java # ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/DebugStorageRangeAt.java # ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/BlockResult.java # ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/BlockResultFactory.java # ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/DebugStorageRangeAtResult.java # ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/EthJsonRpcHttpBySpecTest.java
Currently works with retesteth at branch 9a4609a5d7d84b61734c2dbb5d2d8cf4981b33e0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haven't finished looking over everything - just dropping in a few comments for now 😄
public class NoProofSolver extends EthHashSolver { | ||
|
||
NoProofSolver(final Iterable<Long> nonceGenerator) { | ||
super(nonceGenerator, null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about creating an EthHashSolver
interface, so we don't have to set null values in the superclass? Doesn't look like you're using anything significant from the superclass? Then the implementation EthHashSolver
becomes DefaultEthHashSolver
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An interface already exists, and it's a functional interface. Reduced it to a lambda.
final ProtocolSpec<C> original = delegate.getByBlockNumber(number); | ||
// Pre Spurious Dragon we need to "touch" the accounts to create a zero-balance version. We use | ||
// the maximum possible reward as a sentinel value. | ||
final boolean skipZeroBlockRewards = !TOUCH_ACCOUNT_SCHEDULES.contains(original.getName()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you just use:
final boolean skipZeroBlockRewards = !TOUCH_ACCOUNT_SCHEDULES.contains(original.getName()); | |
final boolean skipZeroBlockRewards = original.isSkipZeroBlockRewards(); |
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep. Style tweak to eliminate the variable since it's not calculated.
public ProtocolSpec<C> getByBlockNumber(final long number) { | ||
final ProtocolSpec<C> original = delegate.getByBlockNumber(number); | ||
// Pre Spurious Dragon we need to "touch" the accounts to create a zero-balance version. We use | ||
// the maximum possible reward as a sentinel value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like an outdated comment here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
original.getTransactionReceiptFactory(), | ||
original.getDifficultyCalculator(), | ||
Wei.ZERO, // block reward | ||
null, // transaction receipt type; unused |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should remove this param or set something here - thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds like a reasonable activity, but that kind of refactor should stand on its own PR IMHO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Turns out this is to support EIP-658, so no it cannot be removed. Perhaps a different comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you look at the ProtocolSpec
constructor, this field is never actually used so looks like it can be removed safely. Alternatively a less invasive change might be to add a getter for the field and set the value here to origin.getReceiptType()
(plus log a ticket to remove later).
As a general principle, I want to avoid using nulls even if it makes sense right now because over time it will make the code more brittle and we've done a pretty good job of avoiding nulls up to this point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in #1825
private EthHashSolver ethHashSolver; | ||
|
||
public boolean resetContext( | ||
final String genesisConfigString, final String sealEngine, final Optional<Long> clockTime) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about creating an enum
for sealEngine
rather than just letting it be any string?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My concern is how do we deal with new random values? The testing team has already shown that they will introduce random undocumented values ("NoReward") and I expect at least one other arbitrary add ("ProgPow" or some variant of the name). If we make an enum then unexpected test evolution becomes a parsing error and we fail with an RPC exception instead of bad data. Retesteh is already bad when it comes to reporting back data on the RPC failures (i.e. which test tripped it) but is much better about state failures.
So if PegaSys was controlling the code I'd say yes, but I don't feel we can trust the community code will behave well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍Makes sense to me as-is then
|
||
protocolSchedule = | ||
MainnetProtocolSchedule.fromConfig( | ||
JsonGenesisConfigOptions.fromJsonObject((ObjectNode) genesisConfig.get("config"))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(optional) There's also JsonUtil.getObjectNode
which avoids the casting :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
rename debug_accountRange
original.getTransactionReceiptFactory(), | ||
original.getDifficultyCalculator(), | ||
Wei.ZERO, // block reward | ||
null, // transaction receipt type; unused |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you look at the ProtocolSpec
constructor, this field is never actually used so looks like it can be removed safely. Alternatively a less invasive change might be to add a getter for the field and set the value here to origin.getReceiptType()
(plus log a ticket to remove later).
As a general principle, I want to avoid using nulls even if it makes sense right now because over time it will make the code more brittle and we've done a pretty good job of avoiding nulls up to this point.
|
||
blockchainQueries = new BlockchainQueries(blockchain, worldStateArchive); | ||
|
||
final String sealengine = JsonUtil.getString(genesisConfig, "sealengine", ""); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be worth normalizing the sealengine
value with toLowerCase()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sealEngine values are canonically mixed case, per the docs that do cover it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just makes everything more stable if casing inconsistencies crop up even if there's a supposed canonical form for each value.
/* Converts all to lowercase for easier lookup since the keys in a 'genesis.json' file are assumed | ||
* case insensitive. | ||
*/ | ||
private static ObjectNode normalizeKeys(final ObjectNode genesis) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be worth deduping this method by moving it to JsonUtil
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll do this and the receiptType in another PR by the end of the day and then merge them in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done in #1826
final JsonRpcParameter parameters = new JsonRpcParameter(); | ||
final BlockResultFactory blockResult = new BlockResultFactory(); | ||
final Map<String, JsonRpcMethod> jsonRpcMethods = new HashMap<>(); | ||
JsonRpcMethodsFactory.addMethods( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(nit) In retrospect seems unnecessary to publicly expose this method, when it's just looping over some methods and adding them to a hashmap.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's either expose it publicly or duplicate it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally, I'd duplicate - its not a lot of code 🤷♀
context.getBlockchainQueries().transactionReceiptByTransactionHash(txHash); | ||
return new JsonRpcSuccessResponse( | ||
request.getId(), | ||
receipt.map(this::calculateLogHash).orElse(Hash.EMPTY_LIST_HASH).toString()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is Hash.EMPTY_LIST_HASH
the right default? The general json-rpc pattern has been to return null
if a value isn't found. The hash of empty list implies that the receipt was found and has no logs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is what retesteth specified when they defined the method. It does feel like an implementation detail leaking through but returning null breaks the RPC tests.
public JsonRpcResponse response(final JsonRpcRequest request) { | ||
long blocksToMine = parameters.required(request.getParams(), 0, Long.class); | ||
while (blocksToMine-- > 0) { | ||
if (!context.mineNewBlock()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels like this mineNewBlock
method should be a method in this class, rather than sitting in context
. When I see a "context" class I don't usually expect it to be doing real work, but just providing access to dependencies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@Override | ||
public JsonRpcResponse response(final JsonRpcRequest request) { | ||
final long epochSeconds = parameters.required(request.getParams(), 0, Long.class); | ||
context.setTimestamp(epochSeconds); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here - seems like you should be getting the clock from context
, and resetting the value in this method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
public JsonRpcResponse response(final JsonRpcRequest request) { | ||
final long blockNumber = parameters.required(request.getParams(), 0, Long.TYPE); | ||
|
||
return new JsonRpcSuccessResponse(request.getId(), context.rewindToBlock(blockNumber)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as above - seems like you should be getting the blockchain
from context
and then rewinding here. Or alternatively, maybe context
has an "actions" object that holds various retesteth actions? Seems more cohesive to just house the logic here though unless there's a lot of reuse.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
import com.google.common.base.Charsets; | ||
import com.google.common.io.Resources; | ||
|
||
class RetestethFixtures { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this class is unused.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, when I duplicated the RPC methods I also duplicated the test classes and testing support. Looks like this is indeed dead and should be removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Move the `normalizeKeys` method into JsonUtil as Retesteth will re-use it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me!
|
||
blockchainQueries = new BlockchainQueries(blockchain, worldStateArchive); | ||
|
||
final String sealengine = JsonUtil.getString(genesisConfig, "sealengine", ""); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just makes everything more stable if casing inconsistencies crop up even if there's a supposed canonical form for each value.
final JsonRpcParameter parameters = new JsonRpcParameter(); | ||
final BlockResultFactory blockResult = new BlockResultFactory(); | ||
final Map<String, JsonRpcMethod> jsonRpcMethods = new HashMap<>(); | ||
JsonRpcMethodsFactory.addMethods( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally, I'd duplicate - its not a lot of code 🤷♀
PR description
Add support for retesteth, a JSON-RPC based reference testing API.
Fixed Issue(s)
PAN-2949 PAN-2950 PAN-2951 PAN-2935 PAN-2954 PAN-2955