{"action":"closed","number":1573,"pull_request":{"url":"https://api.github.com/repos/trufflesuite/truffle/pulls/1573","id":240323303,"node_id":"MDExOlB1bGxSZXF1ZXN0MjQwMzIzMzAz","html_url":"https://github.com/trufflesuite/truffle/pull/1573","diff_url":"https://github.com/trufflesuite/truffle/pull/1573.diff","patch_url":"https://github.com/trufflesuite/truffle/pull/1573.patch","issue_url":"https://api.github.com/repos/trufflesuite/truffle/issues/1573","number":1573,"state":"closed","locked":false,"title":"Move the debugger to preallocation of structs, along with other small allocation and decoding fixes","user":{"login":"haltman-at","id":35589221,"node_id":"MDQ6VXNlcjM1NTg5MjIx","avatar_url":"https://avatars3.githubusercontent.com/u/35589221?v=4","gravatar_id":"","url":"https://api.github.com/users/haltman-at","html_url":"https://github.com/haltman-at","followers_url":"https://api.github.com/users/haltman-at/followers","following_url":"https://api.github.com/users/haltman-at/following{/other_user}","gists_url":"https://api.github.com/users/haltman-at/gists{/gist_id}","starred_url":"https://api.github.com/users/haltman-at/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/haltman-at/subscriptions","organizations_url":"https://api.github.com/users/haltman-at/orgs","repos_url":"https://api.github.com/users/haltman-at/repos","events_url":"https://api.github.com/users/haltman-at/events{/privacy}","received_events_url":"https://api.github.com/users/haltman-at/received_events","type":"User","site_admin":false},"body":"The primary purpose of this pull request is to move the debugger to using preallocation of structs, like Ganache does, so that the same decoding code can be used for both; this pull request deletes the debugger-specific code for decoding of structs, as the debugger will now use the code that was previously used only for Ganache.  Also, in addition to preallocating structs, contracts are now also preallocated as well.  All of this is, of course, a purely non-functional change (except perhaps when it comes to performance; I don't know that this will really make much difference but it should ideally frontload any costs there and make them one-time); but I also included several functional changes along with it that I deemed easy to incorporate.\r\n\r\n(@seesemichaelj also made some changes on this branch, most of which I'm not entirely familiar with; I'll let him comment with his changes below.)\r\n\r\nFirstly, the debugger now supports decoding for contracts with inheritance -- inherited state variables will be passed to the allocator along with those from the contract itself.\r\n\r\nSecondly, the debugger now properly handles allocation for contracts with constant variables; constant variables are now skipped during allocation, as they should be (this is done by filtering them out before passing them to the allocator; this isn't handled by the allocator itself).  Note that there is presently no support in the debugger for *decoding* of constant variables; I'm intending to add this at a later time.  (Although, this isn't high-priority -- there isn't much need to decode constants, because they don't change.)\r\n\r\nThirdly, enums can now be decoded in any location rather than just in storage.   (Thanks to @seesemichaelj for catching a bug here.)  Currently they decode to an internal object that the user shouldn't really see, but, hey, that's what they did already in storage.  I'm intending to fix this in a later PR.\r\n\r\nFourthly, I did some tinkering with the struct decoding logic, because I noticed what appeared to be some errors in it.  And hey, @seesemichaelj says it's working better now, so that's good. :)\r\n\r\nAlso, in another nonfunctional change, I deleted the now-defunct file `mapping.ts`.\r\n\r\nFinally it is worth noting that I did not add any new automated tests in this PR.  Probably there should be some, but they would be decoding tests, and I think it would make more sense to redo the decoding tests in a later PR.\r\n\r\nI have a number of additional notes on the changes above, mostly regarding the preallocation change:\r\n\r\n1. Let's first note what this PR does *not* do -- it does not rewrite the debugger's allocator.  The point of this PR was that it was something I could do *without* substantially altering the allocator (there was one small alteration, see next point).  This means that the debugger still cannot handle static arrays.  I'm intending to rewrite the allocator, and fix static arrays, in my next PR, along with some other improvements.\r\n2. In order to avoid recomputation, we need to somehow memoize the allocations for structs we've already allocated.  Again, I didn't want to alter the allocator much, and I also didn't want to go adding a bunch to the state here; so instead what I did is this.  I added an extra argument to the allocator which allows it to take an object containing allocations already made.  If it goes to allocate a struct, first it looks it up in there to see if it's already been allocated; if so, it just uses the allocation it just looked up rather than recomputing it.  Now, this could still lead to recomputation; but to prevent this, in addition, I topologically sorted the structs and contracts to be allocated, and allocated them in that order.  (I think this is different than the approach Ganache uses, which is to simply memoize *everything* as it allocates it, and not to worry about order; @seesemichaelj can correct me if I'm wrong there.)  This actually means that the recursive case in the allocator will now never be called.  However, I've left it in for now as something of a failsafe.  However, in my next PR, when I rewrite the allocator, I won't bother to include such a failsafe.\r\n3. Regarding that topological sort -- I used a fairly naïve, unoptimized topological sort.  I don't think this should be a performance problem, but if it becomes one, well, we can address it then.  (Getting any performance improvement from using a better one would have required making more of an explicit graph structure rather than just using lists, which I judged not worth the trouble.)\r\n4. I added to the state `data.info.userDefinedTypes` (along with corresponding selector).  This lists all the user-defined types, such as structs, contracts, and enums.  The thing is, I just stored the ID of the type, not the definition or the entry from `data.info.scopes`.  Because the thing we care about here is mostly the `variables` member from `data.info.scopes`; but I'm not sure `data.info.scopes` is ready yet when `data.info.userDefinedTypes` is set up (although that entry might be?), so I chose to store just the ID, and fetch related information later from it.\r\n6. Speaking of which, `data.info.scopes` has now been changed to account for inheritance and constants; the old one is now at `data.info.scopes.raw`.  Similarly with `data.views.scopes.inlined`.  Now, this means that `data.info.scopes` now contains substantial computation, meaning it probably really belongs in `data.views` now, not `data.info`; however since I intended the new one as something of a drop-in replacement to this commonly-used selector, I didn't want to do that.  I'm intending to reorganize this though to how it should be in a later PR (probably when I handle decoding constants or globally available variables).\r\n7. Finally, one note that is not about allocation but rather about decoding -- as mentioned, I made some changes to struct decoding.  Let's say we have a struct; we want to decode it, which means decoding each of its members, which means determining pointers for each of its members.  Each slot in each of these child pointers has a path and an offset.  Now, the path is obviously the slot of the parent's `from`; but what about the offset?  Here's why this is an issue -- the offset should be the offset of that member, as determined by the allocator; except, that the member might itself have a nontrivial `path`.  The `offset` field is supposed to be a number, so we can't just stick this all this information in `offset`; we have to collapse it to a single overall offset with `slotAddress`, which I do.  This loses information, despite @gnidan's intent to not lose information that led to the `path` system in the first place.  Despite that, I think this is OK -- because, well, it's a struct offset, not a path to the base.  I think keeping that information isn't really very necessary for something that's ultimately just going to used as an offset; certainly there's no hashing going on here that would confuse things!  So, I went ahead and collapsed it with `slotAddress`, as needed.","created_at":"2018-12-20T22:44:21Z","updated_at":"2019-01-03T01:21:13Z","closed_at":"2019-01-03T01:21:13Z","merged_at":"2019-01-03T01:21:13Z","merge_commit_sha":"38db96cbc693a7d31c698b468e4108d3b46317c2","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/trufflesuite/truffle/pulls/1573/commits","review_comments_url":"https://api.github.com/repos/trufflesuite/truffle/pulls/1573/comments","review_comment_url":"https://api.github.com/repos/trufflesuite/truffle/pulls/comments{/number}","comments_url":"https://api.github.com/repos/trufflesuite/truffle/issues/1573/comments","statuses_url":"https://api.github.com/repos/trufflesuite/truffle/statuses/02f12447571aec84b4b24cd63ddc5c2fa7167fb4","head":{"label":"trufflesuite:preallocation","ref":"preallocation","sha":"02f12447571aec84b4b24cd63ddc5c2fa7167fb4","user":{"login":"trufflesuite","id":22205159,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIyMjA1MTU5","avatar_url":"https://avatars1.githubusercontent.com/u/22205159?v=4","gravatar_id":"","url":"https://api.github.com/users/trufflesuite","html_url":"https://github.com/trufflesuite","followers_url":"https://api.github.com/users/trufflesuite/followers","following_url":"https://api.github.com/users/trufflesuite/following{/other_user}","gists_url":"https://api.github.com/users/trufflesuite/gists{/gist_id}","starred_url":"https://api.github.com/users/trufflesuite/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/trufflesuite/subscriptions","organizations_url":"https://api.github.com/users/trufflesuite/orgs","repos_url":"https://api.github.com/users/trufflesuite/repos","events_url":"https://api.github.com/users/trufflesuite/events{/privacy}","received_events_url":"https://api.github.com/users/trufflesuite/received_events","type":"Organization","site_admin":false},"repo":{"id":38267641,"node_id":"MDEwOlJlcG9zaXRvcnkzODI2NzY0MQ==","name":"truffle","full_name":"trufflesuite/truffle","private":false,"owner":{"login":"trufflesuite","id":22205159,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIyMjA1MTU5","avatar_url":"https://avatars1.githubusercontent.com/u/22205159?v=4","gravatar_id":"","url":"https://api.github.com/users/trufflesuite","html_url":"https://github.com/trufflesuite","followers_url":"https://api.github.com/users/trufflesuite/followers","following_url":"https://api.github.com/users/trufflesuite/following{/other_user}","gists_url":"https://api.github.com/users/trufflesuite/gists{/gist_id}","starred_url":"https://api.github.com/users/trufflesuite/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/trufflesuite/subscriptions","organizations_url":"https://api.github.com/users/trufflesuite/orgs","repos_url":"https://api.github.com/users/trufflesuite/repos","events_url":"https://api.github.com/users/trufflesuite/events{/privacy}","received_events_url":"https://api.github.com/users/trufflesuite/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/trufflesuite/truffle","description":"The most popular blockchain development framework","fork":false,"url":"https://api.github.com/repos/trufflesuite/truffle","forks_url":"https://api.github.com/repos/trufflesuite/truffle/forks","keys_url":"https://api.github.com/repos/trufflesuite/truffle/keys{/key_id}","collaborators_url":"https://api.github.com/repos/trufflesuite/truffle/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/trufflesuite/truffle/teams","hooks_url":"https://api.github.com/repos/trufflesuite/truffle/hooks","issue_events_url":"https://api.github.com/repos/trufflesuite/truffle/issues/events{/number}","events_url":"https://api.github.com/repos/trufflesuite/truffle/events","assignees_url":"https://api.github.com/repos/trufflesuite/truffle/assignees{/user}","branches_url":"https://api.github.com/repos/trufflesuite/truffle/branches{/branch}","tags_url":"https://api.github.com/repos/trufflesuite/truffle/tags","blobs_url":"https://api.github.com/repos/trufflesuite/truffle/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/trufflesuite/truffle/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/trufflesuite/truffle/git/refs{/sha}","trees_url":"https://api.github.com/repos/trufflesuite/truffle/git/trees{/sha}","statuses_url":"https://api.github.com/repos/trufflesuite/truffle/statuses/{sha}","languages_url":"https://api.github.com/repos/trufflesuite/truffle/languages","stargazers_url":"https://api.github.com/repos/trufflesuite/truffle/stargazers","contributors_url":"https://api.github.com/repos/trufflesuite/truffle/contributors","subscribers_url":"https://api.github.com/repos/trufflesuite/truffle/subscribers","subscription_url":"https://api.github.com/repos/trufflesuite/truffle/subscription","commits_url":"https://api.github.com/repos/trufflesuite/truffle/commits{/sha}","git_commits_url":"https://api.github.com/repos/trufflesuite/truffle/git/commits{/sha}","comments_url":"https://api.github.com/repos/trufflesuite/truffle/comments{/number}","issue_comment_url":"https://api.github.com/repos/trufflesuite/truffle/issues/comments{/number}","contents_url":"https://api.github.com/repos/trufflesuite/truffle/contents/{+path}","compare_url":"https://api.github.com/repos/trufflesuite/truffle/compare/{base}...{head}","merges_url":"https://api.github.com/repos/trufflesuite/truffle/merges","archive_url":"https://api.github.com/repos/trufflesuite/truffle/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/trufflesuite/truffle/downloads","issues_url":"https://api.github.com/repos/trufflesuite/truffle/issues{/number}","pulls_url":"https://api.github.com/repos/trufflesuite/truffle/pulls{/number}","milestones_url":"https://api.github.com/repos/trufflesuite/truffle/milestones{/number}","notifications_url":"https://api.github.com/repos/trufflesuite/truffle/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/trufflesuite/truffle/labels{/name}","releases_url":"https://api.github.com/repos/trufflesuite/truffle/releases{/id}","deployments_url":"https://api.github.com/repos/trufflesuite/truffle/deployments","created_at":"2015-06-29T19:46:53Z","updated_at":"2019-01-02T18:56:34Z","pushed_at":"2019-01-03T01:21:13Z","git_url":"git://github.com/trufflesuite/truffle.git","ssh_url":"git@github.com:trufflesuite/truffle.git","clone_url":"https://github.com/trufflesuite/truffle.git","svn_url":"https://github.com/trufflesuite/truffle","homepage":"http://truffleframework.com","size":58925,"stargazers_count":7448,"watchers_count":7448,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1029,"mirror_url":null,"archived":false,"open_issues_count":164,"license":null,"forks":1029,"open_issues":164,"watchers":7448,"default_branch":"develop"}},"base":{"label":"trufflesuite:develop","ref":"develop","sha":"935e91b3fbe96b843e9a1d80b796f860d09c139b","user":{"login":"trufflesuite","id":22205159,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIyMjA1MTU5","avatar_url":"https://avatars1.githubusercontent.com/u/22205159?v=4","gravatar_id":"","url":"https://api.github.com/users/trufflesuite","html_url":"https://github.com/trufflesuite","followers_url":"https://api.github.com/users/trufflesuite/followers","following_url":"https://api.github.com/users/trufflesuite/following{/other_user}","gists_url":"https://api.github.com/users/trufflesuite/gists{/gist_id}","starred_url":"https://api.github.com/users/trufflesuite/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/trufflesuite/subscriptions","organizations_url":"https://api.github.com/users/trufflesuite/orgs","repos_url":"https://api.github.com/users/trufflesuite/repos","events_url":"https://api.github.com/users/trufflesuite/events{/privacy}","received_events_url":"https://api.github.com/users/trufflesuite/received_events","type":"Organization","site_admin":false},"repo":{"id":38267641,"node_id":"MDEwOlJlcG9zaXRvcnkzODI2NzY0MQ==","name":"truffle","full_name":"trufflesuite/truffle","private":false,"owner":{"login":"trufflesuite","id":22205159,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIyMjA1MTU5","avatar_url":"https://avatars1.githubusercontent.com/u/22205159?v=4","gravatar_id":"","url":"https://api.github.com/users/trufflesuite","html_url":"https://github.com/trufflesuite","followers_url":"https://api.github.com/users/trufflesuite/followers","following_url":"https://api.github.com/users/trufflesuite/following{/other_user}","gists_url":"https://api.github.com/users/trufflesuite/gists{/gist_id}","starred_url":"https://api.github.com/users/trufflesuite/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/trufflesuite/subscriptions","organizations_url":"https://api.github.com/users/trufflesuite/orgs","repos_url":"https://api.github.com/users/trufflesuite/repos","events_url":"https://api.github.com/users/trufflesuite/events{/privacy}","received_events_url":"https://api.github.com/users/trufflesuite/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/trufflesuite/truffle","description":"The most popular blockchain development framework","fork":false,"url":"https://api.github.com/repos/trufflesuite/truffle","forks_url":"https://api.github.com/repos/trufflesuite/truffle/forks","keys_url":"https://api.github.com/repos/trufflesuite/truffle/keys{/key_id}","collaborators_url":"https://api.github.com/repos/trufflesuite/truffle/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/trufflesuite/truffle/teams","hooks_url":"https://api.github.com/repos/trufflesuite/truffle/hooks","issue_events_url":"https://api.github.com/repos/trufflesuite/truffle/issues/events{/number}","events_url":"https://api.github.com/repos/trufflesuite/truffle/events","assignees_url":"https://api.github.com/repos/trufflesuite/truffle/assignees{/user}","branches_url":"https://api.github.com/repos/trufflesuite/truffle/branches{/branch}","tags_url":"https://api.github.com/repos/trufflesuite/truffle/tags","blobs_url":"https://api.github.com/repos/trufflesuite/truffle/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/trufflesuite/truffle/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/trufflesuite/truffle/git/refs{/sha}","trees_url":"https://api.github.com/repos/trufflesuite/truffle/git/trees{/sha}","statuses_url":"https://api.github.com/repos/trufflesuite/truffle/statuses/{sha}","languages_url":"https://api.github.com/repos/trufflesuite/truffle/languages","stargazers_url":"https://api.github.com/repos/trufflesuite/truffle/stargazers","contributors_url":"https://api.github.com/repos/trufflesuite/truffle/contributors","subscribers_url":"https://api.github.com/repos/trufflesuite/truffle/subscribers","subscription_url":"https://api.github.com/repos/trufflesuite/truffle/subscription","commits_url":"https://api.github.com/repos/trufflesuite/truffle/commits{/sha}","git_commits_url":"https://api.github.com/repos/trufflesuite/truffle/git/commits{/sha}","comments_url":"https://api.github.com/repos/trufflesuite/truffle/comments{/number}","issue_comment_url":"https://api.github.com/repos/trufflesuite/truffle/issues/comments{/number}","contents_url":"https://api.github.com/repos/trufflesuite/truffle/contents/{+path}","compare_url":"https://api.github.com/repos/trufflesuite/truffle/compare/{base}...{head}","merges_url":"https://api.github.com/repos/trufflesuite/truffle/merges","archive_url":"https://api.github.com/repos/trufflesuite/truffle/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/trufflesuite/truffle/downloads","issues_url":"https://api.github.com/repos/trufflesuite/truffle/issues{/number}","pulls_url":"https://api.github.com/repos/trufflesuite/truffle/pulls{/number}","milestones_url":"https://api.github.com/repos/trufflesuite/truffle/milestones{/number}","notifications_url":"https://api.github.com/repos/trufflesuite/truffle/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/trufflesuite/truffle/labels{/name}","releases_url":"https://api.github.com/repos/trufflesuite/truffle/releases{/id}","deployments_url":"https://api.github.com/repos/trufflesuite/truffle/deployments","created_at":"2015-06-29T19:46:53Z","updated_at":"2019-01-02T18:56:34Z","pushed_at":"2019-01-03T01:21:13Z","git_url":"git://github.com/trufflesuite/truffle.git","ssh_url":"git@github.com:trufflesuite/truffle.git","clone_url":"https://github.com/trufflesuite/truffle.git","svn_url":"https://github.com/trufflesuite/truffle","homepage":"http://truffleframework.com","size":58925,"stargazers_count":7448,"watchers_count":7448,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1029,"mirror_url":null,"archived":false,"open_issues_count":164,"license":null,"forks":1029,"open_issues":164,"watchers":7448,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/trufflesuite/truffle/pulls/1573"},"html":{"href":"https://github.com/trufflesuite/truffle/pull/1573"},"issue":{"href":"https://api.github.com/repos/trufflesuite/truffle/issues/1573"},"comments":{"href":"https://api.github.com/repos/trufflesuite/truffle/issues/1573/comments"},"review_comments":{"href":"https://api.github.com/repos/trufflesuite/truffle/pulls/1573/comments"},"review_comment":{"href":"https://api.github.com/repos/trufflesuite/truffle/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/trufflesuite/truffle/pulls/1573/commits"},"statuses":{"href":"https://api.github.com/repos/trufflesuite/truffle/statuses/02f12447571aec84b4b24cd63ddc5c2fa7167fb4"}},"author_association":"CONTRIBUTOR","merged":true,"mergeable":null,"rebaseable":null,"mergeable_state":"unknown","merged_by":{"login":"gnidan","id":151065,"node_id":"MDQ6VXNlcjE1MTA2NQ==","avatar_url":"https://avatars1.githubusercontent.com/u/151065?v=4","gravatar_id":"","url":"https://api.github.com/users/gnidan","html_url":"https://github.com/gnidan","followers_url":"https://api.github.com/users/gnidan/followers","following_url":"https://api.github.com/users/gnidan/following{/other_user}","gists_url":"https://api.github.com/users/gnidan/gists{/gist_id}","starred_url":"https://api.github.com/users/gnidan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gnidan/subscriptions","organizations_url":"https://api.github.com/users/gnidan/orgs","repos_url":"https://api.github.com/users/gnidan/repos","events_url":"https://api.github.com/users/gnidan/events{/privacy}","received_events_url":"https://api.github.com/users/gnidan/received_events","type":"User","site_admin":false},"comments":6,"review_comments":10,"maintainer_can_modify":false,"commits":23,"additions":532,"deletions":318,"changed_files":17}}
{"actor":{"display_login":"gnidan"}}