Skip to content
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

Clean-up state-manager.touched #287

Conversation

mattdean-digicatapult
Copy link
Contributor

Fixes #267

I'm looking to contribute on this project a bit, especially with the aim of cleaning up the StateManager interface, and thought I'd start here.

I've taken a different approach to that in the issue description so feel free to criticise if there was a particular reason for suggesting turning the StateManager into an EventEmitter. I just felt that would be externalising state that should instead be encapsulated in StateManager itself.

Instead the approach I've taken is to move all mutations of StateManager.touched into StateManager such that touched can be considered private. This involved adding a new method to the StateManager interface in order to tidy up touched accounts. I would have preferred to include this as part of a commit phase but couldn't find somewhere sensible to do so without changing a lot of code.

I've also had to include one usage of the private method StateManager._putAccount which I feel should probably be public in the long run anyway.

Finally some methods have been made asynchronous in order to allow using StateManager methods instead of directly manipulating StateManager.cache. This makes the diff look a little worse than it really is.

lib/runCall.js Outdated
var newBalance = new BN(toAccount.balance).add(txValue)
toAccount.balance = newBalance
// _putAccount as the nonce may have changed for contract creation
stateManager._putAccount(ethUtil.toBuffer(toAddress), toAccount, cb)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The functions with an underscore would be internal functions of the StateManager and should not be called from outside. (It may be the case at the moment in some places but that should be fixed.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. The only way of achieving this write in the current codebase is to either manipulate the cache directly (which I feel should also be a no-no) or to call _putAccount. My preference would be to make _putAccount public (rename to putAccount) but I didn't want to change the interface in this way without checking first. Would you be ok with this?

@coveralls
Copy link

coveralls commented Mar 14, 2018

Coverage Status

Coverage increased (+0.07%) to 85.505% when pulling 5327e6f on mattdean-digicatapult:clean-up-statemanager-touched into 01b7f37 on ethereumjs:master.

@jwasinger jwasinger requested review from holgerd77 and jwasinger April 9, 2018 03:02
@jwasinger
Copy link
Contributor

jwasinger commented Apr 9, 2018

@mattdean-digicatapult thank you for the PR and I am sorry that this has languished without a response (we are very busy!). I like the changes here and think they improve code readability.

I don't fully understand the solution described in #267 :

This should be done in a much cleaner manner, perhaps with an event emitted from StateManager for touching an account and subscribing to that event in runTx.

Otherwise, I feel like this PR addresses the issue well. Would like to here @axic and @holgerd77 's opinions before we merge this.

P.s. @mattdean-digicatapult please rebase this branch.

jwasinger
jwasinger previously approved these changes Apr 9, 2018
@mattdean-digicatapult
Copy link
Contributor Author

Thanks. Rebased as requested

@jwasinger
Copy link
Contributor

jwasinger commented Apr 11, 2018

@mattdean-digicatapult Thanks. Looks like we are having some issues with the CircleCI job (I think it might have to do with your branch being located on your personal fork of ethereumjs-vm). We have another PR that updates the Circle config to the latest format. I would like to see if that helps with the issue at all.

If you could also please squash the two commits in this PR into one.

Thanks

@jwasinger
Copy link
Contributor

Please rebase this again.

@mattdean-digicatapult mattdean-digicatapult force-pushed the clean-up-statemanager-touched branch from 66af9d3 to 5327e6f Compare April 16, 2018 08:08
@mattdean-digicatapult
Copy link
Contributor Author

Rebased, squashed and circle is now happy 😃

@jwasinger jwasinger self-requested a review April 16, 2018 17:17
@jwasinger jwasinger merged commit 1cbba0a into ethereumjs:master Apr 16, 2018
@axic
Copy link
Member

axic commented Apr 18, 2018

@holgerd77 do you also want to have a look at this? Probably it didn't break anything, just to be sure before a release.

@holgerd77 holgerd77 mentioned this pull request Apr 25, 2018
Copy link
Member

@holgerd77 holgerd77 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally really beautiful and clean PR, just have two or three questions for my own understanding.

@@ -248,7 +248,6 @@ module.exports = function (opts, cb) {
if (results.exceptionError) {
delete results.gasRefund
delete results.selfdestruct
self.stateManager.touched = []
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Matthew, I am just doing a second review on this before we put this out on npm as a release. Just for my understanding: why is this here not needed anymore?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only way exceptionError can be truthy is if err is truthy. In this case stateManager.revertContracts() will have been called on ln 233. That method clears _touched

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, thanks.

@@ -69,7 +69,6 @@ module.exports = function (opts, cb) {

if (tx.to.toString('hex') !== '') {
accounts.add(tx.to.toString('hex'))
self.stateManager.touched.push(tx.to)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm trying to remember; I think this one is just logically superfluous. Any operation that modifies the empty-ness of the to address will necessarily add that address to the touched set. Therefore there's no need to do it here as part of cache population.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, just seeing that the toAccount (also the newly created one from loadToAccount) is added in runCall.addTxValue() through stateManager.putAccount(). So this should be fine.

var newBalance = new BN(toAccount.balance).add(txValue)
toAccount.balance = newBalance
// putAccount as the nonce may have changed for contract creation
stateManager.putAccount(ethUtil.toBuffer(toAddress), toAccount, cb)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Up to here, I think changes are functionally equivalent to the old version.

.add(new BN(fromAccount.balance))
fromAccount.balance = finalFromBalance

self.stateManager.putAccountBalance(utils.toBuffer(tx.from), finalFromBalance, next)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.


// save the miner's account
if (!(new BN(minerAccount.balance).isZero())) {
self.stateManager.cache.put(block.header.coinbase, minerAccount)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason that this stays on acting on the cache directly and not switch to putAccount or putAccountBalance?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not that I can think of. I was just refactoring and didn't change it. We should probably have a separate ticket to clean up all these direct cache writes

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, probably, have added a note to #268.

self._touched.clear()
cb()
})
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, this looks good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Clean up StateManager.touched
6 participants