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