github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/eth/tracers/internal/tracers/prestate_tracer.js (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // prestateTracer outputs sufficient information to create a local execution of 18 // the transaction from a custom assembled genesis block. 19 { 20 // prestate is the genesis that we're building. 21 prestate: null, 22 23 // lookupAccount injects the specified account into the prestate object. 24 lookupAccount: function(addr, db){ 25 var acc = toHex(addr); 26 if (this.prestate[acc] === undefined) { 27 this.prestate[acc] = { 28 balance: '0x' + db.getBalance(addr).toString(16), 29 nonce: db.getNonce(addr), 30 code: toHex(db.getCode(addr)), 31 storage: {} 32 }; 33 } 34 }, 35 36 // lookupStorage injects the specified storage entry of the given account into 37 // the prestate object. 38 lookupStorage: function(addr, key, db){ 39 var acc = toHex(addr); 40 var idx = toHex(key); 41 42 if (this.prestate[acc].storage[idx] === undefined) { 43 var val = toHex(db.getState(addr, key)); 44 if (val != "0x0000000000000000000000000000000000000000000000000000000000000000") { 45 this.prestate[acc].storage[idx] = toHex(db.getState(addr, key)); 46 } 47 } 48 }, 49 50 // result is invoked when all the opcodes have been iterated over and returns 51 // the final result of the tracing. 52 result: function(ctx, db) { 53 // At this point, we need to deduct the 'value' from the 54 // outer transaction, and move it back to the origin 55 this.lookupAccount(ctx.from, db); 56 57 var fromBal = bigInt(this.prestate[toHex(ctx.from)].balance.slice(2), 16); 58 var toBal = bigInt(this.prestate[toHex(ctx.to)].balance.slice(2), 16); 59 60 this.prestate[toHex(ctx.to)].balance = '0x'+toBal.subtract(ctx.value).toString(16); 61 this.prestate[toHex(ctx.from)].balance = '0x'+fromBal.add(ctx.value).toString(16); 62 63 // Decrement the caller's nonce, and remove empty create targets 64 this.prestate[toHex(ctx.from)].nonce--; 65 if (ctx.type == 'CREATE') { 66 // We can blibdly delete the contract prestate, as any existing state would 67 // have caused the transaction to be rejected as invalid in the first place. 68 delete this.prestate[toHex(ctx.to)]; 69 } 70 // Return the assembled allocations (prestate) 71 return this.prestate; 72 }, 73 74 // step is invoked for every opcode that the VM executes. 75 step: function(log, db) { 76 // Add the current account if we just started tracing 77 if (this.prestate === null){ 78 this.prestate = {}; 79 // Balance will potentially be wrong here, since this will include the value 80 // sent along with the message. We fix that in 'result()'. 81 this.lookupAccount(log.contract.getAddress(), db); 82 } 83 // Whenever new state is accessed, add it to the prestate 84 switch (log.op.toString()) { 85 case "EXTCODECOPY": case "EXTCODESIZE": case "BALANCE": 86 this.lookupAccount(toAddress(log.stack.peek(0).toString(16)), db); 87 break; 88 case "CREATE": 89 var from = log.contract.getAddress(); 90 this.lookupAccount(toContract(from, db.getNonce(from)), db); 91 break; 92 case "CALL": case "CALLCODE": case "DELEGATECALL": case "STATICCALL": 93 this.lookupAccount(toAddress(log.stack.peek(1).toString(16)), db); 94 break; 95 case 'SSTORE':case 'SLOAD': 96 this.lookupStorage(log.contract.getAddress(), toWord(log.stack.peek(0).toString(16)), db); 97 break; 98 } 99 }, 100 101 // fault is invoked when the actual execution of an opcode fails. 102 fault: function(log, db) {} 103 }