const Buffer = require('safe-buffer').Buffer // use for Node.js <4.5.0
const async = require('async')
const Trie = require('merkle-patricia-tree/secure')
const Block = require('ethereumjs-block')
const Blockchain = require('ethereumjs-blockchain')
const BlockHeader = require('ethereumjs-block/header.js')
const VM = require('../../')
const level = require('level')
const levelMem = require('level-mem')
const Account = require('ethereumjs-account').default
const utils = require('ethereumjs-util')
const BN = utils.BN
const rlp = utils.rlp
const testData = require('./test-data')
// inMemory blockchainDB
var blockchainDB = levelMem()

var state = new Trie()

var validate = false

var hardfork = 'byzantium'

var blockchain = new Blockchain({ db: blockchainDB, hardfork, validate })

if (validate) {
  blockchain.ethash.cacheDB = level('./.cachedb')
}

var vm = new VM({
  state: state,
  blockchain: blockchain,
  hardfork
})
var genesisBlock = new Block({ hardfork })

testData.homestead = true

vm.on('beforeTx', function (tx) {
  tx._homestead = true
})

vm.on('beforeBlock', function (block) {
  block.header.isHomestead = function () {
    return true
  }
})

async.series([
  // set up pre-state
  function (next) {
    setupPreConditions(state, testData, next)
  },

  // create and add genesis block
  function (next) {
    genesisBlock.header = new BlockHeader(formatBlockHeader(testData.genesisBlockHeader),
      { hardfork })

    blockchain.putGenesis(genesisBlock, next)
  },

  // add some following blocks
  function (next) {
    async.eachSeries(testData.blocks, eachBlock, next)

    function eachBlock (raw, cb) {
      try {
        var block = new Block(
          Buffer.from(raw.rlp.slice(2), 'hex'))

        // forces the block into thinking they are homestead
        block.header.isHomestead = function () {
          return true
        }
        block.uncleHeaders.forEach(function (uncle) {
          uncle.isHomestead = function () { return true }
        })

        blockchain.putBlock(block, function (err) {
          cb(err)
        })
      } catch (err) {
        cb()
      }
    }
  },

  // make sure the blocks check
  // if a block is missing, vm.runBlockchain will fail
  function runBlockchain (next) {
    vm.runBlockchain(next)
  },

  // get the blockchain head
  function getHead (next) {
    vm.blockchain.getHead(function (err, block) {
      // make sure the state is set before checking post conditions
      state.root = block.header.stateRoot
      next(err)
    })
  }
], function () {
  console.log('--- Finished processing the BlockChain ---')
  console.log('New head:', '0x' + blockchain.meta.rawHead.toString('hex'))
  console.log('Expected:', testData.lastblockhash)
})

function setupPreConditions (state, testData, done) {
  var keysOfPre = Object.keys(testData.pre)

  async.eachSeries(keysOfPre, function (key, callback) {
    var acctData = testData.pre[key]
    var account = new Account()

    account.nonce = format(acctData.nonce)
    account.balance = format(acctData.balance)

    var codeBuf = Buffer.from(acctData.code.slice(2), 'hex')
    var storageTrie = state.copy()
    storageTrie.root = null

    async.series([

      function (cb2) {
        var keys = Object.keys(acctData.storage)

        async.forEachSeries(keys, function (key, cb3) {
          var val = acctData.storage[key]
          val = rlp.encode(Buffer.from(val.slice(2), 'hex'))
          key = utils.setLength(Buffer.from(key.slice(2), 'hex'), 32)

          storageTrie.put(key, val, cb3)
        }, cb2)
      },
      function (cb2) {
        account.setCode(state, codeBuf, cb2)
      },
      function (cb2) {
        account.stateRoot = storageTrie.root

        if (testData.exec && key === testData.exec.address) {
          testData.root = storageTrie.root
        }
        state.put(Buffer.from(utils.stripHexPrefix(key), 'hex'), account.serialize(), function () {
          cb2()
        })
      }
    ], callback)
  }, done)
}

function format (a, toZero, isHex) {
  if (a === '') {
    return Buffer.alloc(0)
  }

  if (a.slice && a.slice(0, 2) === '0x') {
    a = a.slice(2)
    if (a.length % 2) a = '0' + a
    a = Buffer.from(a, 'hex')
  } else if (!isHex) {
    a = Buffer.from(new BN(a).toArray())
  } else {
    if (a.length % 2) a = '0' + a
    a = Buffer.from(a, 'hex')
  }

  if (toZero && a.toString('hex') === '') {
    a = Buffer.from([0])
  }

  return a
}

function formatBlockHeader (data) {
  var r = {}
  var keys = Object.keys(data)
  keys.forEach(function (key) {
    r[key] = utils.addHexPrefix(data[key])
  })
  return r
}

@@ -327,16 +327,24 @@
 ../../')
+.default
 %0Aconst l
@@ -670,52 +670,49 @@
 var 
-validate = false%0A%0Avar hardfork = 'byzantium'
+hardfork = testData.network.toLowerCase()
 %0A%0Ava
@@ -773,41 +773,12 @@
 fork
-, validate %7D)%0A%0Aif (validate) %7B%0A  
+ %7D)%0A
 bloc
@@ -820,18 +820,16 @@
 achedb')
-%0A%7D
 %0A%0Avar vm
@@ -944,35 +944,8 @@
 %7D)%0A%0A
-testData.homestead = true%0A%0A
 vm.o
@@ -1317,26 +1317,8 @@
 der(
-formatBlockHeader(
 test
@@ -1340,17 +1340,16 @@
 ckHeader
-)
 ,%0A      
@@ -4363,177 +4363,4 @@
 %0A%7D%0A%0A
-function formatBlockHeader (data) %7B%0A  var r = %7B%7D%0A  var keys = Object.keys(data)%0A  keys.forEach(function (key) %7B%0A    r%5Bkey%5D = utils.addHexPrefix(data%5Bkey%5D)%0A  %7D)%0A  return r%0A%7D%0A

rebase and in response of review