-
Notifications
You must be signed in to change notification settings - Fork 683
feat: add support for debug_storageRangeAt
RPC
#755
Conversation
Need to clean up the code (copy pasta from |
Hahaha... what my last comment said but hopefully for real this time |
Not the prettiest way of implementing this rpc method but it gets the job done 🤷 Basically we are storing the raw, un-hashed version of storage keys along with their hashed keys so we can return both hashed and raw keys to the user for the Findings: geth stores their hashed keys along with the raw, un-hashed keys. geth also sorts their keys after getting them out of the database (see here: https://gist.github.com/eshaben/ae99036dc15a3784ed3ea50856cd733d -- this is the ordering of keys returned from the trie read stream) 🤷 This is ready for initial review! If anyone wants to test against geth, I used the following command to start up a geth console: Then I went to remix and deployed my contracts and sent transactions. After sending transactions I went back to geth console and tried to use
If you have any questions or want help configuring test environment for this, let me know! |
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.
Looking good and loving the new tests! Made some comments and suggestions. I'll do another review once you've done the clean up you mentioned.
* @param maxResult | ||
* @returns returns a storage object with the keys being keccak-256 hashes of the storage keys, | ||
* and the values being the raw, unhashed key and value for that specific storage slot. Also | ||
* retuns a next key which is the keccak-256 hash of the next key in storage for continuous downloading. |
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.
* retuns a next key which is the keccak-256 hash of the next key in storage for continuous downloading. | |
* returns a next key which is the keccak-256 hash of the next key in storage for continuous downloading. |
@@ -365,6 +370,11 @@ export default class Blockchain extends Emittery.Typed< | |||
); | |||
}); | |||
|
|||
// save storage keys to the database one at a time |
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.
// save storage keys to the database one at a time | |
// save storage keys to the database |
Because this loop happens within the batch
callback, teeeecchhhhnically they'll all get saved at the same time :-)
* Strategy: | ||
* | ||
* 1. Get transaction hash | ||
* 2. Replay transaction | ||
* 3. Create read stream to get the storage keys from the transaction | ||
* 4. Sort storage keys | ||
* 5. Filter, assemble, and send storage data for the given range back |
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.
❤️
try { | ||
await this.traceTransaction(transactionHash, { | ||
disableMemory: true, | ||
disableStack: false, | ||
disableStorage: false | ||
}); | ||
} catch (e) { | ||
throw new Error(e); | ||
} |
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.
traceTransaction
shouldn't (:sweat_smile:) have any side effects, so this bit can probably be removed.
* @param blockHash | ||
* @param txIndex | ||
* @param contractAddress | ||
* @param startKey | ||
* @param maxResult |
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 descriptions for each of these parameters?
const txReceipt1 = await provider.send("eth_getTransactionReceipt", [ | ||
tx1 | ||
]); | ||
const txReceipt2 = await provider.send("eth_getTransactionReceipt", [ | ||
tx2 | ||
]); | ||
const txReceipt3 = await provider.send("eth_getTransactionReceipt", [ | ||
tx3 | ||
]); |
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 slightly neater way:
const txReceipt1 = await provider.send("eth_getTransactionReceipt", [ | |
tx1 | |
]); | |
const txReceipt2 = await provider.send("eth_getTransactionReceipt", [ | |
tx2 | |
]); | |
const txReceipt3 = await provider.send("eth_getTransactionReceipt", [ | |
tx3 | |
]); | |
const [txReceipt1, txReceipt2, txReceipt3] = await Promise.all([ | |
provider.send("eth_getTransactionReceipt", [tx1]), | |
provider.send("eth_getTransactionReceipt", [tx2]), | |
provider.send("eth_getTransactionReceipt", [tx3]) | |
]); |
}); | ||
}); | ||
}; | ||
await getStorageKeys(); |
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 move the let keys: Buffer[] = [];
declaration inside the getStorageKeys
function and then:
await getStorageKeys(); | |
const keys = await getStorageKeys(); |
return new Promise((resolve, reject) => { | ||
trie | ||
.createReadStream() | ||
.on("data", async data => { |
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.
.on("data", async data => { | |
.on("data", data => { |
.on("data", async data => { | ||
keys.push(data.key); | ||
}) | ||
.on("end", async () => { |
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.
.on("end", async () => { | |
.on("end", () => { |
type StepEvent = { | ||
gasLeft: BN; | ||
memory: Array<number>; // Not officially sure the type. Not a buffer or uint8array | ||
stack: Array<BN>; | ||
depth: number; | ||
opcode: { | ||
name: string; | ||
}; | ||
pc: number; | ||
address: 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.
Maybe we can move this type from here (and from the traceTransaction
) to a common place, maybe @ganache/ethereum-utils
can export this type?
debug_storageRangeAt
RPC
…the keys from the trie stream
9db8596
to
20ab776
Compare
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.
Only one more little quick fix and I think it's good to go! Awesome work @eshaben !
Co-authored-by: David Murdoch <[email protected]>
Resolves #682