1. 程式人生 > >ethereumjs-vm/examples/run-transactions-complete

ethereumjs-vm/examples/run-transactions-complete

1.設定賬戶:

ethereumjs-vm/examples/run-transactions-complete/key-pair.json

{
  "secretKey": "3cd7232cd6f3fc66a57a6bedc1a8ed6c228fff0a327e169c2bcc5e869ed49511",
  "publicKey": "0406cc661590d48ee972944b35ad13ff03c7876eae3fd191e8a2f77311b0a3c6613407b5005e63d7d8d76b89d5f900cde691497688bb281e07a5052ff61edebdc0"
}

 

2.設定的要執行的交易:

ethereumjs-vm/examples/run-transactions-complete/raw-tx1.json

{
  "nonce": "0x00",
  "gasPrice": "0x09184e72a000",
  "gasLimit": "0x90710",
  "data": "0x60606040526103dd806100126000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063454a2ab31461004f578063b9a2de3a14610091578063edd481bb146100d35761004d565b005b6100656004808035906020019091905050610189565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100a760048080359060200190919050506102d2565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100e960048080359060200190919050506100ff565b6040518082815260200191505060405180910390f35b600060016000818150548092919060010191905055905080508143016000600050600083815260200190815260200160002060005060000160005081905550336000600050600083815260200190815260200160002060005060030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055505b919050565b60006000600060005060008481526020019081526020016000206000509050346012600a8360010160005054011811806101c95750438160000160005054115b1561022d573373ffffffffffffffffffffffffffffffffffffffff16600034604051809050600060405180830381858888f19350505050508060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691506102cc565b8060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660008260010160005054604051809050600060405180830381858888f1935050505050338160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055503481600101600050819055503391506102cc565b50919050565b600060006000600050600084815260200190815260200160002060005090508060000160005054431015156103d6578060030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660008260010160005054604051809050600060405180830381858888f19350505050506000816001016000508190555060008160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055506000816000016000508190555060008160030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055505b5b5091905056
" }

上面這個交易是設定了一個合約

 

ethereumjs-vm/examples/run-transactions-complete/raw-tx2.js

var bidSig = '0x454a2ab3'
var time = '0000000000000000000000000000000000000000000000000000000000000045'

var rawTx2 = {
  nonce: '0x01',
  gasPrice: '0x09184e72a000',
  gasLimit: '0x20710',
  value: '0x10',
  to: '0x692a70d2e424a56d2c6c27aa97d1a86395877b3a',
  data: bidSig + time
}

module.exports 
= rawTx2

這個交易則是呼叫了合約中的某個函式

 

3.執行

ethereumjs-vm/examples/run-transactions-complete/index.js

/*
 * Example - Run code contain within transactions
 *
 *
 * Execute it with `node index.js`
 */

var Buffer = require('safe-buffer').Buffer // use for Node.js <4.5.0
var async = require('async')
var VM = require('./../../index.js')
var Account = require('ethereumjs-account')
var Transaction = require('ethereumjs-tx')
var Trie = require('merkle-patricia-tree')
var rlp = require('rlp')
var utils = require('ethereumjs-util')

// creating a trie that just resides in memory
var stateTrie = new Trie()

// create a new VM instance
var vm = new VM({state: stateTrie}) //stateTrie就是區塊上的state merkle-patricia樹,用於儲存區塊上的所有賬戶的資訊

// import the key pair
//   pre-generated (saves time)
//   used to sign transactions and generate addresses
var keyPair = require('./key-pair')

var createdAddress

// Transaction to initalize the name register, in this case
// it will register the sending address as 'null_radix'
// Notes:
//   - In a transaction, all strings as interpeted as hex
//   - A transaction has the fiels:
//     - nonce
//     - gasPrice
//     - gasLimit
//     - data
var rawTx1 = require('./raw-tx1')

// 2nd Transaction
var rawTx2 = require('./raw-tx2')

// sets up the initial state and runs the callback when complete
// 設定初始狀態,在完成時執行回撥函式
function setup (cb) {
  // the address we are sending from
  var publicKeyBuf = Buffer.from(keyPair.publicKey, 'hex')
  var address = utils.pubToAddress(publicKeyBuf, true)
  console.log(address.toString('hex'));//賬戶address為ca35b7d915458ef540ade6068dfe2f44e8fa733c
  // create a new account
  var account = new Account()//建立一個空賬戶
  // give the account some wei.
  //    Note: this needs to be a `Buffer` or a string. All
  //      strings need to be in hex.
  account.balance = '0xf00000000000000001' //設定賬戶balance餘額的值

  // store in the trie,將該賬戶儲存到字首樹中
  stateTrie.put(address, account.serialize(), cb) //將該address與賬戶狀態的資訊相關聯並存儲在了區塊鏈上的state字首樹上,區塊頭上的stateRoot就是該state字首樹的root值
}

// runs a transaction through the vm
function runTx (raw, cb) {
  // create a new transaction out of the json
  var tx = new Transaction(raw)

  // tx.from,對該交易進行簽名
  tx.sign(Buffer.from(keyPair.secretKey, 'hex'))

  console.log('----running tx-------')
  // run the tx \o/
  vm.runTx({//執行交易
    tx: tx
  }, function (err, results) {
    createdAddress = results.createdAddress //返回執行該交易生成的合約地址資訊
    // log some results
    console.log('gas used: ' + results.gasUsed.toString()) //得到使用的gas值
    console.log('returned: ' + results.vm.return.toString('hex'))
    if (createdAddress) {
      console.log('address created: ' +
          createdAddress.toString('hex'))
    }

    cb(err)
  })
}

var storageRoot // used later

// Now lets look at what we created. The transaction
// should have created a new account for the contract
// in the trie.Lets test to see if it did.
// 交易應該為在字首樹上的合約建立了一個賬戶,即合約賬戶。下面檢視是否如此
function checkResults (cb) {
  // fetch the new account from the trie.
  stateTrie.get(createdAddress, function (err, val) {//val為該合約帳號的RLP序列化的值account.serialize()
    var account = new Account(val)//所以可以用它來初始化一個賬戶,然後得到下面的資訊

    storageRoot = account.stateRoot // used later! :)
    console.log('------results------')
    console.log('nonce: ' + account.nonce.toString('hex'))
    console.log('balance in wei: ' + account.balance.toString('hex'))
    console.log('stateRoot: ' + storageRoot.toString('hex'))
    console.log('codeHash:' + account.codeHash.toString('hex'))
    console.log('-------------------')
    cb(err)
  })
}

// So if everything went right we should have "null_radix"
// stored at "0x9bdf9e2cc4dfa83de3c35da792cdf9b9e9fcfabd". To
// see this we need to print out the name register's
// storage trie.
//如果上面的部分都成功執行的話,那麼應該會有value = "null_radix"儲存在key = "0x9bdf9e2cc4dfa83de3c35da792cdf9b9e9fcfabd"中
//要看到這一點,我們需要打印出名字暫存器的儲存字首樹
function checkResults2 (cb) {
  // fetch the new account from the trie.
  stateTrie.get('0x9bdf9e2cc4dfa83de3c35da792cdf9b9e9fcfabd', function (err, val) {//並沒有得到上面所說的value = "null_radix" ???
    console.log('------results2------')
    console.log(val);
    console.log('------------')
    cb(err)
  })
}


// reads and prints the storage of a contract
// 讀取並打印合約的儲存
function readStorage (cb) {
  // we need to create a copy of the state root
  var storageTrie = stateTrie.copy() 
  console.log(storageRoot.toString('hex'));//56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421,即null的RLP編碼的Keccak-256 hash值
  console.log(storageTrie.root.toString('hex'));//a7d73ff53f4b8722d594cb0462907879e58d95e5784c05510ce5419c52331be5
  // Since we are using a copy we won't change the
  // root of `stateTrie`
  // 由於我們使用的是副本,所以不會更改stateTrie的根.但是執行的結果發現是改了的
  // 將下面的註釋掉,才能夠通過stream.on('data'...得到字首樹中的資訊
  // storageTrie.root = storageRoot //將剛剛上面生成的合約賬戶的stateRoot賦值到storageTrie.root
  console.log(storageTrie.root.toString('hex'));//storageTrie.root = storageRoot後storageTrie.root變為56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421,即null的RLP編碼的Keccak-256 hash值,這樣下面的stream.on('data'...是得不到返回值的
  var stream = storageTrie.createReadStream() //建立可讀流

  console.log('------Storage------')

  // prints all of the keys and values in the storage trie
  // 列印所有在儲存字首樹中的keys和values
  stream.on('data', function (data) {
    // remove the 'hex' if you want to see the ascii values
    console.log('key: ' + data.key.toString('hex'))
    // console.log('Value: ' + rlp.decode(data.value).toString())
    console.log('Value: ');
    rlp.decode(data.value).map(item => {//陣列內的值分別是nonce,balance,stateRoot,codehash
      console.log(item.toString('hex'));
    })
  })

  stream.on('end', cb)
}

// run everything
async.series([//按下面的順序進行執行
  setup,
  async.apply(runTx, rawTx1),//運行了兩個交易
  async.apply(runTx, rawTx2),
  checkResults,
  checkResults2,
  readStorage
])

// Now when you run you should see a complete trace.
// `onStep` provides an object that contains all the
// information on the current state of the `VM`.

返回:

userdeMBP:run-transactions-complete user$ node index.js
ca35b7d915458ef540ade6068dfe2f44e8fa733c //從key-pair.json得到的賬戶地址
----running tx-------
gas used: 312834
returned: 60606040526000357c010000000000000000000000000000000000000000000000000000000090048063454a2ab31461004f578063b9a2de3a14610091578063edd481bb146100d35761004d565b005b6100656004808035906020019091905050610189565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100a760048080359060200190919050506102d2565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100e960048080359060200190919050506100ff565b6040518082815260200191505060405180910390f35b600060016000818150548092919060010191905055905080508143016000600050600083815260200190815260200160002060005060000160005081905550336000600050600083815260200190815260200160002060005060030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055505b919050565b60006000600060005060008481526020019081526020016000206000509050346012600a8360010160005054011811806101c95750438160000160005054115b1561022d573373ffffffffffffffffffffffffffffffffffffffff16600034604051809050600060405180830381858888f19350505050508060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691506102cc565b8060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660008260010160005054604051809050600060405180830381858888f1935050505050338160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055503481600101600050819055503391506102cc565b50919050565b600060006000600050600084815260200190815260200160002060005090508060000160005054431015156103d6578060030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660008260010160005054604051809050600060405180830381858888f19350505050506000816001016000508190555060008160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055506000816000016000508190555060008160030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055505b5b5091905056
address created: 692a70d2e424a56d2c6c27aa97d1a86395877b3a //生成的合約賬戶地址
----running tx-------
gas used: 29746
returned: 0000000000000000000000000000000000000000000000000000000000000000
------results------
nonce: 
balance in wei: 
stateRoot: 56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421 //null的RLP編碼的Keccak-256 hash值
codeHash:c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 //即空字串hash值,說明為外部賬戶
-------------------
------results2------
null
------------
56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421
a7d73ff53f4b8722d594cb0462907879e58d95e5784c05510ce5419c52331be5
a7d73ff53f4b8722d594cb0462907879e58d95e5784c05510ce5419c52331be5
------Storage------
key: 0000000000000000000000000000000000000000 //空賬戶,預設存在;有時省略賬戶時則使用它
Value: 

2f8ae2f307888000
56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421
c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
key: 692a70d2e424a56d2c6c27aa97d1a86395877b3a
Value: 
01

56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421
a6db6bcd1c3757abef01cdf587304df3698a3b1e6b93667fbe87072d261ee7e1   //不為空字串hash值,說明為合約賬戶
key: ca35b7d915458ef540ade6068dfe2f44e8fa733c //從key-pair.json得到的賬戶地址
Value: 
02  //使用其運行了兩個交易,所以nonce為2
efd0751d0cf8778001
56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421
c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470