github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/state/runtime/instrumentation/js/internal/tracers/prestate_tracer_legacy.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  			this.prestate[acc].storage[idx] = toHex(db.getState(addr, key));
    44  		}
    45  	},
    46  
    47  	// result is invoked when all the opcodes have been iterated over and returns
    48  	// the final result of the tracing.
    49  	result: function(ctx, db) {
    50  		if (this.prestate === null) {
    51  			this.prestate = {};
    52  			// If tx is transfer-only, the recipient account
    53  			// hasn't been populated.
    54  			this.lookupAccount(ctx.to, db);
    55  		}
    56  
    57  		// At this point, we need to deduct the 'value' from the
    58  		// outer transaction, and move it back to the origin
    59  		this.lookupAccount(ctx.from, db);
    60  
    61  		var fromBal = bigInt(this.prestate[toHex(ctx.from)].balance.slice(2), 16);
    62  		var toBal   = bigInt(this.prestate[toHex(ctx.to)].balance.slice(2), 16);
    63  
    64  		this.prestate[toHex(ctx.to)].balance   = '0x'+toBal.subtract(ctx.value).toString(16);
    65  		this.prestate[toHex(ctx.from)].balance = '0x'+fromBal.add(ctx.value).add((ctx.gasUsed + ctx.intrinsicGas) * ctx.gasPrice).toString(16);
    66  
    67  		// Decrement the caller's nonce, and remove empty create targets
    68  		this.prestate[toHex(ctx.from)].nonce--;
    69  		if (ctx.type == 'CREATE') {
    70  			// We can blibdly delete the contract prestate, as any existing state would
    71  			// have caused the transaction to be rejected as invalid in the first place.
    72  			delete this.prestate[toHex(ctx.to)];
    73  		}
    74  		// Return the assembled allocations (prestate)
    75  		return this.prestate;
    76  	},
    77  
    78  	// step is invoked for every opcode that the VM executes.
    79  	step: function(log, db) {
    80  		// Add the current account if we just started tracing
    81  		if (this.prestate === null){
    82  			this.prestate = {};
    83  			// Balance will potentially be wrong here, since this will include the value
    84  			// sent along with the message. We fix that in 'result()'.
    85  			this.lookupAccount(log.contract.getAddress(), db);
    86  		}
    87  		// Whenever new state is accessed, add it to the prestate
    88  		switch (log.op.toString()) {
    89  			case "EXTCODECOPY": case "EXTCODESIZE": case "EXTCODEHASH": case "BALANCE":
    90  				this.lookupAccount(toAddress(log.stack.peek(0).toString(16)), db);
    91  				break;
    92  			case "CREATE":
    93  				var from = log.contract.getAddress();
    94  				this.lookupAccount(toContract(from, db.getNonce(from)), db);
    95  				break;
    96  			case "CREATE2":
    97  				var from = log.contract.getAddress();
    98  				// stack: salt, size, offset, endowment
    99  				var offset = log.stack.peek(1).valueOf()
   100  				var size = log.stack.peek(2).valueOf()
   101  				var end = offset + size
   102  				this.lookupAccount(toContract2(from, log.stack.peek(3).toString(16), log.memory.slice(offset, end)), db);
   103  				break;
   104  			case "CALL": case "CALLCODE": case "DELEGATECALL": case "STATICCALL":
   105  				this.lookupAccount(toAddress(log.stack.peek(1).toString(16)), db);
   106  				break;
   107  			case 'SSTORE':case 'SLOAD':
   108  				this.lookupStorage(log.contract.getAddress(), toWord(log.stack.peek(0).toString(16)), db);
   109  				break;
   110  		}
   111  	},
   112  
   113  	// fault is invoked when the actual execution of an opcode fails.
   114  	fault: function(log, db) {}
   115  }