Skip to content

Multi-fragment activation: charge gas per fragment#4312

Merged
tsahee merged 26 commits intomasterfrom
NIT-4405-2
Feb 7, 2026
Merged

Multi-fragment activation: charge gas per fragment#4312
tsahee merged 26 commits intomasterfrom
NIT-4405-2

Conversation

@KolbyML
Copy link
Member

@KolbyML KolbyML commented Feb 2, 2026

fixes NIT-4405

@codecov
Copy link

codecov bot commented Feb 2, 2026

Codecov Report

❌ Patch coverage is 15.55556% with 38 lines in your changes missing coverage. Please review.
✅ Project coverage is 33.00%. Comparing base (35440a4) to head (4878677).
⚠️ Report is 7 commits behind head on master.

Additional details and impacted files
@@             Coverage Diff             @@
##           master    #4312       +/-   ##
===========================================
- Coverage   57.24%   33.00%   -24.24%     
===========================================
  Files         483      484        +1     
  Lines       57539    57702      +163     
===========================================
- Hits        32939    19047    -13892     
- Misses      19694    35330    +15636     
+ Partials     4906     3325     -1581     

@github-actions
Copy link
Contributor

github-actions bot commented Feb 3, 2026

❌ 6 Tests Failed:

Tests completed Failed Passed Skipped
4150 6 4144 0
View the top 3 failed tests by shortest run time
TestNitroNodeVersionAlerter
Stack Traces | 0.330s run time
... [CONTENT TRUNCATED: Keeping last 20 lines]
INFO [02-07|00:07:00.419] Deploying rollup creator contract
INFO [02-07|00:07:00.419] Chain head was updated                   number=25  hash=98b708..cff1f6 root=644614..b5df70 elapsed="296.019µs"
INFO [02-07|00:07:00.419] Updated payload                          id=0x03c83748913219f5 number=25  hash=fcff55..1d0a9a txs=1   withdrawals=0 gas=3,088,290 fees=3.08829e-06    root=7d7a5e..8758ac elapsed=1.288ms
INFO [02-07|00:07:00.421] Stopping work on payload                 id=0x03c83748913219f5 reason=delivery
INFO [02-07|00:07:00.422] Imported new potential chain segment     number=25  hash=fcff55..1d0a9a blocks=1  txs=1   mgas=3.088 elapsed=2.669ms     mgasps=1157.021 triediffs=90.99KiB  triedirty=0.00B
INFO [02-07|00:07:00.423] Chain head was updated                   number=25  hash=fcff55..1d0a9a root=7d7a5e..8758ac elapsed="358.014µs"
INFO [02-07|00:07:00.430] Submitted contract creation              hash=0xaa66fb85200f1172299653e50559dae4ff285c3ca26f6374e62e7e28557f0b33 from=0x57Ff0F473737a1c161bfF9efDF016F7991585088 nonce=23  contract=0xB211efa485d87C29b9486E7631D3140e16D28E08 value=0
INFO [02-07|00:07:00.431] Starting work on payload                 id=0x03dcf905c4b8c1c9
INFO [02-07|00:07:00.433] Updated payload                          id=0x03dcf905c4b8c1c9 number=31  hash=2946cf..766e0b txs=1   withdrawals=0 gas=5,314,408 fees=5.314408e-06   root=45607f..0f98bb elapsed=1.789ms
INFO [02-07|00:07:00.435] Stopping work on payload                 id=0x03dcf905c4b8c1c9 reason=delivery
INFO [02-07|00:07:00.436] Imported new potential chain segment     number=31  hash=2946cf..766e0b blocks=1  txs=1   mgas=5.314 elapsed=3.115ms     mgasps=1705.601 triediffs=115.05KiB triedirty=0.00B
INFO [02-07|00:07:00.437] Chain head was updated                   number=31  hash=2946cf..766e0b root=45607f..0f98bb elapsed="474.631µs"
INFO [02-07|00:07:00.476] Submitted contract creation              hash=0x404604726bcdb55869a04f2d52faf7593f6f20a78354489cec0e212156cf6d12 from=0x57Ff0F473737a1c161bfF9efDF016F7991585088 nonce=8   contract=0x64a43e36cC9cE3126a39d5B8034195B308940273 value=0
INFO [02-07|00:07:00.477] Starting work on payload                 id=0x038fd9cb3acc694a
INFO [02-07|00:07:00.478] Updated payload                          id=0x038fd9cb3acc694a number=9   hash=f80d07..29c43c txs=1   withdrawals=0 gas=1,934,509 fees=1.934509e-06   root=d4a5d3..ecfe5e elapsed="729.683µs"
INFO [02-07|00:07:00.479] Stopping work on payload                 id=0x038fd9cb3acc694a reason=delivery
INFO [02-07|00:07:00.480] Imported new potential chain segment     number=9   hash=f80d07..29c43c blocks=1  txs=1   mgas=1.935 elapsed=1.648ms     mgasps=1173.490 triediffs=28.31KiB  triedirty=0.00B
INFO [02-07|00:07:00.480] Chain head was updated                   number=9   hash=f80d07..29c43c root=d4a5d3..ecfe5e elapsed="294.035µs"
INFO [02-07|00:07:00.483] Submitted contract creation              hash=0xe1a5c027e0ad4d2fccccc0a89d119d04622b2ece2cb6b5c667a7f6885796957c from=0x57Ff0F473737a1c161bfF9efDF016F7991585088 nonce=9   contract=0xe1593eE43c49131b49d77047AF8283dC055f3e6E value=0
--- FAIL: TestNitroNodeVersionAlerter (0.33s)
TestRedisProduceComplex/one_producer,_all_consumers_are_active
Stack Traces | 1.130s run time
... [CONTENT TRUNCATED: Keeping last 20 lines]
�[36mDEBUG�[0m[02-06|23:52:32.968] Redis stream consuming                   �[36mconsumer_id�[0m=7f4e881e-5b18-4e66-9c1f-8d6f4d7ca047 �[36mmessage_id�[0m=1770421951905-4
�[36mDEBUG�[0m[02-06|23:52:32.968] consumer: setting result                 �[36mcid�[0m=7f4e881e-5b18-4e66-9c1f-8d6f4d7ca047 �[36mmsgIdInStream�[0m=1770421951905-4  �[36mresultKeyInRedis�[0m=result-key:stream:126a377e-4bf5-4f0c-9d20-226bb4fe756e.1770421951905-4
�[36mDEBUG�[0m[02-06|23:52:32.968] Redis stream consuming                   �[36mconsumer_id�[0m=1a787152-1a1e-4398-9145-e05d44638ebd �[36mmessage_id�[0m=1770421951905-5
�[36mDEBUG�[0m[02-06|23:52:32.968] consumer: xack                           �[36mcid�[0m=7f4e881e-5b18-4e66-9c1f-8d6f4d7ca047 �[36mmessageId�[0m=1770421951905-4
�[36mDEBUG�[0m[02-06|23:52:32.968] consumer: setting result                 �[36mcid�[0m=1a787152-1a1e-4398-9145-e05d44638ebd �[36mmsgIdInStream�[0m=1770421951905-5  �[36mresultKeyInRedis�[0m=result-key:stream:126a377e-4bf5-4f0c-9d20-226bb4fe756e.1770421951905-5
�[36mDEBUG�[0m[02-06|23:52:32.968] consumer: xack                           �[36mcid�[0m=453f6dd4-36c3-4e27-872a-ae0d67db0f66 �[36mmessageId�[0m=1770421951905-2
�[36mDEBUG�[0m[02-06|23:52:32.968] consumer: xdel                           �[36mcid�[0m=490f3948-0444-4035-b864-57512662d4a2 �[36mmessageId�[0m=1770421951905-3
�[36mDEBUG�[0m[02-06|23:52:32.968] consumer: xdel                           �[36mcid�[0m=7f4e881e-5b18-4e66-9c1f-8d6f4d7ca047 �[36mmessageId�[0m=1770421951905-4
�[36mDEBUG�[0m[02-06|23:52:32.969] consumer: xdel                           �[36mcid�[0m=453f6dd4-36c3-4e27-872a-ae0d67db0f66 �[36mmessageId�[0m=1770421951905-2
�[36mDEBUG�[0m[02-06|23:52:32.968] Redis stream consuming                   �[36mconsumer_id�[0m=d2f7be42-2164-4ce7-8073-2133bb427fea �[36mmessage_id�[0m=1770421951905-6
�[36mDEBUG�[0m[02-06|23:52:32.969] consumer: setting result                 �[36mcid�[0m=d2f7be42-2164-4ce7-8073-2133bb427fea �[36mmsgIdInStream�[0m=1770421951905-6  �[36mresultKeyInRedis�[0m=result-key:stream:126a377e-4bf5-4f0c-9d20-226bb4fe756e.1770421951905-6
�[36mDEBUG�[0m[02-06|23:52:32.969] consumer: xack                           �[36mcid�[0m=1a787152-1a1e-4398-9145-e05d44638ebd �[36mmessageId�[0m=1770421951905-5
�[36mDEBUG�[0m[02-06|23:52:32.969] consumer: xack                           �[36mcid�[0m=d2f7be42-2164-4ce7-8073-2133bb427fea �[36mmessageId�[0m=1770421951905-6
�[36mDEBUG�[0m[02-06|23:52:32.969] consumer: xdel                           �[36mcid�[0m=d2f7be42-2164-4ce7-8073-2133bb427fea �[36mmessageId�[0m=1770421951905-6
�[36mDEBUG�[0m[02-06|23:52:32.969] trimming                                 �[36mxTrimMinID�[0m=1770421951905-5 �[36mtrimmed�[0m=0 �[36mtrim-err�[0m=<nil>
�[36mDEBUG�[0m[02-06|23:52:32.970] consumer: xdel                           �[36mcid�[0m=1a787152-1a1e-4398-9145-e05d44638ebd �[36mmessageId�[0m=1770421951905-5
�[36mDEBUG�[0m[02-06|23:52:32.998] checkResponses                           �[36mresponded�[0m=80 �[36merrored�[0m=0 �[36mchecked�[0m=100
�[36mDEBUG�[0m[02-06|23:52:33.005] redis producer: check responses starting
�[36mDEBUG�[0m[02-06|23:52:33.014] checkResponses                           �[36mresponded�[0m=20 �[36merrored�[0m=0 �[36mchecked�[0m=20
--- FAIL: TestRedisProduceComplex/one_producer,_all_consumers_are_active (1.13s)
TestBroadcastClientConfirmedMessage
Stack Traces | 5.020s run time
... [CONTENT TRUNCATED: Keeping last 20 lines]
ERROR[02-06|23:53:05.604] Server connection timed out without receiving data url=ws://127.0.0.1:40461/ err="read tcp4 127.0.0.1:37942->127.0.0.1:40461: i/o timeout"
ERROR[02-06|23:53:05.604] Server connection timed out without receiving data url=ws://127.0.0.1:42525/ err="read tcp4 127.0.0.1:38086->127.0.0.1:42525: i/o timeout"
INFO [02-06|23:53:05.604] First reconnection attempt, skipping backoff url=ws://127.0.0.1:40461/
INFO [02-06|23:53:05.604] First reconnection attempt, skipping backoff url=ws://127.0.0.1:42525/
INFO [02-06|23:53:05.604] connecting to arbitrum inbox message broadcaster url=ws://127.0.0.1:40461/
INFO [02-06|23:53:05.604] connecting to arbitrum inbox message broadcaster url=ws://127.0.0.1:42525/
INFO [02-06|23:53:05.605] Feed connected                           feedServerVersion=2 chainId=8742 requestedSeqNum=0
INFO [02-06|23:53:05.605] Feed connected                           feedServerVersion=2 chainId=8742 requestedSeqNum=1
ERROR[02-06|23:53:05.805] Server connection timed out without receiving data url=ws://127.0.0.1:40461/ err="read tcp4 127.0.0.1:37948->127.0.0.1:40461: i/o timeout"
INFO [02-06|23:53:05.805] First reconnection attempt, skipping backoff url=ws://127.0.0.1:40461/
INFO [02-06|23:53:05.805] connecting to arbitrum inbox message broadcaster url=ws://127.0.0.1:40461/
ERROR[02-06|23:53:05.806] Server connection timed out without receiving data url=ws://127.0.0.1:42525/ err="read tcp4 127.0.0.1:38102->127.0.0.1:42525: i/o timeout"
INFO [02-06|23:53:05.806] First reconnection attempt, skipping backoff url=ws://127.0.0.1:42525/
INFO [02-06|23:53:05.806] connecting to arbitrum inbox message broadcaster url=ws://127.0.0.1:42525/
INFO [02-06|23:53:05.807] Feed connected                           feedServerVersion=2 chainId=8742 requestedSeqNum=1
INFO [02-06|23:53:05.807] Feed connected                           feedServerVersion=2 chainId=8742 requestedSeqNum=0
ERROR[02-06|23:53:06.007] Server connection timed out without receiving data url=ws://127.0.0.1:40461/ err="read tcp4 127.0.0.1:37962->127.0.0.1:40461: i/o timeout"
INFO [02-06|23:53:06.007] First reconnection attempt, skipping backoff url=ws://127.0.0.1:40461/
    broadcastclient_test.go:359: Client did not receive confirm message
--- FAIL: TestBroadcastClientConfirmedMessage (5.02s)

📣 Thoughts on this report? Let Codecov know! | Powered by Codecov

}

wasm, err := getWasmFromContractCode(statedb, code, progParams, false)
wasm, err := getWasmFromContractCode(statedb, code, progParams, false, nil)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering - maybe we should pass p.programs.Burner() anyway here; otherwise, i'd add a comment why nil is ok

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok I will add a comment

if !statedb.AddressInAccessList(addr) {
statedb.AddAddressToAccessList(addr)
// charge cold account access gas
if cost, overflow = cost.SafeIncrement(multigas.ResourceKindStorageAccess, gethParams.ColdAccountAccessCostEIP2929-gethParams.WarmStorageReadCostEIP2929); overflow {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we subtract warm storage here instead of just charge for cold read?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah a 100gas difference won't make a difference, so I will remove the warm cost Tsahi, just told me to model the code off EXTCODECOPY costs

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// gasExtCodeCopyEIP2929 implements extcodecopy according to EIP-2929
// EIP spec:
// > If the target is not in accessed_addresses,
// > charge COLD_ACCOUNT_ACCESS_COST gas, and add the address to accessed_addresses.
// > Otherwise, charge WARM_STORAGE_READ_COST gas.
func gasExtCodeCopyEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (multigas.MultiGas, error) {
	// memory expansion first (dynamic part of pre-2929 implementation)
	multiGas, err := gasExtCodeCopy(evm, contract, stack, mem, memorySize)
	if err != nil {
		return multigas.ZeroGas(), err
	}
	addr := common.Address(stack.peek().Bytes20())
	// Check slot presence in the access list
	if !evm.StateDB.AddressInAccessList(addr) {
		evm.StateDB.AddAddressToAccessList(addr)
		var overflow bool
		// We charge (cold-warm), since 'warm' is already charged as constantGas
		// Charge cold → warm delta as storage-access gas.
		// See rationale in: https://github.com/OffchainLabs/nitro/blob/master/docs/decisions/0002-multi-dimensional-gas-metering.md
		if multiGas, overflow = multiGas.SafeIncrement(multigas.ResourceKindStorageAccess, params.ColdAccountAccessCostEIP2929-params.WarmStorageReadCostEIP2929); overflow {
			return multigas.ZeroGas(), ErrGasUintOverflow
		}
		return multiGas, nil
	}
	return multiGas, nil
}

For reference EIP2929 specifies it this way, but honestly the way Tsahi wrote to me, it matters more that the feel is the same, rather then it being exactly the same.

if cost, overflow = cost.SafeIncrement(multigas.ResourceKindComputation, evmMemoryCost(codeSize)); overflow {
return vm.ErrGasUintOverflow
}
for kind := multigas.ResourceKindUnknown; kind < multigas.NumResourceKind; kind++ {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a bit vulnerable to changing the order of resource kinds, isn't it? I wonder if there's any safe way of iterating over every kind

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah a loop seems overkill, I ended up just doing 2 if cases for the resources we use

if codeSize > 0x1FFFFFFFE0 {
return 0
}
words := (codeSize + 31) / 32
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use this helper for word count

@KolbyML
Copy link
Member Author

KolbyML commented Feb 3, 2026

@pmikolajczyk41 @bragaigor @MishkaRogachev ok I believe I resolved your guys concerns ready for another look

@KolbyML KolbyML requested a review from tsahee February 4, 2026 20:58
@KolbyML KolbyML assigned tsahee and unassigned KolbyML Feb 4, 2026
return vm.ErrGasUintOverflow
}
// charge memory gas
if cost, overflow = cost.SafeIncrement(multigas.ResourceKindComputation, evmMemoryCost(codeSize)); overflow {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should remove this componenet.
Evm memory cost has a weird structure that should account only for added cost of new code, and we generally don't charge it in stylus. Stylus has a different way of charging for memory and I think here we could ignore both.
Not entirely sure.

@tsahee tsahee assigned KolbyML and unassigned tsahee Feb 5, 2026
@KolbyML KolbyML requested a review from tsahee February 5, 2026 12:10
@KolbyML KolbyML assigned tsahee and unassigned KolbyML Feb 5, 2026
@KolbyML
Copy link
Member Author

KolbyML commented Feb 5, 2026

@tsahee ready for another look. I believe I resolved your concerns. CI is a bit flakey, which is annoying, but I believe it is unrelated to this PR? I checked the logs and all the flakey tests don't seem to be related

Copy link
Contributor

@tsahee tsahee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@tsahee tsahee enabled auto-merge February 6, 2026 23:48
@tsahee tsahee added this pull request to the merge queue Feb 6, 2026
Merged via the queue into master with commit 890f0e2 Feb 7, 2026
26 checks passed
@tsahee tsahee deleted the NIT-4405-2 branch February 7, 2026 01:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants