lib/evm/opFns.js
function makeCall (runState, callOptions, localOpts, cb) {
  var selfdestruct = Object.assign({}, runState.selfdestruct)
  callOptions.caller = callOptions.caller || runState.address
  callOptions.origin = runState.origin
  callOptions.gasPrice = runState.gasPrice
  callOptions.block = runState.block
  callOptions.static = callOptions.static || false
  callOptions.selfdestruct = selfdestruct
  callOptions.storageReader = runState.storageReader

  // increment the runState.depth
  callOptions.depth = runState.depth + 1

  // empty the return data buffer
  runState.lastReturned = Buffer.alloc(0)

  // check if account has enough ether
  // Note: in the case of delegatecall, the value is persisted and doesn't need to be deducted again
  if (runState.depth >= runState._common.param('vm', 'stackLimit') || (callOptions.delegatecall !== true && new BN(runState.contract.balance).lt(callOptions.value))) {
    runState.stack.push(new BN(0))
    cb(null)
  } else {
    // if creating a new contract then increament the nonce
    if (!callOptions.to) {
      runState.contract.nonce = new BN(runState.contract.nonce).addn(1)
    }

    runState.stateManager.putAccount(runState.address, runState.contract, function (err) {
      if (err) return cb(err)
      runState._vm.runCall(callOptions, parseCallResults)
    })
  }

  function parseCallResults (err, results) {
    if (err) return cb(err)

    // concat the runState.logs
    if (results.vm.logs) {
      runState.logs = runState.logs.concat(results.vm.logs)
    }

    // add gasRefund
    if (results.vm.gasRefund) {
      runState.gasRefund = runState.gasRefund.add(results.vm.gasRefund)
    }

    // this should always be safe
    runState.gasLeft.isub(results.gasUsed)

    // save results to memory
    if (results.vm.return && (!results.vm.exceptionError || results.vm.exceptionError.error === ERROR.REVERT)) {
      if (results.vm.return.length > 0) {
        const memOffset = localOpts.outOffset.toNumber()
        let dataLength = localOpts.outLength.toNumber()
        if (results.vm.return.length < dataLength) {
          dataLength = results.vm.return.length
        }
        const data = getDataSlice(results.vm.return, new BN(0), new BN(dataLength))
        runState.memory.extend(memOffset, dataLength)
        runState.memory.write(memOffset, dataLength, data)
      }

      if (results.vm.exceptionError && results.vm.exceptionError.error === ERROR.REVERT && isCreateOpCode(runState.opName)) {
        runState.lastReturned = results.vm.return
      }

      switch (runState.opName) {
        case 'CALL':
        case 'CALLCODE':
        case 'DELEGATECALL':
        case 'STATICCALL':
          runState.lastReturned = results.vm.return
          break
      }
    }

    if (!results.vm.exceptionError) {
      Object.assign(runState.selfdestruct, selfdestruct)
      // update stateRoot on current contract
      runState.stateManager.getAccount(runState.address, function (err, account) {
        if (err) return cb(err)

        runState.contract = account
        // push the created address to the stack
        if (results.createdAddress) {
          runState.stack.push(new BN(results.createdAddress))
          cb(null)
        } else {
          runState.stack.push(new BN(results.vm.exception))
          cb(null)
        }
      })
    } else {
      // creation failed so don't increment the nonce
      if (results.vm.createdAddress) {
        runState.contract.nonce = new BN(runState.contract.nonce).subn(1)
      }

      runState.stack.push(new BN(results.vm.exception))
      cb(null)
    }
  }
}
function makeCall (runState, callOptions, localOpts, cb) {
  var selfdestruct = Object.assign({}, runState.selfdestruct)
  callOptions.caller = callOptions.caller || runState.address
  callOptions.origin = runState.origin
  callOptions.gasPrice = runState.gasPrice
  callOptions.block = runState.block
  callOptions.static = callOptions.static || false
  callOptions.selfdestruct = selfdestruct
  callOptions.storageReader = runState.storageReader

  // increment the runState.depth
  callOptions.depth = runState.depth + 1

  // empty the return data buffer
  runState.lastReturned = Buffer.alloc(0)

  // check if account has enough ether
  // Note: in the case of delegatecall, the value is persisted and doesn't need to be deducted again
  if (runState.depth >= runState._common.param('vm', 'stackLimit') || (callOptions.delegatecall !== true && new BN(runState.contract.balance).lt(callOptions.value))) {
    runState.stack.push(new BN(0))
    cb(null)
  } else {
    // if creating a new contract then increament the nonce
    if (!callOptions.to) {
      runState.contract.nonce = new BN(runState.contract.nonce).addn(1)
    }

    runState.stateManager.putAccount(runState.address, runState.contract, function (err) {
      if (err) return cb(err)
      runState._vm.runCall(callOptions, parseCallResults)
    })
  }

  function parseCallResults (err, results) {
    if (err) return cb(err)

    // concat the runState.logs
    if (results.vm.logs) {
      runState.logs = runState.logs.concat(results.vm.logs)
    }

    // add gasRefund
    if (results.vm.gasRefund) {
      runState.gasRefund = runState.gasRefund.add(results.vm.gasRefund)
    }

    // this should always be safe
    runState.gasLeft.isub(results.gasUsed)

    // save results to memory
    if (results.vm.return && (!results.vm.exceptionError || results.vm.exceptionError.error === ERROR.REVERT)) {
      if (results.vm.return.length > 0) {
        const memOffset = localOpts.outOffset.toNumber()
        let dataLength = localOpts.outLength.toNumber()
        if (results.vm.return.length < dataLength) {
          dataLength = results.vm.return.length
        }
        const data = getDataSlice(results.vm.return, new BN(0), new BN(dataLength))
        runState.memory.extend(memOffset, dataLength)
        runState.memory.write(memOffset, dataLength, data)
      }

      if (results.vm.exceptionError && results.vm.exceptionError.error === ERROR.REVERT && isCreateOpCode(runState.opName)) {
        runState.lastReturned = results.vm.return
      }

      switch (runState.opName) {
        case 'CALL':
        case 'CALLCODE':
        case 'DELEGATECALL':
        case 'STATICCALL':
          runState.lastReturned = results.vm.return
          break
      }
    }

    if (!results.vm.exceptionError) {
      Object.assign(runState.selfdestruct, selfdestruct)
      // update stateRoot on current contract
      runState.stateManager.getAccount(runState.address, function (err, account) {
        if (err) return cb(err)

        runState.contract = account
        // push the created address to the stack
        if (results.createdAddress) {
          runState.stack.push(new BN(results.createdAddress))
          cb(null)
        } else {
          runState.stack.push(new BN(results.vm.exception))
          cb(null)
        }
      })
    } else {
      // creation failed so don't increment the nonce
      if (results.vm.createdAddress) {
        runState.contract.nonce = new BN(runState.contract.nonce).subn(1)
      }

      runState.stack.push(new BN(results.vm.exception))
      cb(null)
    }
  }
}
function makeCall ( runState , callOptions , localOpts , cb ) { var selfdestruct = Object . assign ( { } , runState . selfdestruct ) callOptions . caller = callOptions . caller || runState . address callOptions . origin = runState . origin callOptions . gasPrice = runState . gasPrice callOptions . block = runState . block callOptions . static = callOptions . static || false callOptions . selfdestruct = selfdestruct callOptions . storageReader = runState . storageReader // increment the runState.depth callOptions . depth = runState . depth + 1 // empty the return data buffer runState . lastReturned = Buffer . alloc ( 0 ) // check if account has enough ether // Note: in the case of delegatecall, the value is persisted and doesn't need to be deducted again if ( runState . depth >= runState . _common . param ( 'vm' , 'stackLimit' ) || ( callOptions . delegatecall !== true && new BN ( runState . contract . balance ) . lt ( callOptions . value ) ) ) { runState . stack . push ( new BN ( 0 ) ) cb ( null ) } else { // if creating a new contract then increament the nonce if ( ! callOptions . to ) { runState . contract . nonce = new BN ( runState . contract . nonce ) . addn ( 1 ) } runState . stateManager . putAccount ( runState . address , runState . contract , function ( err ) { if ( err ) return cb ( err ) runState . _vm . runCall ( callOptions , parseCallResults ) } ) } function parseCallResults ( err , results ) { if ( err ) return cb ( err ) // concat the runState.logs if ( results . vm . logs ) { runState . logs = runState . logs . concat ( results . vm . logs ) } // add gasRefund if ( results . vm . gasRefund ) { runState . gasRefund = runState . gasRefund . add ( results . vm . gasRefund ) } // this should always be safe runState . gasLeft . isub ( results . gasUsed ) // save results to memory if ( results . vm . return && ( ! results . vm . exceptionError || results . vm . exceptionError . error === ERROR . REVERT ) ) { if ( results . vm . return . length > 0 ) { const memOffset = localOpts . outOffset . toNumber ( ) let dataLength = localOpts . outLength . toNumber ( ) if ( results . vm . return . length < dataLength ) { dataLength = results . vm . return . length } const data = getDataSlice ( results . vm . return , new BN ( 0 ) , new BN ( dataLength ) ) runState . memory . extend ( memOffset , dataLength ) runState . memory . write ( memOffset , dataLength , data ) } if ( results . vm . exceptionError && results . vm . exceptionError . error === ERROR . REVERT && isCreateOpCode ( runState . opName ) ) { runState . lastReturned = results . vm . return } switch ( runState . opName ) { case 'CALL' : case 'CALLCODE' : case 'DELEGATECALL' : case 'STATICCALL' : runState . lastReturned = results . vm . return break } } if ( ! results . vm . exceptionError ) { Object . assign ( runState . selfdestruct , selfdestruct ) // update stateRoot on current contract runState . stateManager . getAccount ( runState . address , function ( err , account ) { if ( err ) return cb ( err ) runState . contract = account // push the created address to the stack if ( results . createdAddress ) { runState . stack . push ( new BN ( results . createdAddress ) ) cb ( null ) } else { runState . stack . push ( new BN ( results . vm . exception ) ) cb ( null ) } } ) } else { // creation failed so don't increment the nonce if ( results . vm . createdAddress ) { runState . contract . nonce = new BN ( runState . contract . nonce ) . subn ( 1 ) } runState . stack . push ( new BN ( results . vm . exception ) ) cb ( null ) } } }
sets up and calls runCall
sets up and calls runCall