Skip to content

Commit

Permalink
Handle balance overflow as evm exception (#720)
Browse files Browse the repository at this point in the history
* Handle balance overflow as evm exception error

* vm: Lowercase exception messages

* vm: renaming error message variable

Co-authored-by: Everton Fraga <ev@ethereum.org>
  • Loading branch information
cgewecke and evertonfraga committed Apr 16, 2020
1 parent b24a74a commit 9cbf19b
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 13 deletions.
24 changes: 19 additions & 5 deletions packages/vm/lib/evm/evm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,17 +151,24 @@ export default class EVM {
// Load `to` account
const toAccount = await this._state.getAccount(message.to)
// Add tx value to the `to` account
let errorMessage
if (!message.delegatecall) {
await this._addToBalance(toAccount, message)
try {
await this._addToBalance(toAccount, message)
} catch (e) {
errorMessage = e
}
}

// Load code
await this._loadCode(message)
if (!message.code || message.code.length === 0) {
// Exit early if there's no code or value transfer overflowed
if (!message.code || message.code.length === 0 || errorMessage) {
return {
gasUsed: new BN(0),
execResult: {
gasUsed: new BN(0),
exceptionError: errorMessage, // Only defined if addToBalance failed
returnValue: Buffer.alloc(0),
},
}
Expand Down Expand Up @@ -218,14 +225,21 @@ export default class EVM {
toAccount.nonce = new BN(toAccount.nonce).addn(1).toArrayLike(Buffer)

// Add tx value to the `to` account
await this._addToBalance(toAccount, message)
let errorMessage
try {
await this._addToBalance(toAccount, message)
} catch (e) {
errorMessage = e
}

if (!message.code || message.code.length === 0) {
// Exit early if there's no contract code or value transfer overflowed
if (!message.code || message.code.length === 0 || errorMessage) {
return {
gasUsed: new BN(0),
createdAddress: message.to,
execResult: {
gasUsed: new BN(0),
exceptionError: errorMessage, // only defined if addToBalance failed
returnValue: Buffer.alloc(0),
},
}
Expand Down Expand Up @@ -383,7 +397,7 @@ export default class EVM {
async _addToBalance(toAccount: Account, message: Message): Promise<void> {
const newBalance = new BN(toAccount.balance).add(message.value)
if (newBalance.gt(MAX_INTEGER)) {
throw new Error('Value overflow')
throw new VmError(ERROR.VALUE_OVERFLOW)
}
toAccount.balance = toBuffer(newBalance)
// putAccount as the nonce may have changed for contract creation
Expand Down
1 change: 1 addition & 0 deletions packages/vm/lib/exceptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export enum ERROR {
CREATE_COLLISION = 'create collision',
STOP = 'stop',
REFUND_EXHAUSTED = 'refund exhausted',
VALUE_OVERFLOW = 'value overflow',
}

export class VmError {
Expand Down
43 changes: 35 additions & 8 deletions packages/vm/tests/api/runTx.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ tape('should run simple tx without errors', async (t) => {
t.end()
})

tape('should fail when account balance overflows', async t => {
tape('should fail when account balance overflows (call)', async t => {
const vm = new VM()
const suite = setup(vm)

Expand All @@ -84,11 +84,28 @@ tape('should fail when account balance overflows', async t => {
await suite.putAccount(tx.from.toString('hex'), from)
await suite.putAccount(tx.to, to)

shouldFail(t,
suite.runTx({ tx }),
(e) => t.equal(e.message, 'Value overflow')
)
const res = await suite.runTx({ tx })

t.equal(res.execResult.exceptionError.error, 'value overflow')
t.equal(vm.stateManager._checkpointCount, 0)
t.end()
})

tape('should fail when account balance overflows (create)', async t => {
const vm = new VM()
const suite = setup(vm)

const contractAddress = Buffer.from('37d6c3cdbc9304cad74eef8e18a85ed54263b4e7', 'hex')
const tx = getTransaction(true, true, '0x01', true)
const from = createAccount()
const to = createAccount('0x00', ethUtil.MAX_INTEGER)
await suite.putAccount(tx.from.toString('hex'), from)
await suite.putAccount(contractAddress, to)

const res = await suite.runTx({ tx })

t.equal(res.execResult.exceptionError.error, 'value overflow')
t.equal(vm.stateManager._checkpointCount, 0)
t.end()
})

Expand Down Expand Up @@ -117,15 +134,25 @@ function shouldFail (st, p, onErr) {
p.then(() => st.fail('runTx didnt return any errors')).catch(onErr)
}

function getTransaction (sign = false, calculageGas = false, value = '0x00') {
function getTransaction (sign = false, calculageGas = false, value = '0x00', createContract = false) {
let to = '0x0000000000000000000000000000000000000000'
let data = '0x7f7465737432000000000000000000000000000000000000000000000000000000600057'

if (createContract){
to = undefined
data = '0x6080604052348015600f57600080fd5b50603e80601d6000396000f3fe6080604052600080fdfea' +
'265627a7a723158204aed884a44fd1747efccba1447a2aa2d9a4b06dd6021c4a3bbb993021e0a909e' +
'64736f6c634300050f0032'
}

const privateKey = Buffer.from('e331b6d69882b4cb4ea581d88e0b604039a3de5967688d3dcffdd2270c0fd109', 'hex')
const txParams = {
nonce: '0x00',
gasPrice: 100,
gasLimit: 1000,
to: '0x0000000000000000000000000000000000000000',
to: to,
value: value,
data: '0x7f7465737432000000000000000000000000000000000000000000000000000000600057',
data: data,
chainId: 3
}

Expand Down

0 comments on commit 9cbf19b

Please sign in to comment.