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, "") +}