-
Notifications
You must be signed in to change notification settings - Fork 757
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
TangerineWhistle HF Support #807
Conversation
…est:state:selectedForks CI script
… account creation and CREATE nonce increment (EIP-161)
a2a2354 brings test failures down to 1..1096
# tests 1096
# pass 991
# fail 105 Addresses the following part from the specification:
|
Codecov Report
@@ Coverage Diff @@
## master #807 +/- ##
==========================================
+ Coverage 84.43% 84.59% +0.16%
==========================================
Files 19 18 -1
Lines 1240 1253 +13
Branches 247 247
==========================================
+ Hits 1047 1060 +13
Misses 125 125
Partials 68 68
Continue to review full report at Codecov.
|
These TangerineWhistle tests - do they also test against ChainStart/Homestead (cannot seem to find this in the tests)? Because we do not have implemented some ChainStart things, so that could also be a reason why tests fail. Changes seem to be mostly gas changes, most of them which are implemented. |
No, they only tests against Makes sense? 😄 |
…n or later (EIP-161)
2f9ed3c is bringing test failures down to 99: 1..1096
# tests 1096
# pass 997
# fail 99 Following part of the specification:
|
I am struggling a lot with:
respectively the definition of a dead account as being non-existent or empty (no code, zero nonce, zero balance) and the way the related StateManager API is set up. This is not very consistent and in parts badly named or at least commented, following potential problems or potentially problematic design decisions:
First question: is this analysis correct? My impression is - based on this - that if we overlay this chaos with pre-SpuriousDragon functionality, understanding of the code respectively these empty states get even worse. Suggestion here would be that we do a separate PR on this and:
Does this make sense? Other suggestions on this? //cc @s1na @jochem-brouwer ,all others |
Hm yeah you're right that the API is not ideal for distinguishing between those states. My first impression is that changing
|
…costs, new accountExists StateManager function
@s1na ok, have added a new |
This pull request introduces 1 alert when merging 6bb93d8 into 195be3b - view on LGTM.com new alerts:
|
Hi @jochem-brouwer, do you think you might find some time to work a bit as well during the next 2 weeks or so? I likely won't find so many free hours to continue here. Task is mainly to have a look a the old |
@holgerd77 Sure, I will pick this up! 😄 |
This pull request introduces 2 alerts when merging f09a36b into 195be3b - view on LGTM.com new alerts:
|
Some notes: had to dig up an older version of the Ethereum Yellow Paper to actually make sense of this problem. In I'll have to think about it a bit more but I think we should create functions which have these names and thus follow the specification from the Yellow Paper. To cleanup these empty accounts from the Trie, Sweeper.sol was deployed on mainnet, but this ironically lead to a consensus bug between geth/parity. Failing tests
|
|
This pull request introduces 2 alerts when merging e2f5371 into 195be3b - view on LGTM.com new alerts:
|
Final test for TangerineWhistle now passes. This was very confusing - it was a test which had to do with However, now's the task to fix the Spurious Dragon tests:
|
This pull request introduces 2 alerts when merging 46d9cd6 into 4539018 - view on LGTM.com new alerts:
|
Can't request a review for some reason from you @holgerd77, but tests pass and this seems ready (tests pass locally) |
This pull request introduces 2 alerts when merging a0bd87b into 4539018 - view on LGTM.com new alerts:
|
This pull request introduces 2 alerts when merging d43da03 into 4539018 - view on LGTM.com new alerts:
|
@@ -111,7 +115,7 @@ export default class DefaultStateManager implements StateManager { | |||
const codeHash = keccak256(value) | |||
|
|||
if (codeHash.equals(KECCAK256_NULL)) { | |||
return | |||
//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.
a note that this is commented out
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.
@jochem-brouwer can you clarify why this should be commented out?
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 should not be commented out, this is a remainder from toying around in order to resolve those failing tests. It will not change anything though; the only call is from evm.ts
which does not call putContractCode
if the code to put is the empty string.
@@ -54,24 +54,30 @@ export default class Cache { | |||
/** | |||
* Looks up address in underlying trie. | |||
* @param address - Address of account | |||
* @param create - Create emtpy account if non-existent |
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.
* @param create - Create emtpy account if non-existent | |
* @param create - Create empty account if non-existent |
@@ -71,7 +71,7 @@ export default class DefaultStateManager implements StateManager { | |||
* @param address - Address of the `account` to get | |||
*/ | |||
async getAccount(address: Buffer): Promise<Account> { | |||
const account = await this._cache.getOrLoad(address) | |||
const account = (await this._cache.getOrLoad(address)) as Account |
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 cast with as Account
because getOrLoad
was updated to return with optional undefined (Promise<Account | undefined>
), so it may be better to update the return signature of the function here instead of casting.
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, thanks Jochem, really great! 😄 Will do an exception and admin-merge here, since socio-technically 😋 this is the PR from Jochem (I opened initially).
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.
Congrats on getting this through the finish line! I started reviewing yesterday but had to leave in the middle. I see it's merged now but I completed the review for future PRs. Just a few minor code quality comments.
if (runState._common.gteHardfork('spuriousDragon')) { | ||
// We are at or after Spurious Dragon | ||
// Call new account gas: account is DEAD and we transfer nonzero value | ||
if ((await runState.stateManager.accountIsEmpty(toAddressBuf)) && !value.isZero()) { |
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 add these methods to EEI
and use those here instead? We want to make sure the EVM has access only to what's exposed from the EEI
and nothing else.
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 am not sure what you mean here. You mean the calls to the stateManager
? I.e. put accountIsEmpty
and accountExists
in EEI
?
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.
Yeah exactly. isAccountEmtpy
is already in the EEI
and can be used. accountExists
needs to be added.
To clarify the reasoning, we want to isolate the execution of EVM code as much as possible. EEI
is supposed to be the only external interface evm code has access to.
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.
Cool, makes sense!
} else if (!(await runState.stateManager.accountExists(toAddressBuf))) { | ||
// We are before Spurious Dragon | ||
// Call new account gas: account does not exist (it is not in the state trie, not even as an "empty" account) | ||
const accountDoesNotExist = !(await runState.stateManager.accountExists(toAddressBuf)) |
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.
No need to call accountExists
twice
@@ -111,7 +115,7 @@ export default class DefaultStateManager implements StateManager { | |||
const codeHash = keccak256(value) | |||
|
|||
if (codeHash.equals(KECCAK256_NULL)) { | |||
return | |||
//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.
@jochem-brouwer can you clarify why this should be commented out?
@@ -10,7 +10,8 @@ export interface StorageDump { | |||
export interface StateManager { | |||
copy(): StateManager | |||
getAccount(address: Buffer): Promise<Account> | |||
putAccount(address: Buffer, account: Account): Promise<void> | |||
putAccount(address: Buffer, account: Account | null): Promise<void> |
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 don't see the interface of DefaultStateManager.putAccount
changing. Is this change still valid or maybe deleteAccount
suffices 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.
Yup I should revert the changes to the interface, thanks!
*/ | ||
async getOrLoad(key: Buffer): Promise<Account> { | ||
async getOrLoad(key: Buffer, create: boolean = true): Promise<Account | undefined> { |
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 don't see any invocation of getOrLoad
with create=false
. Are these changes deprecated? in that case can you revert them? (also _lookupAccount
)
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.
Yup you are right, I will remove this.
Initial push on
TangerineWhistle
support, I would assume that only the changes from EIP-161 need to be separated for this to work.Initial test run:
Feel free to pick things up and continue on this.