How to retrieve the bytecode of NodeJS VM state? JavaScript Smart Contract experiment ** Updated **

Viewed 675

I am trying to reproduce the smart contract process of Ethereum by using NodeJS and the VM.

I have resolved some questions but it also raised a new one.

My goal would be to retrieve the bytecode that I load and execute in a NodeJS VM instance after it's execution;

The initial state would be the smart contract code that I load as bytecode in VM.

I also make two call that are in bytecode. and executed.

How could I retrieve the new state in bytecode from that VM instance?

const vm = require('vm');
const v8 = require('v8');

v8.setFlagsFromString('--no-lazy');

if (Number.parseInt(process.versions.node.split('.')[0], 10) >= 12) {
    v8.setFlagsFromString('--no-flush-bytecode'); // Thanks to A-Parser (@a-parser)
  }
  
  /**
 * Generates v8 bytecode buffer.
 * could be the compile for smart contract to compile the bytecode
 * the bytecode will go on the blockchain so it can never change.
 * The input could be a file with all the JavaScript
 * @param   {string} javascriptCode JavaScript source that will represent a smart contract on the blockchain
 * @returns {Buffer} The generated bytecode.
 */
const compileCode = function (javascriptCode) {

    if (typeof javascriptCode !== 'string') {
      throw new Error(`javascriptCode must be string. ${typeof javascriptCode} was given.`)
    }
  
    let script =  new vm.Script(javascriptCode)
    let bytecodeBuffer = script.createCachedData()

  return bytecodeBuffer;
}

/**
 * Runs v8 bytecode buffer and returns the result.
 * @param   {Buffer} bytecodeBuffer The buffer object that was created using compileCode function.
 * @returns {any}    The result of the very last statement executed in the script.
 */
const runBytecode = function (bytecodeBuffer) {

    if (!Buffer.isBuffer(bytecodeBuffer)) {
      throw new Error(`bytecodeBuffer must be a buffer object.`);
    }
  
   // fixBytecode(bytecodeBuffer);
  
    let length = readSourceHash(bytecodeBuffer);
  
    let dummyCode = "";
  
    if (length > 1) {
      dummyCode = '"' + "\u200b".repeat(length - 2) + '"'; // "\u200b" Zero width space
    }
  
    let script = new vm.Script(dummyCode, {
      cachedData: bytecodeBuffer
    });
  
    if (script.cachedDataRejected) {
      throw new Error('Invalid or incompatible cached data (cachedDataRejected)');
    }
   //console.log(bytecodeBuffer)
    return script.runInThisContext();
  };



// TODO: rewrite this function
const readSourceHash = function (bytecodeBuffer) {

    if (!Buffer.isBuffer(bytecodeBuffer)) {
      throw new Error(`bytecodeBuffer must be a buffer object.`)
    }
 
      return bytecodeBuffer.slice(8, 12).reduce((sum, number, power) => sum += number * Math.pow(256, power), 0)
    
  }





 /* 
  This is an example of a smart contract in javascript.
  It would get stored on the blockchain as bytecode.
  It could be compiled from a file to.
*/




 let smartContract = ` 

                function setName(_name){ 
                    name = _name
                    console.log('name set') 
                }
                
                function getName(){
                    console.log(name)
                }
                
                `

 // we compile the smart contract into bytecode
 // the contract will be loaded in the VM
 let bytecode = compileCode(smartContract)
 runBytecode(bytecode)

 /* 
  this call will set the name in the Contract that reside in the VM
  The name is set but not wrtien anywhere yet. It is only set on this
  instance fo the VM. This change the state an we would need to recompile
  the contract with the new data and update the blockchain.
  */
 let call = "setName('Satoshi')"
 let callBytecode = compileCode(call)
 runBytecode(callBytecode)



/*
  Execute the call in the contract in the VM
  the function is just printing out the value that we pass to our javascript contract
  the state of the contract did not change 

*/

let rCall = "getName()"
let rcallBytecode = compileCode(rCall)

  runBytecode(rcallBytecode)
 //console.log(bytecode)

How can I retrieve the bytecode that was loaded in the VM and save it with the name remaining there. Imagine an array of name and every time someone load and call that function it adds the name to it. Then save the new bytecode with that extra name in it. Save it and pass it to the next VM that want to run it.

0 Answers
Related