-
Notifications
You must be signed in to change notification settings - Fork 766
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[VM] fix blockchain tests and add Homestead support #815
Conversation
Codecov Report
Flags with carried forward coverage won't be shown. Click here to find out more. |
Right this is bad. TangerineWhistle tests are not passing at all. Byzantium+ seems to locally pass (haven't ran all tests though but it seems like those forks work). TangerineWhistle:
SpuriousDragon:
My gut says it is because of Embedding Transaction Status in Receipt Trie (introduced in Byzantium). VM also has a note about this. |
If I generate the state root and put that state root in the receipt then the tests pass for Spurious Dragon and for Tangerine Whistle 1 test fails. Failing test: We thus need a way to keep the checkpoint/revert/commit functionality of |
t.comment("skipping test: no data available for " + options.forkConfigTestSuite) | ||
return | ||
} | ||
|
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 too late in the process, false forks should be already filtered out when the test files are read (currently the code logic in ethereumjs-util
) and there should be no output on this, this is otherwise causing too much unnecessary noise.
Will do a follow-up comment here: #808
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 see where you are getting from, but this is not the case for state tests either: files are read and are then filtered out (this is thus not done in the ethereumjs-testing
module, but actually in the state test runner which we define in the VM package).
So this is inconsistent. Do you think we should move this check to ethereumjs-testing
? (Such that the runner never skips any tests?). I see in #808 you have moved all the testing logic in the VM package and I think this is a good idea; we can then move these fork checks to a more 'natural' place (i.e. the tests filter) and then let the runner only do anything if it actually has the right data to test.
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.
Ok, will see this as resolved for now.
Will push some commits soon which has #814 merged on top of it. This changes |
|
Homestead:
This does need the ethereumjs/ethereumjs-util#269 PR merged though, otherwise randomStatetest94 fails. Will push asap. |
packages/vm/lib/evm/opFns.ts
Outdated
runState.eei.useGas(new BN(runState._common.param('gasPrices', 'callNewAccount'))) | ||
} | ||
|
||
gasLimit = maxCallGas( |
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.
Note that maxCallGas
is called after we have deducted all the call gas (this was not done before, callNewAccount
could be deducted after maxCallGas
). This was a difference from geth, so this might actually fix some consensus issues if we would do a mainnet sync (although it is very strange that no state test has found this!). The issue is thus that the forwarded gas between geth/EthereumJS might be different.
Blockchain tests, local:
|
What is missing on this on this PR? Can this be updated easily? Would have some time for a review later during the evening. |
@holgerd77 will update! |
17e0b70
to
b303a21
Compare
@holgerd77 I spent more time on this than I want to admit 😅 But it works! Note that in the tests all forks supported forks are added as state test; Homestead is also checked in the blockchain test. The tests are still a bit ugly (but they do work now for older forks). I could make them a bit more prettier but I think that should be done in a new PR. @evertonfraga could you specifically review the CI? 😄 EDIT: also note the state tests pass for all supported forks! 😄 |
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.
Didn't got so deep into opFns.ts
yet, some comments to address.
PR also needs a conflict resolve.
} | ||
return Buffer.from(loaded) | ||
|
||
return returnBuffer |
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 for my understanding, since I've read through both code versions a couple of times now and would assume that both would work: what has been changed/fixed 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.
There is a KECCAK test in the Homestead suite which requires one to hash ~1.5GB of data (randomStateTest94
). The old approach uses too much memory (I assume because of how JS-arrays are implemented; one keeps pushing values into this array, thus expanding it). It runs out of memory on my pc (not sure if it also runs OOM on the CI) which has 16GB of RAM (also tested it with bumping the amount of RAM node can access).
The issue is thus not that this changes any functionality; this however uses less memory as the new approach does not go OOM on my pc.
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.
Ah, nice explanation, thanks!
(and also cool "digging-deep")
async getStateRoot(): Promise<Buffer> { | ||
if (this._checkpointCount !== 0) { | ||
async getStateRoot(force: boolean = false): Promise<Buffer> { | ||
if (!force && this._checkpointCount !== 0) { | ||
throw new Error('Cannot get state root with uncommitted checkpoints') | ||
} | ||
await this._cache.flush() |
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.
Ok, looks good.
packages/vm/lib/state/interface.ts
Outdated
@@ -22,7 +22,7 @@ export interface StateManager { | |||
checkpoint(): Promise<void> | |||
commit(): Promise<void> | |||
revert(): Promise<void> | |||
getStateRoot(): Promise<Buffer> | |||
getStateRoot(force: boolean): Promise<Buffer> |
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.
Correct me if I am wrong, but I think force
should be marked as optional
in the interface, since there is a default value in the implementation.
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 can try this, I tried using a default value in the interface (false
) but TypeScript does not support this. Marking it optional in the interface sounds like a good idea, I think that might work, but I don't know if TypeScript supports these optional values in the interface. Will try.
packages/vm/package.json
Outdated
"test:state:slow": "npm run test:state -- --runSkipped=slow", | ||
"test:buildIntegrity": "npm run test:state -- --test='stackOverflow'", | ||
"test:blockchain": "node -r ts-node/register --stack-size=1500 ./tests/tester --blockchain", | ||
"test:API": "tape -r ts-node/register --stack-size=1500 './tests/api/**/*.js'", | ||
"test:API:browser": "karma start karma.conf.js", | ||
"test:blockchain:allForks": "node -r ts-node/register --stack-size=1500 ./tests/tester --blockchain --fork=Homestead && node -r ts-node/register --stack-size=1500 ./tests/tester --blockchain --fork=TangerineWhistle && node -r ts-node/register --stack-size=1500 ./tests/tester --blockchain --fork=SpuriousDragon && node -r ts-node/register --stack-size=1500 ./tests/tester --blockchain --fork=Byzantium && node -r ts-node/register --stack-size=1500 ./tests/tester --blockchain --fork=Constantinople && node -r ts-node/register --stack-size=1500 ./tests/tester --blockchain --fork=Petersburg && node -r ts-node/register --stack-size=1500 ./tests/tester --blockchain --fork=Istanbul && node -r ts-node/register --stack-size=1500 ./tests/tester --blockchain --fork=MuirGlacier", |
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.
Wonder if this can be simplified with something build upon something like echo {'Istanbul','Byzantium'} | xargs -n1 | xargs -I v1 echo v1
, see this StackExchange question for some inspiration.
packages/vm/package.json
Outdated
@@ -14,13 +14,14 @@ | |||
"coverage:test": "tape './tests/api/**/*.js' ./tests/tester.js --state --dist", | |||
"docs:build": "typedoc --options typedoc.js", | |||
"test:state": "ts-node ./tests/tester --state", | |||
"test:state:allForks": "npm run test:state -- --fork=TangerineWhistle && npm run test:state -- --fork=SpuriousDragon && npm run test:state -- --fork=Byzantium && npm run test:state -- --fork=Constantinople && npm run test:state -- --fork=Petersburg && npm run test:state -- --fork=Istanbul && npm run test:state -- --fork=MuirGlacier", | |||
"test:state:selectedForks": "npm run test:state -- --fork=Petersburg && npm run test:state -- --fork=TangerineWhistle", | |||
"test:state:allForks": "npm run test:state -- --fork=Homestead && npm run test:state -- --fork=TangerineWhistle && npm run test:state -- --fork=SpuriousDragon && npm run test:state -- --fork=Byzantium && npm run test:state -- --fork=Constantinople && npm run test:state -- --fork=Petersburg && npm run test:state -- --fork=Istanbul && npm run test:state -- --fork=MuirGlacier", |
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.
Similar suggestion as for blockchain:allForks
t.comment("skipping test: no data available for " + options.forkConfigTestSuite) | ||
return | ||
} | ||
|
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.
Ok, will see this as resolved for now.
582ce78
to
bc4f199
Compare
[VM] fix blockchain tests
[VM] TangerineWhistle: fix tests [VM] remove obsolete test [VM] remove allforks test from default workflow (it is still in nightly tests)
[VM] Pre-TangerineWhistle: make too much gas forwarded in calls go OOG [VM] lint [VM] update package scripts [VM] fix workflow [VM] include Homestead in PR test runner [VM] fix package-lock
[VM] change docs
bc4f199
to
8546612
Compare
Looks like the rebase introduced an error. |
[Ethash] lint
655767d
to
fccea35
Compare
Okay, this should be fixed now (Ethash had an unhandled rejection in a Promise). Ready for re-review @holgerd77 |
@jochem-brouwer ah, great, will start in 10 min. 😛 |
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 looks good now, also checked the test run results (so: check that both blockchain and state tests are actually executed), thanks Jochem! 😄
Will merge.
"test:state:allForks": "npm run test:state -- --fork=TangerineWhistle && npm run test:state -- --fork=SpuriousDragon && npm run test:state -- --fork=Byzantium && npm run test:state -- --fork=Constantinople && npm run test:state -- --fork=Petersburg && npm run test:state -- --fork=Istanbul && npm run test:state -- --fork=MuirGlacier", | ||
"test:state:selectedForks": "npm run test:state -- --fork=Petersburg && npm run test:state -- --fork=TangerineWhistle", | ||
"test:state:allForks": "echo {'Homestead','TangerineWhistle','SpuriousDragon','Byzantium','Constantinople','Petersburg','Istanbul','MuirGlacier'} | xargs -n1 | xargs -I v1 npm run test:state -- --fork=v1", | ||
"test:state:selectedForks": "echo {'Homestead','TangerineWhistle','SpuriousDragon','Petersburg',} | xargs -n1 | xargs -I v1 npm run test:state -- --fork=v1", |
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.
👍
@@ -713,7 +718,11 @@ export const handlers: { [k: string]: OpHandler } = { | |||
if (!value.isZero()) { | |||
runState.eei.useGas(new BN(runState._common.param('gasPrices', 'callValueTransfer'))) | |||
} | |||
gasLimit = maxCallGas(gasLimit, runState.eei.getGasLeft()) | |||
gasLimit = maxCallGas(gasLimit, runState.eei.getGasLeft(), runState) | |||
// note that TW or later this cannot happen (it could have ran out of gas prior to getting here though) |
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.
Won't make this a blocker either, but such abbreviations like TW
are suboptimal since hard to read (I didn't make it at all to "Tangerine Whistle" on first round), better to fully write stuff like this down.
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.
Good point, will keep it in mind 👍
Closes #813. Closes #824.
Note: I have put more forks in the PR CI file.