diff --git a/common/types_arbitrum.go b/common/types_arbitrum.go
new file mode 100644
index 000000000000..c63ca761588c
--- /dev/null
+++ b/common/types_arbitrum.go
@@ -0,0 +1,64 @@
+// Copyright 2015 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 .
+
+package common
+
+type Signed interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64
+}
+
+type Unsigned interface {
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
+}
+
+type Integer interface {
+ Signed | Unsigned
+}
+
+type Float interface {
+ ~float32 | ~float64
+}
+
+// Ordered is anything that implements comparison operators such as `<` and `>`.
+// Unfortunately, that doesn't include big ints.
+type Ordered interface {
+ Integer | Float
+}
+
+// MinInt the minimum of two ints
+func MinInt[T Ordered](value, ceiling T) T {
+ if value > ceiling {
+ return ceiling
+ }
+ return value
+}
+
+// MaxInt the maximum of two ints
+func MaxInt[T Ordered](value, floor T) T {
+ if value < floor {
+ return floor
+ }
+ return value
+}
+
+// SaturatingUAdd add two integers without overflow
+func SaturatingUAdd[T Unsigned](a, b T) T {
+ sum := a + b
+ if sum < a || sum < b {
+ sum = ^T(0)
+ }
+ return sum
+}
diff --git a/core/state/statedb.go b/core/state/statedb.go
index f9b6f882c3bd..6b96abed0eb4 100644
--- a/core/state/statedb.go
+++ b/core/state/statedb.go
@@ -65,6 +65,8 @@ type StateDB struct {
// Arbitrum
unexpectedBalanceDelta *big.Int // total balance change across all accounts
userWasms UserWasms // user wasms encountered during execution
+ openWasmPages uint16 // number of pages currently open
+ everWasmPages uint16 // largest number of pages ever allocated during this tx's execution
deterministic bool // whether the order in which deletes are committed should be deterministic
db Database
@@ -144,6 +146,9 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
}
sdb := &StateDB{
unexpectedBalanceDelta: new(big.Int),
+ userWasms: make(UserWasms),
+ openWasmPages: 0,
+ everWasmPages: 0,
db: db,
trie: tr,
@@ -723,6 +728,9 @@ func (s *StateDB) Copy() *StateDB {
// Copy all the basic fields, initialize the memory ones
state := &StateDB{
unexpectedBalanceDelta: new(big.Int).Set(s.unexpectedBalanceDelta),
+ userWasms: make(UserWasms, len(s.userWasms)),
+ openWasmPages: s.openWasmPages,
+ everWasmPages: s.everWasmPages,
db: s.db,
trie: s.db.CopyTrie(s.trie),
@@ -794,6 +802,11 @@ func (s *StateDB) Copy() *StateDB {
state.accessList = s.accessList.Copy()
state.transientStorage = s.transientStorage.Copy()
+ // Arbitrum: copy wasm calls
+ for call, wasm := range s.userWasms {
+ state.userWasms[call] = wasm
+ }
+
// If there's a prefetcher running, make an inactive copy of it that can
// only access data but does not actively preload (since the user will not
// know that they need to explicitly terminate an active copy).
@@ -987,6 +1000,10 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
func (s *StateDB) SetTxContext(thash common.Hash, ti int) {
s.thash = thash
s.txIndex = ti
+
+ // Arbitrum: clear memory charging state for new tx
+ s.openWasmPages = 0
+ s.everWasmPages = 0
}
func (s *StateDB) clearJournalAndRefund() {
diff --git a/core/state/statedb_arbitrum.go b/core/state/statedb_arbitrum.go
index 6dcd88504f94..fd9e53c581b8 100644
--- a/core/state/statedb_arbitrum.go
+++ b/core/state/statedb_arbitrum.go
@@ -78,6 +78,30 @@ func (s *StateDB) SetCompiledWasmCode(addr common.Address, code []byte, version
}
}
+func (s *StateDB) GetStylusPages() (uint16, uint16) {
+ return s.openWasmPages, s.everWasmPages
+}
+
+func (s *StateDB) GetStylusPagesOpen() uint16 {
+ return s.openWasmPages
+}
+
+func (s *StateDB) SetStylusPagesOpen(open uint16) {
+ s.openWasmPages = open
+}
+
+// Tracks that `new` additional pages have been opened, returning the previous counts
+func (s *StateDB) AddStylusPages(new uint16) (uint16, uint16) {
+ open, ever := s.GetStylusPages()
+ s.openWasmPages = common.SaturatingUAdd(open, new)
+ s.everWasmPages = common.MaxInt(ever, s.openWasmPages)
+ return open, ever
+}
+
+func (s *StateDB) AddStylusPagesEver(new uint16) {
+ s.everWasmPages = common.SaturatingUAdd(s.everWasmPages, new)
+}
+
func NewDeterministic(root common.Hash, db Database) (*StateDB, error) {
sdb, err := New(root, db, nil)
if err != nil {
diff --git a/core/types/receipt_arbitrum.go b/core/types/receipt_arbitrum.go
new file mode 100644
index 000000000000..9c82eac10824
--- /dev/null
+++ b/core/types/receipt_arbitrum.go
@@ -0,0 +1,21 @@
+// 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 .
+
+package types
+
+func (r *Receipt) GasUsedForL2() uint64 {
+ return r.GasUsed - r.GasUsedForL1
+}
diff --git a/core/vm/contract_arbitrum.go b/core/vm/contract_arbitrum.go
new file mode 100644
index 000000000000..96e60fea114b
--- /dev/null
+++ b/core/vm/contract_arbitrum.go
@@ -0,0 +1,26 @@
+// Copyright 2015 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 .
+
+package vm
+
+func (c *Contract) BurnGas(amount uint64) error {
+ if c.Gas < amount {
+ c.Gas = 0
+ return ErrOutOfGas
+ }
+ c.Gas -= amount
+ return nil
+}
diff --git a/core/vm/interface.go b/core/vm/interface.go
index ef871ca970b7..0d233f8d3b38 100644
--- a/core/vm/interface.go
+++ b/core/vm/interface.go
@@ -31,6 +31,13 @@ type StateDB interface {
GetCompiledWasmCode(addr common.Address, version uint32) []byte
SetCompiledWasmCode(addr common.Address, code []byte, version uint32)
+ // Arbitrum: track stylus's memory footprint
+ GetStylusPages() (uint16, uint16)
+ GetStylusPagesOpen() uint16
+ SetStylusPagesOpen(open uint16)
+ AddStylusPages(new uint16) (uint16, uint16)
+ AddStylusPagesEver(new uint16)
+
NoncanonicalProgramHash(common.Address, uint32) common.Hash
Deterministic() bool
Database() state.Database
diff --git a/log/format.go b/log/format.go
index d7e2f820afe7..ef7443454826 100644
--- a/log/format.go
+++ b/log/format.go
@@ -472,6 +472,9 @@ func formatLogfmtBigInt(n *big.Int) string {
// escapeString checks if the provided string needs escaping/quoting, and
// calls strconv.Quote if needed
func escapeString(s string) string {
+ // Arbitrum: remove console colors introduced in Arbitrator
+ s = Uncolor(s)
+
needsQuoting := false
for _, r := range s {
// We quote everything below " (0x22) and above~ (0x7E), plus equal-sign
@@ -490,6 +493,9 @@ func escapeString(s string) string {
// to escapeString. The difference is that this method is more lenient: it allows
// for spaces and linebreaks to occur without needing quoting.
func escapeMessage(s string) string {
+ // Arbitrum: remove console colors introduced in Arbitrator
+ s = Uncolor(s)
+
needsQuoting := false
for _, r := range s {
// Allow CR/LF/TAB. This is to make multi-line messages work.
diff --git a/log/logger_arbitrum.go b/log/logger_arbitrum.go
new file mode 100644
index 000000000000..9fcdaf6b6fec
--- /dev/null
+++ b/log/logger_arbitrum.go
@@ -0,0 +1,9 @@
+package log
+
+import "regexp"
+
+var uncolor = regexp.MustCompile("\x1b\\[([0-9]+;)*[0-9]+m")
+
+func Uncolor(text string) string {
+ return uncolor.ReplaceAllString(text, "")
+}