Skip to content

Commit

Permalink
Merge pull request #389 from OffchainLabs/tx-calldata-cache-compression
Browse files Browse the repository at this point in the history
Include tx compression level in calldata units cache
  • Loading branch information
PlasmaPower authored Dec 21, 2024
2 parents 6ec497d + 0d33cae commit d99138f
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 2 deletions.
43 changes: 41 additions & 2 deletions core/types/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,54 @@ type Transaction struct {
inner TxData // Consensus contents of a transaction
time time.Time // Time first seen locally (spam avoidance)

// Arbitrum cache: must be atomically accessed
CalldataUnits uint64
// Arbitrum cache of the calldata units at a brotli compression level.
// The top 8 bits are the brotli compression level last used to compute this,
// and the remaining 56 bits are the calldata units at that compression level.
calldataUnitsForBrotliCompressionLevel atomic.Uint64

// caches
hash atomic.Pointer[common.Hash]
size atomic.Uint64
from atomic.Pointer[sigCache]
}

// GetRawCachedCalldataUnits returns the cached brotli compression level and corresponding calldata units,
// or (0, 0) if the cache is empty.
func (tx *Transaction) GetRawCachedCalldataUnits() (uint64, uint64) {
repr := tx.calldataUnitsForBrotliCompressionLevel.Load()
cachedCompressionLevel := repr >> 56
calldataUnits := repr & ((1 << 56) - 1)
return cachedCompressionLevel, calldataUnits
}

// GetCachedCalldataUnits returns the cached calldata units for a given brotli compression level,
// returning nil if no cache is present or the cache is for a different compression level.
func (tx *Transaction) GetCachedCalldataUnits(requestedCompressionLevel uint64) *uint64 {
cachedCompressionLevel, cachedUnits := tx.GetRawCachedCalldataUnits()
if cachedUnits == 0 {
// empty cache
return nil
}
if cachedCompressionLevel != requestedCompressionLevel {
// wrong compression level
return nil
}
return &cachedUnits
}

// SetCachedCalldataUnits sets the cached brotli compression level and corresponding calldata units,
// or clears the cache if the values are too large to fit (at least 2**8 and 2**56 respectively).
// Note that a zero calldataUnits is also treated as an empty cache.
func (tx *Transaction) SetCachedCalldataUnits(compressionLevel uint64, calldataUnits uint64) {
var repr uint64
// Ensure the compressionLevel and calldataUnits will fit.
// Otherwise, just clear the cache.
if compressionLevel < 1<<8 && calldataUnits < 1<<56 {
repr = compressionLevel<<56 | calldataUnits
}
tx.calldataUnitsForBrotliCompressionLevel.Store(repr)
}

// NewTx creates a new transaction.
func NewTx(inner TxData) *Transaction {
tx := new(Transaction)
Expand Down
49 changes: 49 additions & 0 deletions core/types/transaction_arbitrum_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright 2014 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package types

import "testing"

func TestTxCalldataUnitsCache(t *testing.T) {
tx := &Transaction{}
units := tx.GetCachedCalldataUnits(0)
if units != nil {
t.Errorf("unexpected initial cache present %v for compression 0", units)
}
units = tx.GetCachedCalldataUnits(1)
if units != nil {
t.Errorf("unexpected initial cache present %v for compression 1", units)
}
tx.SetCachedCalldataUnits(200, 1000)
units = tx.GetCachedCalldataUnits(100)
if units != nil {
t.Errorf("unexpected cached units %v present for incorrect compression 100", units)
}
units = tx.GetCachedCalldataUnits(0)
if units != nil {
t.Errorf("unexpected cached units %v present for incorrect compression 0", units)
}
units = tx.GetCachedCalldataUnits(200)
if units == nil || *units != 1000 {
t.Errorf("unexpected cached units %v for correct compression 200", units)
}
tx.SetCachedCalldataUnits(1, 1<<60)
units = tx.GetCachedCalldataUnits(1)
if units != nil {
t.Errorf("unexpected cache value %v present after reset", units)
}
}

0 comments on commit d99138f

Please sign in to comment.