@ -1,309 +1,338 @@
const util = require ( '../util' )
const uiutil = require ( '../helpers/uiHelper' )
const ethutil = require ( 'ethereumjs-util' )
import { hexConvert , hexListFromBNs , formatMemory } from '../util'
import { normalizeHexAddress } from '../helpers/uiHelper'
import { toChecksumAddress , BN , toBuffer , } from 'ethereumjs-util'
const Web3 = require ( 'web3' )
function web3VmProvider ( ) {
this . web3 = new Web3 ( )
this . vm = null
this . vmTraces = { }
this . txs = { }
this . txsReceipt = { }
this . processingHash = null
this . processingAddress = null
this . processingIndex = null
this . previousDepth = 0
this . incr = 0
this . eth = { }
this . debug = { }
this . eth . getCode = ( . . . args ) = > this . getCode ( . . . args )
this . eth . getTransaction = ( . . . args ) = > this . getTransaction ( . . . args )
this . eth . getTransactionReceipt = ( . . . args ) = > this . getTransactionReceipt ( . . . args )
this . eth . getTransactionFromBlock = ( . . . args ) = > this . getTransactionFromBlock ( . . . args )
this . eth . getBlockNumber = ( . . . args ) = > this . getBlockNumber ( . . . args )
this . debug . traceTransaction = ( . . . args ) = > this . traceTransaction ( . . . args )
this . debug . storageRangeAt = ( . . . args ) = > this . storageRangeAt ( . . . args )
this . debug . preimage = ( . . . args ) = > this . preimage ( . . . args )
this . providers = { 'HttpProvider' : function ( url ) { } }
this . currentProvider = { 'host' : 'vm provider' }
this . storageCache = { }
this . lastProcessedStorageTxHash = { }
this . sha3Preimages = { }
// util
this . sha3 = ( . . . args ) = > this . web3 . utils . sha3 ( . . . args )
this . toHex = ( . . . args ) = > this . web3 . utils . toHex ( . . . args )
this . toAscii = ( . . . args ) = > this . web3 . utils . hexToAscii ( . . . args )
this . fromAscii = ( . . . args ) = > this . web3 . utils . asciiToHex ( . . . args )
this . fromDecimal = ( . . . args ) = > this . web3 . utils . numberToHex ( . . . args )
this . fromWei = ( . . . args ) = > this . web3 . utils . fromWei ( . . . args )
this . toWei = ( . . . args ) = > this . web3 . utils . toWei ( . . . args )
this . toBigNumber = ( . . . args ) = > this . web3 . utils . toBN ( . . . args )
this . isAddress = ( . . . args ) = > this . web3 . utils . isAddress ( . . . args )
this . utils = Web3 . utils || [ ]
}
export class Web3VmProvider {
web3VmProvider . prototype . setVM = function ( vm ) {
if ( this . vm === vm ) return
this . vm = vm
this . vm . on ( 'step' , ( data ) = > {
this . pushTrace ( this , data )
} )
this . vm . on ( 'afterTx' , ( data ) = > {
this . txProcessed ( this , data )
} )
this . vm . on ( 'beforeTx' , ( data ) = > {
this . txWillProcess ( this , data )
} )
}
web3
vm
vmTraces
txs
txsReceipt
processingHash
processingAddress
processingIndex
previousDepth
incr
eth
debug
providers
currentProvider
storageCache
lastProcessedStorageTxHash
sha3Preimages
sha3
toHex
toAscii
fromAscii
fromDecimal
fromWei
toWei
toBigNumber
isAddress
utils
web3VmProvider . prototype . releaseCurrentHash = function ( ) {
const ret = this . processingHash
this . processingHash = undefined
return ret
}
web3VmProvider . prototype . txWillProcess = function ( self , data ) {
self . incr ++
self . processingHash = util . hexConvert ( data . hash ( ) )
self . vmTraces [ self . processingHash ] = {
gas : '0x0' ,
return : '0x0' ,
structLogs : [ ]
}
let tx = { }
tx . hash = self . processingHash
tx . from = ethutil . toChecksumAddress ( util . hexConvert ( data . getSenderAddress ( ) ) )
if ( data . to && data . to . length ) {
tx . to = ethutil . toChecksumAddress ( util . hexConvert ( data . to ) )
constructor ( ) {
this . web3 = new Web3 ( )
this . vm = null
this . vmTraces = { }
this . txs = { }
this . txsReceipt = { }
this . processingHash = null
this . processingAddress = null
this . processingIndex = null
this . previousDepth = 0
this . incr = 0
this . eth = { }
this . debug = { }
this . eth . getCode = ( . . . args ) = > this . getCode ( . . . args )
this . eth . getTransaction = ( . . . args ) = > this . getTransaction ( . . . args )
this . eth . getTransactionReceipt = ( . . . args ) = > this . getTransactionReceipt ( . . . args )
this . eth . getTransactionFromBlock = ( . . . args ) = > this . getTransactionFromBlock ( . . . args )
this . eth . getBlockNumber = ( . . . args ) = > this . getBlockNumber ( . . . args )
this . debug . traceTransaction = ( . . . args ) = > this . traceTransaction ( . . . args )
this . debug . storageRangeAt = ( . . . args ) = > this . storageRangeAt ( . . . args )
this . debug . preimage = ( . . . args ) = > this . preimage ( . . . args )
this . providers = { 'HttpProvider' : function ( url ) { } }
this . currentProvider = { 'host' : 'vm provider' }
this . storageCache = { }
this . lastProcessedStorageTxHash = { }
this . sha3Preimages = { }
// util
this . sha3 = ( . . . args ) = > this . web3 . utils . sha3 ( . . . args )
this . toHex = ( . . . args ) = > this . web3 . utils . toHex ( . . . args )
this . toAscii = ( . . . args ) = > this . web3 . utils . hexToAscii ( . . . args )
this . fromAscii = ( . . . args ) = > this . web3 . utils . asciiToHex ( . . . args )
this . fromDecimal = ( . . . args ) = > this . web3 . utils . numberToHex ( . . . args )
this . fromWei = ( . . . args ) = > this . web3 . utils . fromWei ( . . . args )
this . toWei = ( . . . args ) = > this . web3 . utils . toWei ( . . . args )
this . toBigNumber = ( . . . args ) = > this . web3 . utils . toBN ( . . . args )
this . isAddress = ( . . . args ) = > this . web3 . utils . isAddress ( . . . args )
this . utils = Web3 . utils || [ ]
}
this . processingAddress = tx . to
tx . data = util . hexConvert ( data . data )
tx . input = util . hexConvert ( data . input )
tx . gas = ( new ethutil . BN ( util . hexConvert ( data . gas ) . replace ( '0x' , '' ) , 16 ) ) . toString ( 10 )
if ( data . value ) {
tx . value = util . hexConvert ( data . value )
}
self . txs [ self . processingHash ] = tx
self . txsReceipt [ self . processingHash ] = tx
self . storageCache [ self . processingHash ] = { }
if ( tx . to ) {
const account = ethutil . toBuffer ( tx . to )
self . vm . stateManager . dumpStorage ( account , ( storage ) = > {
self . storageCache [ self . processingHash ] [ tx . to ] = storage
self . lastProcessedStorageTxHash [ tx . to ] = self . processingHash
setVM ( vm ) {
if ( this . vm === vm ) return
this . vm = vm
this . vm . on ( 'step' , ( data ) = > {
this . pushTrace ( this , data )
} )
this . vm . on ( 'afterTx' , ( data ) = > {
this . txProcessed ( this , data )
} )
this . vm . on ( 'beforeTx' , ( data ) = > {
this . txWillProcess ( this , data )
} )
}
this . processingIndex = 0
}
web3VmProvider . prototype . txProcessed = function ( self , data ) {
const lastOp = self . vmTraces [ self . processingHash ] . structLogs [ self . processingIndex - 1 ]
if ( lastOp ) {
lastOp . error = lastOp . op !== 'RETURN' && lastOp . op !== 'STOP' && lastOp . op !== 'SELFDESTRUCT'
releaseCurrentHash ( ) {
const ret = this . processingHash
this . processingHash = undefined
return ret
}
self . vmTraces [ self . processingHash ] . gas = '0x' + data . gasUsed . toString ( 16 )
const logs = [ ]
for ( let l in data . execResult . logs ) {
const log = data . execResult . logs [ l ]
const topics = [ ]
if ( log [ 1 ] . length > 0 ) {
for ( var k in log [ 1 ] ) {
topics . push ( '0x' + log [ 1 ] [ k ] . toString ( 'hex' ) )
}
} else {
topics . push ( '0x' )
txWillProcess ( self , data ) {
self . incr ++
self . processingHash = hexConvert ( data . hash ( ) )
self . vmTraces [ self . processingHash ] = {
gas : '0x0' ,
return : '0x0' ,
structLogs : [ ]
}
logs . push ( {
address : '0x' + log [ 0 ] . toString ( 'hex' ) ,
data : '0x' + log [ 2 ] . toString ( 'hex' ) ,
topics : topics ,
rawVMResponse : log
} )
let tx = { }
tx [ 'hash' ] = self . processingHash
tx [ 'from' ] = toChecksumAddress ( hexConvert ( data . getSenderAddress ( ) ) )
if ( data . to && data . to . length ) {
tx [ 'to' ] = toChecksumAddress ( hexConvert ( data . to ) )
}
this . processingAddress = tx [ 'to' ]
tx [ 'data' ] = hexConvert ( data . data )
tx [ 'input' ] = hexConvert ( data . input )
tx [ 'gas' ] = ( new BN ( hexConvert ( data . gas ) . replace ( '0x' , '' ) , 16 ) ) . toString ( 10 )
if ( data . value ) {
tx [ 'value' ] = hexConvert ( data . value )
}
self . txs [ self . processingHash ] = tx
self . txsReceipt [ self . processingHash ] = tx
self . storageCache [ self . processingHash ] = { }
if ( tx [ 'to' ] ) {
const account = toBuffer ( tx [ 'to' ] )
self . vm . stateManager . dumpStorage ( account , ( storage ) = > {
self . storageCache [ self . processingHash ] [ tx [ 'to' ] ] = storage
self . lastProcessedStorageTxHash [ tx [ 'to' ] ] = self . processingHash
} )
}
this . processingIndex = 0
}
self . txsReceipt [ self . processingHash ] . logs = logs
self . txsReceipt [ self . processingHash ] . transactionHash = self . processingHash
const status = data . execResult . exceptionError ? 0 : 1
self . txsReceipt [ self . processingHash ] . status = ` 0x ${ status } `
if ( data . createdAddress ) {
const address = util . hexConvert ( data . createdAddress )
self . vmTraces [ self . processingHash ] . return = ethutil . toChecksumAddress ( address )
self . txsReceipt [ self . processingHash ] . contractAddress = ethutil . toChecksumAddress ( address )
} else if ( data . execResult . returnValue ) {
self . vmTraces [ self . processingHash ] . return = util . hexConvert ( data . execResult . returnValue )
} else {
self . vmTraces [ self . processingHash ] . return = '0x'
}
this . processingIndex = null
this . processingAddress = null
this . previousDepth = 0
}
txProcessed ( self , data ) {
const lastOp = self . vmTraces [ self . processingHash ] . structLogs [ self . processingIndex - 1 ]
if ( lastOp ) {
lastOp . error = lastOp . op !== 'RETURN' && lastOp . op !== 'STOP' && lastOp . op !== 'SELFDESTRUCT'
}
self . vmTraces [ self . processingHash ] . gas = '0x' + data . gasUsed . toString ( 16 )
web3VmProvider . prototype . pushTrace = function ( self , data ) {
const depth = data . depth + 1 // geth starts the depth from 1
if ( ! self . processingHash ) {
console . log ( 'no tx processing' )
return
}
let previousopcode
if ( self . vmTraces [ self . processingHash ] && self . vmTraces [ self . processingHash ] . structLogs [ this . processingIndex - 1 ] ) {
previousopcode = self . vmTraces [ self . processingHash ] . structLogs [ this . processingIndex - 1 ]
}
const logs = [ ]
for ( let l in data . execResult . logs ) {
const log = data . execResult . logs [ l ]
const topics = [ ]
if ( log [ 1 ] . length > 0 ) {
for ( var k in log [ 1 ] ) {
topics . push ( '0x' + log [ 1 ] [ k ] . toString ( 'hex' ) )
}
} else {
topics . push ( '0x' )
}
logs . push ( {
address : '0x' + log [ 0 ] . toString ( 'hex' ) ,
data : '0x' + log [ 2 ] . toString ( 'hex' ) ,
topics : topics ,
rawVMResponse : log
} )
}
self . txsReceipt [ self . processingHash ] . logs = logs
self . txsReceipt [ self . processingHash ] . transactionHash = self . processingHash
const status = data . execResult . exceptionError ? 0 : 1
self . txsReceipt [ self . processingHash ] . status = ` 0x ${ status } `
if ( this . previousDepth > depth && previousopcode ) {
// returning from context, set error it is not STOP, RETURN
previousopcode . invalidDepthChange = previousopcode . op !== 'RETURN' && previousopcode . op !== 'STOP'
}
const step = {
stack : util.hexListFromBNs ( data . stack ) ,
memory : util.formatMemory ( data . memory ) ,
storage : data.storage ,
op : data.opcode.name ,
pc : data.pc ,
gasCost : data.opcode.fee.toString ( ) ,
gas : data.gasLeft.toString ( ) ,
depth : depth ,
error : data.error === false ? undefined : data . error
}
self . vmTraces [ self . processingHash ] . structLogs . push ( step )
if ( step . op === 'CREATE' || step . op === 'CALL' ) {
if ( step . op === 'CREATE' ) {
this . processingAddress = '(Contract Creation - Step ' + this . processingIndex + ')'
this . storageCache [ this . processingHash ] [ this . processingAddress ] = { }
this . lastProcessedStorageTxHash [ this . processingAddress ] = this . processingHash
if ( data . createdAddress ) {
const address = hexConvert ( data . createdAddress )
self . vmTraces [ self . processingHash ] . return = toChecksumAddress ( address )
self . txsReceipt [ self . processingHash ] . contractAddress = toChecksumAddress ( address )
} else if ( data . execResult . returnValue ) {
self . vmTraces [ self . processingHash ] . return = hexConvert ( data . execResult . returnValue )
} else {
this . processingAddress = uiutil . normalizeHexAddress ( step . stack [ step . stack . length - 2 ] )
this . processingAddress = ethutil . toChecksumAddress ( this . processingAddress )
if ( ! self . storageCache [ self . processingHash ] [ this . processingAddress ] ) {
const account = ethutil . toBuffer ( this . processingAddress )
self . vm . stateManager . dumpStorage ( account , function ( storage ) {
self . storageCache [ self . processingHash ] [ self . processingAddress ] = storage
self . lastProcessedStorageTxHash [ self . processingAddress ] = self . processingHash
} )
}
self . vmTraces [ self . processingHash ] . return = '0x'
}
this . processingIndex = null
this . processingAddress = null
this . previousDepth = 0
}
if ( previousopcode && previousopcode . op === 'SHA3' ) {
const preimage = getSha3Input ( previousopcode . stack , previousopcode . memory )
const imageHash = step . stack [ step . stack . length - 1 ] . replace ( '0x' , '' )
self . sha3Preimages [ imageHash ] = {
'preimage' : preimage
pushTrace ( self , data ) {
const depth = data . depth + 1 // geth starts the depth from 1
if ( ! self . processingHash ) {
console . log ( 'no tx processing' )
return
}
let previousopcode
if ( self . vmTraces [ self . processingHash ] && self . vmTraces [ self . processingHash ] . structLogs [ this . processingIndex - 1 ] ) {
previousopcode = self . vmTraces [ self . processingHash ] . structLogs [ this . processingIndex - 1 ]
}
}
this . processingIndex ++
this . previousDepth = depth
}
if ( this . previousDepth > depth && previousopcode ) {
// returning from context, set error it is not STOP, RETURN
previousopcode . invalidDepthChange = previousopcode . op !== 'RETURN' && previousopcode . op !== 'STOP'
}
const step = {
stack : hexListFromBNs ( data . stack ) ,
memory : formatMemory ( data . memory ) ,
storage : data.storage ,
op : data.opcode.name ,
pc : data.pc ,
gasCost : data.opcode.fee.toString ( ) ,
gas : data.gasLeft.toString ( ) ,
depth : depth ,
error : data.error === false ? undefined : data . error
}
self . vmTraces [ self . processingHash ] . structLogs . push ( step )
if ( step . op === 'CREATE' || step . op === 'CALL' ) {
if ( step . op === 'CREATE' ) {
this . processingAddress = '(Contract Creation - Step ' + this . processingIndex + ')'
this . storageCache [ this . processingHash ] [ this . processingAddress ] = { }
this . lastProcessedStorageTxHash [ this . processingAddress ] = this . processingHash
} else {
this . processingAddress = normalizeHexAddress ( step . stack [ step . stack . length - 2 ] )
this . processingAddress = toChecksumAddress ( this . processingAddress )
if ( ! self . storageCache [ self . processingHash ] [ this . processingAddress ] ) {
const account = toBuffer ( this . processingAddress )
self . vm . stateManager . dumpStorage ( account , function ( storage ) {
self . storageCache [ self . processingHash ] [ self . processingAddress ] = storage
self . lastProcessedStorageTxHash [ self . processingAddress ] = self . processingHash
} )
}
}
}
if ( previousopcode && previousopcode . op === 'SHA3' ) {
const preimage = this . getSha3Input ( previousopcode . stack , previousopcode . memory )
const imageHash = step . stack [ step . stack . length - 1 ] . replace ( '0x' , '' )
self . sha3Preimages [ imageHash ] = {
'preimage' : preimage
}
}
web3VmProvider . prototype . getCode = function ( address , cb ) {
address = ethutil . toChecksumAddress ( address )
const account = ethutil . toBuffer ( address )
this . vm . stateManager . getContractCode ( account , ( error , result ) = > {
cb ( error , util . hexConvert ( result ) )
} )
}
this . processingIndex ++
this . previousDepth = depth
}
getCode ( address , cb ) {
address = toChecksumAddress ( address )
const account = toBuffer ( address )
this . vm . stateManager . getContractCode ( account , ( error , result ) = > {
cb ( error , hexConvert ( result ) )
} )
}
web3VmProvider . prototype . setProvider = function ( provider ) { }
setProvider ( provider ) { }
web3VmProvider . prototype . traceTransaction = function ( txHash , options , cb ) {
if ( this . vmTraces [ txHash ] ) {
traceTransaction ( txHash , options , cb ) {
if ( this . vmTraces [ txHash ] ) {
if ( cb ) {
cb ( null , this . vmTraces [ txHash ] )
}
return this . vmTraces [ txHash ]
}
if ( cb ) {
cb ( null , this . vmTraces [ txHash ] )
cb ( 'unable to retrieve traces ' + txHash , null )
}
return this . vmTraces [ txHash ]
}
if ( cb ) {
cb ( 'unable to retrieve traces ' + txHash , null )
}
}
web3VmProvider . prototype . storageRangeAt = function ( blockNumber , txIndex , address , start , maxLength , cb ) { // txIndex is the hash in the case of the VM
// we don't use the range params here
address = ethutil . toChecksumAddress ( address )
storageRangeAt ( blockNumber , txIndex , address , start , maxLength , cb ) { // txIndex is the hash in the case of the VM
// we don't use the range params here
address = toChecksumAddress ( address )
if ( txIndex === 'latest' ) {
txIndex = this . lastProcessedStorageTxHash [ address ]
}
if ( txIndex === 'latest' ) {
txIndex = this . lastProcessedStorageTxHash [ address ]
}
if ( this . storageCache [ txIndex ] && this . storageCache [ txIndex ] [ address ] ) {
const storage = this . storageCache [ txIndex ] [ address ]
return cb ( null , {
storage : JSON.parse ( JSON . stringify ( storage ) ) ,
nextKey : null
} )
if ( this . storageCache [ txIndex ] && this . storageCache [ txIndex ] [ address ] ) {
const storage = this . storageCache [ txIndex ] [ address ]
return cb ( null , {
storage : JSON.parse ( JSON . stringify ( storage ) ) ,
nextKey : null
} )
}
cb ( 'unable to retrieve storage ' + txIndex + ' ' + address )
}
cb ( 'unable to retrieve storage ' + txIndex + ' ' + address )
}
web3VmProvider . prototype . getBlockNumber = function ( cb ) { cb ( null , 'vm provider' ) }
getBlockNumber ( cb ) { cb ( null , 'vm provider' ) }
web3VmProvider . prototype . getTransaction = function ( txHash , cb ) {
if ( this . txs [ txHash ] ) {
getTransaction ( txHash , cb ) {
if ( this . txs [ txHash ] ) {
if ( cb ) {
cb ( null , this . txs [ txHash ] )
}
return this . txs [ txHash ]
}
if ( cb ) {
cb ( null , this . txs [ txHash ] )
cb ( 'unable to retrieve tx ' + txHash , null )
}
return this . txs [ txHash ]
}
if ( cb ) {
cb ( 'unable to retrieve tx ' + txHash , null )
}
}
web3VmProvider . prototype . getTransactionReceipt = function ( txHash , cb ) {
// same as getTransaction but return the created address also
if ( this . txsReceipt [ txHash ] ) {
getTransactionReceipt ( txHash , cb ) {
// same as getTransaction but return the created address also
if ( this . txsReceipt [ txHash ] ) {
if ( cb ) {
cb ( null , this . txsReceipt [ txHash ] )
}
return this . txsReceipt [ txHash ]
}
if ( cb ) {
cb ( null , this . txsReceipt [ txHash ] )
cb ( 'unable to retrieve txReceipt ' + txHash , null )
}
return this . txsReceipt [ txHash ]
}
if ( cb ) {
cb ( 'unable to retrieve txReceipt ' + txHash , null )
}
}
web3VmProvider . prototype . getTransactionFromBlock = function ( blockNumber , txIndex , cb ) {
const mes = 'not supposed to be needed by remix in vmmode'
console . log ( mes )
if ( cb ) {
cb ( mes , null )
getTransactionFromBlock ( blockNumber , txIndex , cb ) {
const mes = 'not supposed to be needed by remix in vmmode'
console . log ( mes )
if ( cb ) {
cb ( mes , null )
}
}
}
web3VmProvider . prototype . preimage = function ( hashedKey , cb ) {
hashedKey = hashedKey . replace ( '0x' , '' )
cb ( null , this . sha3Preimages [ hashedKey ] !== undefined ? this . sha3Preimages [ hashedKey ] . preimage : null )
}
preimage ( hashedKey , cb ) {
hashedKey = hashedKey . replace ( '0x' , '' )
cb ( null , this . sha3Preimages [ hashedKey ] !== undefined ? this . sha3Preimages [ hashedKey ] . preimage : null )
}
function getSha3Input ( stack , memory ) {
let memoryStart = stack [ stack . length - 1 ]
let memoryLength = stack [ stack . length - 2 ]
const memStartDec = ( new ethutil . BN ( memoryStart . replace ( '0x' , '' ) , 16 ) ) . toString ( 10 )
memoryStart = parseInt ( memStartDec ) * 2
const memLengthDec = ( new ethutil . BN ( memoryLength . replace ( '0x' , '' ) , 16 ) . toString ( 10 ) )
memoryLength = parseInt ( memLengthDec ) * 2
getSha3Input ( stack , memory ) {
let memoryStart = stack [ stack . length - 1 ]
let memoryLength = stack [ stack . length - 2 ]
const memStartDec = ( new BN ( memoryStart . replace ( '0x' , '' ) , 16 ) ) . toString ( 10 )
memoryStart = parseInt ( memStartDec ) * 2
const memLengthDec = ( new BN ( memoryLength . replace ( '0x' , '' ) , 16 ) . toString ( 10 ) )
memoryLength = parseInt ( memLengthDec ) * 2
let i = Math . floor ( memoryStart / 32 )
const maxIndex = Math . floor ( memoryLength / 32 ) + i
if ( ! memory [ i ] ) {
return emptyFill ( memoryLength )
}
let sha3Input = memory [ i ] . slice ( memoryStart - 32 * i )
i ++
while ( i < maxIndex ) {
sha3Input += memory [ i ] ? memory [ i ] : emptyFill ( 32 )
let i = Math . floor ( memoryStart / 32 )
const maxIndex = Math . floor ( memoryLength / 32 ) + i
if ( ! memory [ i ] ) {
return this . emptyFill ( memoryLength )
}
let sha3Input = memory [ i ] . slice ( memoryStart - 32 * i )
i ++
while ( i < maxIndex ) {
sha3Input += memory [ i ] ? memory [ i ] : this . emptyFill ( 32 )
i ++
}
if ( sha3Input . length < memoryLength ) {
const leftSize = memoryLength - sha3Input . length
sha3Input += memory [ i ] ? memory [ i ] . slice ( 0 , leftSize ) : this . emptyFill ( leftSize )
}
return sha3Input
}
if ( sha3Input . length < memoryLength ) {
const leftSize = memoryLength - sha3Input . length
sha3Input += memory [ i ] ? memory [ i ] . slice ( 0 , leftSize ) : emptyFill ( leftSize )
}
return sha3Input
}
function emptyFill ( size ) {
return ( new Array ( size ) ) . join ( '0' )
emptyFill ( size ) {
return ( new Array ( size ) ) . join ( '0' )
}
}
module .exports = web3VmProvider