Skip to content

feat: Add Gas dimension tracers #457

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 35 commits into from

Conversation

relyt29
Copy link
Collaborator

@relyt29 relyt29 commented May 9, 2025

This PR introduces two native and two live tracers, txGasDimensionLogger and txGasDimensionByOpcode, that on a per-opcode basis track the consumption of gas across multiple dimensions:

  1. Computation - opcodes that operate on the stack, memory, simple math
  2. State access - reading and writing to existing state, storage slots, accounts tree etc
  3. State growth - expanding the amount of state in existence, either by setting a value in a smart contract from 0->Non-Zero or by creating a new account to have to track in the accounts tree
  4. History growth - logging log events which are stored in the history (as opposed to the state)

txGasDimensionLogger

The logger is based off the default geth opcode struct logger. It will return each opcode, and its associated gas dimensional consumption, e.g.

{                                                                                               
  "jsonrpc": "2.0",                                                                             
  "id": 1,                                                                                      
  "result": {                                                                                   
    "gasUsed": 994729,                                                                          
    "gasUsedForL1": 968000,                                                                     
    "gasUsedForL2": 26729,                                                                      
    "intrinsicGas": 21064,                                                                      
    "adjustedRefund": 0,                                                                        
    "failed": false,                                                                            
    "txHash": "0x23eb17459bc5cbdea76949afa741a4cdcec06183d26de389c6d3b168be3800be",             
    "blockTimestamp": 1746807439,                                                               
    "blockNumber": 17,                                                                          
    "dim": [                                                                                    
      {                                                                                         
        "pc": 0,                                                                                
        "op": "PUSH1",                                                                          
        "depth": 1,                                                                             
        "cost": 3,                                                                              
        "cpu": 3                                                                                
      },    
      {                                                                                         
        "pc": 903,                                                                              
        "op": "SSTORE",                                                                         
        "depth": 1,                                                                             
        "cost": 100,                                                                            
        "rw": 100,                                                                              
        "refund": 4800                                                                          
      },  

txGasDimensionByOpcode

The transaction gas dimensions by opcode tracer returns the total sum of gas consumed by each different opcode, split out by dimension, e.g:

                                                                                                                                                                                             
  "jsonrpc": "2.0",                                                                                                                                                                           
  "id": 1,                                                                                                                                                                                    
  "result": {                                                                                                                                                                                 
    "gasUsed": 1003063,                                                                                                                                                                       
    "gasUsedForL1": 968000,                                                                                                                                                                   
    "gasUsedForL2": 35063,                                                                                                                                                                    
    "intrinsicGas": 21064,                                                                                                                                                                    
    "adjustedRefund": 8765,                                                                                                                                                                   
    "failed": false,                                                                                                                                                                          
    "txHash": "0xe6d0c5c6e330b7d993855afd610d01fc1d8f8257a70b83684a2d24a9418afc5a",                                                                                                           
    "blockTimestamp": 1746646719,                                                                                                                                                             
    "blockNumber": 18,                                                                                                                                                                        
    "dimensions": {                                                                                                                                                                           
      "ADD": {                                                                                                                                                                                
        "gas1d": 6,                                                                                                                                                                              
        "cpu": 6             
      },
      "SLOAD": {                                                                                                                                                                                 
        "gas1d": 2200,                                                                                                                                                                              
        "cpu": 200,                                                                                                                                                                              
        "rw": 2000                                                                                                                                                                               
      },                                                                                                                                                                                         
      "SSTORE": {                                                                                                                                                                                
        "gas1d": 20100,                                                                                                                                                                             
        "cpu": 0,                                                                                                                                                                                
        "rw": 100,                                                                                                                                                                               
        "growth": 20000,                                                                                                                                                                             
        "refund": 19900                                                                                                                                                                              
      },   

Tracer Invocation

The tracers need to have a parameter of a transaction hash to operate upon. If you have that and your node either is an archive node with the state or the transaction hash you're tracing is in the last 128 blocks then you can run the tracer like so:

export TX_HASH_TO_LOOK_AT="0x348f7124e88620273caee233f25472009c5ba92a2d6743ae161045da8c533f6c";
 
curl "http://127.0.0.1:8547" \
-X POST \
-H "Content-Type: application/json" \
--data '{  
    "method":"debug_traceTransaction",
    "params":["'"$TX_HASH_TO_LOOK_AT"'", {"tracer": "txGasDimensionByOpcode"}],
    "id":1,
    "jsonrpc":"2.0"
}' | jq > tx.byOpcode.json;   
                                     
curl "http://127.0.0.1:8547" \
-X POST \
-H "Content-Type: application/json" \
--data '{
    "method":"debug_traceTransaction",
    "params":["'"$TX_HASH_TO_LOOK_AT"'", {"tracer":"txGasDimensionLogger"}],
    "id":1,
    "jsonrpc":"2.0"
}' | jq > tx.Logger.json;

Live Tracers

The live tracers are identical use the native tracers under the hood. The difference with the live tracers is that they dump the output of the tracer to disk in protobuf format to then in in order to save on storage space relative to json. Python or whatever can then generate serialization code from the .proto file to ingest the protobuf output.

Live Tracer Invocation

The live tracers can be run like so:

./target/bin/nitro --dev \
    --execution.vmtrace.tracer-name "txGasDimensionByOpcode" \
    --execution.vmtrace.json-config '{"path":"gas-dimension-logs","chainConfig":{"chainId":42161,"homesteadBlock":0,"daoForkBlock":null,"daoForkSupport":true,"eip150Block":0,"eip150Hash":"0x0000000000000000000000000000000000000000000000000000000000000000","eip155Block":0,"eip158Block":0,"byzantiumBlock":0,"constantinopleBlock":0,"petersburgBlock":0,"istanbulBlock":0,"muirGlacierBlock":0,"berlinBlock":0,"londonBlock":0,"clique":{"period":0,"epoch":0},"arbitrum":{"EnableArbOS":true,"AllowDebugPrecompiles":false,"DataAvailabilityCommittee":false,"InitialArbOSVersion":6,"InitialChainOwner":"0xd345e41ae2cb00311956aa7109fc801ae8c81a52","GenesisBlockNum":0}}}'

For example, this will create a directory called gas-dimension-logs in the root of the repo that will have each block as a subfolder, and a protobuf dumped file for the gas dimensions by transaction. The tracer expects a chain configuration because I was unable to get the chain configuration in the tracer creation context without having a bigger diff. So it expects it to be passed in by json - you can use the nitro repository's chain info as a reference for a chain configuration if you don't have one.

@relyt29 relyt29 requested review from eljobe, joshuacolvin0 and tsahee May 9, 2025 17:37
@relyt29 relyt29 self-assigned this May 9, 2025
Copy link

cla-bot bot commented May 9, 2025

We require contributors to sign our Contributor License Agreement. In order for us to review and merge your code, please sign the linked documents below to get yourself added. https://na3.docusign.net/Member/PowerFormSigning.aspx?PowerFormId=b15c81cc-b5ea-42a6-9107-3992526f2898&env=na3&acct=6e152afc-6284-44af-a4c1-d8ef291db402&v=2

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

relyt29 added 24 commits May 9, 2025 13:42
Support live tracing and by RPC, support all pure-CPU opcodes.
Support the simple state access opcodes.

Rest still TODO
1. EXTCODECOPY with no memory expansion, and warm storage access
2. EXTCODECOPY with memory expansion and warm storage access
3. EXTCODECOPY with memory expansion and cold storage access
4. EXTCODECOPY with no memory expansion and cold storage access
Cold access list SLOAD
Warm access list SLOAD
all of the LOG opcodes with both indexed and unindexed data
Selfdestruct to:
* cold, empty account target, sender has balance
* warm, empty account target, sender has balance
* warm, code/value at target, sender has balance
* warm, code/value at target, no money to send
* cold, code/value at target, sender has balance
Tested:
* calling to a contract that is cold but has code
* calling to a contract that is cold and has no code
Tested:
* calling to a contract that is warm and has code
* calling to a contract that is cold and has code
* calling to a contract that is warm and has no code
* calling to a contract that is cold and has no code
Tested by hand:
* Delegatecall to warm address, to a contract with code
* Delegatecall to cold address, to a contract with code
* Delegatecall to cold address, to a contract with no code
* Delegatecall to warm address, to a contract with no code
Tested by Hand:
* warm access list+ target has code + zero value
* warm access list+ target has code + positive value
* warm access list+ target has no code + zero value
* warm access list+ target has no code + positive value
* cold access list+ target has code + zero value
* cold access list+ target has code + positive value
* cold access list+ target has no code + zero value
* cold access list+ target has no code + positive value
Tested By hand:
* CREATE
* CREATE2
* CREATE sending value
* CREATE2 sending value

sending value does not affect gas dimensions but I tested it anyways
Tested by hand in variations:
* writing to a new slot
* writing to the same slot twice with the same value
* writing to the same slot twice with a different value
* writing to a slot that was uninitialized and setting it back to zero
* writing to a slot that was cold but set to non-zero and setting it to
  nonzero
@relyt29 relyt29 force-pushed the gas-dimension-tracing branch from 36931d0 to 9be9106 Compare May 9, 2025 17:42
Copy link

cla-bot bot commented May 9, 2025

We require contributors to sign our Contributor License Agreement. In order for us to review and merge your code, please sign the linked documents below to get yourself added. https://na3.docusign.net/Member/PowerFormSigning.aspx?PowerFormId=b15c81cc-b5ea-42a6-9107-3992526f2898&env=na3&acct=6e152afc-6284-44af-a4c1-d8ef291db402&v=2

Copy link

cla-bot bot commented May 9, 2025

We require contributors to sign our Contributor License Agreement. In order for us to review and merge your code, please sign the linked documents below to get yourself added. https://na3.docusign.net/Member/PowerFormSigning.aspx?PowerFormId=b15c81cc-b5ea-42a6-9107-3992526f2898&env=na3&acct=6e152afc-6284-44af-a4c1-d8ef291db402&v=2

@relyt29
Copy link
Collaborator Author

relyt29 commented May 13, 2025

Closing in favor of #459

@relyt29 relyt29 closed this May 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants