-
Notifications
You must be signed in to change notification settings - Fork 765
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: Strip zeros when putting contract storage in StateManager #880
Changes from all commits
0fa3ff6
21e43e6
5217f50
ffd3beb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
import * as tape from 'tape' | ||
import { BN, toBuffer, keccak256, KECCAK256_RLP } from 'ethereumjs-util' | ||
import { BN, toBuffer, keccak256, KECCAK256_RLP, unpadBuffer, zeros } from 'ethereumjs-util' | ||
import Common from '@ethereumjs/common' | ||
import Account from '@ethereumjs/account' | ||
import { DefaultStateManager } from '../../../lib/state' | ||
|
@@ -409,3 +409,81 @@ tape('StateManager - Contract code', (tester) => { | |
t.end() | ||
}) | ||
}) | ||
|
||
tape('StateManager - Contract storage', (tester) => { | ||
const it = tester.test | ||
|
||
it('should throw on storage values larger than 32 bytes', async (t) => { | ||
t.plan(1) | ||
const stateManager = new DefaultStateManager() | ||
const address = zeros(20) | ||
const key = zeros(32) | ||
const value = Buffer.from('aa'.repeat(33), 'hex') | ||
try { | ||
await stateManager.putContractStorage(address, key, value) | ||
t.fail('did not throw') | ||
} catch (e) { | ||
t.pass('threw on trying to set storage values larger than 32 bytes') | ||
} | ||
t.end() | ||
}) | ||
|
||
it('should strip zeros of storage values', async (t) => { | ||
const stateManager = new DefaultStateManager() | ||
const address = zeros(20) | ||
|
||
const key0 = zeros(32) | ||
const value0 = Buffer.from('00' + 'aa'.repeat(30), 'hex') // put a value of 31-bytes length with a leading zero byte | ||
const expect0 = unpadBuffer(value0) | ||
await stateManager.putContractStorage(address, key0, value0) | ||
const slot0 = await stateManager.getContractStorage(address, key0) | ||
t.ok(slot0.equals(expect0), 'value of 31 bytes padded correctly') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Really nit, but I would think this test would be a bit better readable if the respective execution part of these two cases are combined with the value setup (so everything with *0 together and everything with *1 together) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed -> 5217f50 Note: I have edited this test a little bit (it did |
||
|
||
const key1 = Buffer.concat([zeros(31), Buffer.from('01', 'hex')]) | ||
const value1 = Buffer.from('0000' + 'aa'.repeat(1), 'hex') // put a value of 1-byte length with two leading zero bytes | ||
const expect1 = unpadBuffer(value1) | ||
await stateManager.putContractStorage(address, key1, value1) | ||
const slot1 = await stateManager.getContractStorage(address, key1) | ||
|
||
t.ok(slot1.equals(expect1), 'value of 1 byte padded correctly') | ||
t.end() | ||
}) | ||
|
||
it('should delete storage values which only consist of zero bytes', async (t) => { | ||
const address = zeros(20) | ||
const key = zeros(32) | ||
const startValue = Buffer.from('01', 'hex') | ||
|
||
const zeroLengths = [0, 1, 31, 32] // checks for arbitrary-length zeros | ||
t.plan(zeroLengths.length) | ||
|
||
for (let length of zeroLengths) { | ||
const stateManager = new DefaultStateManager() | ||
const value = zeros(length) | ||
await stateManager.putContractStorage(address, key, startValue) | ||
const currentValue = await stateManager.getContractStorage(address, key) | ||
if (!currentValue.equals(startValue)) { | ||
// sanity check | ||
t.fail('contract value not set correctly') | ||
} else { | ||
// delete the value | ||
await stateManager.putContractStorage(address, key, value) | ||
const deleted = await stateManager.getContractStorage(address, key) | ||
t.ok(deleted.equals(zeros(0)), 'the storage key should be deleted') | ||
} | ||
} | ||
t.end() | ||
}) | ||
|
||
it('should not strip trailing zeros', async (t) => { | ||
const address = zeros(20) | ||
const key = zeros(32) | ||
const value = Buffer.from('0000aabb00', 'hex') | ||
const expect = Buffer.from('aabb00', 'hex') | ||
const stateManager = new DefaultStateManager() | ||
await stateManager.putContractStorage(address, key, value) | ||
const contractValue = await stateManager.getContractStorage(address, key) | ||
t.ok(contractValue.equals(expect), 'trailing zeros are not stripped') | ||
t.end() | ||
}) | ||
}) |
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.
You are writing in the comments that a value will be left-padded and then you actually unpad (I read the semantics of this function as: "remove the padding", correct me if I am wrong) here, how does this go together?
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.
Oops this is a comment from when I was still thinking that storage slots should always be 32 bytes; this is thus not the case, the leading zeros are stripped. Will update