Skip to content

Commit

Permalink
Merge pull request ethereum#15 from OffchainLabs/stylus-memory-model
Browse files Browse the repository at this point in the history
Stylus memory model
  • Loading branch information
rachel-bousfield authored Jun 30, 2023
2 parents 8365a04 + f997cb3 commit c1a03e2
Show file tree
Hide file tree
Showing 8 changed files with 174 additions and 0 deletions.
64 changes: 64 additions & 0 deletions common/types_arbitrum.go
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.

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
}
17 changes: 17 additions & 0 deletions core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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).
Expand Down Expand Up @@ -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() {
Expand Down
24 changes: 24 additions & 0 deletions core/state/statedb_arbitrum.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
21 changes: 21 additions & 0 deletions core/types/receipt_arbitrum.go
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.

package types

func (r *Receipt) GasUsedForL2() uint64 {
return r.GasUsed - r.GasUsedForL1
}
26 changes: 26 additions & 0 deletions core/vm/contract_arbitrum.go
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.

package vm

func (c *Contract) BurnGas(amount uint64) error {
if c.Gas < amount {
c.Gas = 0
return ErrOutOfGas
}
c.Gas -= amount
return nil
}
7 changes: 7 additions & 0 deletions core/vm/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions log/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down
9 changes: 9 additions & 0 deletions log/logger_arbitrum.go
Original file line number Diff line number Diff line change
@@ -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, "")
}

0 comments on commit c1a03e2

Please sign in to comment.