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  }