Skip to content

Commit

Permalink
Merge pull request #305 from OffchainLabs/stylus
Browse files Browse the repository at this point in the history
Arbitrum Stylus
  • Loading branch information
rachel-bousfield authored May 3, 2024
2 parents f941743 + 72f81da commit da4c975
Show file tree
Hide file tree
Showing 50 changed files with 1,028 additions and 54 deletions.
7 changes: 7 additions & 0 deletions arbitrum/recordingdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ func (db *RecordingKV) Get(key []byte) ([]byte, error) {
// Retrieving code
copy(hash[:], key[len(rawdb.CodePrefix):])
res, err = db.diskDb.Get(key)
} else if ok, _ := rawdb.IsActivatedAsmKey(key); ok {
// Arbitrum: the asm is non-consensus
return db.diskDb.Get(key)
} else if ok, _ := rawdb.IsActivatedModuleKey(key); ok {
// Arbitrum: the module is non-consensus (only its hash is)
return db.diskDb.Get(key)
} else {
err = fmt.Errorf("recording KV attempted to access non-hash key %v", hex.EncodeToString(key))
}
Expand Down Expand Up @@ -278,6 +284,7 @@ func (r *RecordingDatabase) PrepareRecording(ctx context.Context, lastBlockHeade
if err != nil {
return nil, nil, nil, fmt.Errorf("failed to create recordingStateDb: %w", err)
}
recordingStateDb.StartRecording()
var recordingChainContext *RecordingChainContext
if lastBlockHeader != nil {
if !lastBlockHeader.Number.IsUint64() {
Expand Down
2 changes: 2 additions & 0 deletions cmd/evm/internal/t8ntool/tracewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,5 @@ func (t *traceWriter) CaptureArbitrumTransfer(env *vm.EVM, from, to *common.Addr

func (t *traceWriter) CaptureArbitrumStorageGet(key common.Hash, depth int, before bool) {}
func (t *traceWriter) CaptureArbitrumStorageSet(key, value common.Hash, depth int, before bool) {}

func (t *traceWriter) CaptureStylusHostio(name string, args, outs []byte, startInk, endInk uint64) {}
2 changes: 2 additions & 0 deletions cmd/geth/logging_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ func censor(input string, start, end int) string {
}

func TestLogging(t *testing.T) {
t.Skip("Skipping cmd logging test due to color stripping")

t.Parallel()
testConsoleLogging(t, "terminal", 6, 24)
testConsoleLogging(t, "logfmt", 2, 26)
Expand Down
22 changes: 22 additions & 0 deletions common/lru/basiclru_arbitrum.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2022 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 lru implements generically-typed LRU caches.
package lru

func (c *BasicLRU[K, V]) Capacity() int {
return c.cap
}
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
}
36 changes: 36 additions & 0 deletions core/rawdb/accessors_state_arbitrum.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2020 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 rawdb

import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
)

// Stores the activated asm and module for a given codeHash
func WriteActivation(db ethdb.KeyValueWriter, moduleHash common.Hash, asm, module []byte) {
key := ActivatedAsmKey(moduleHash)
if err := db.Put(key[:], asm); err != nil {
log.Crit("Failed to store activated wasm asm", "err", err)
}

key = ActivatedModuleKey(moduleHash)
if err := db.Put(key[:], module); err != nil {
log.Crit("Failed to store activated wasm module", "err", err)
}
}
4 changes: 2 additions & 2 deletions core/rawdb/fileutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
// 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/>.

//go:build !js
// +build !js
//go:build !wasm
// +build !wasm

package rawdb

Expand Down
4 changes: 2 additions & 2 deletions core/rawdb/fileutil_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
// 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/>.

//go:build js
// +build js
//go:build wasm
// +build wasm

package rawdb

Expand Down
66 changes: 66 additions & 0 deletions core/rawdb/schema_arbitrum.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright 2018 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 rawdb contains a collection of low level database accessors.

package rawdb

import (
"bytes"

"github.com/ethereum/go-ethereum/common"
)

var (
activatedAsmPrefix = []byte{0x00, 'w', 'a'} // (prefix, moduleHash) -> stylus asm
activatedModulePrefix = []byte{0x00, 'w', 'm'} // (prefix, moduleHash) -> stylus module
)

// WasmKeyLen = CompiledWasmCodePrefix + moduleHash
const WasmKeyLen = 3 + 32

type WasmKey = [WasmKeyLen]byte

func ActivatedAsmKey(moduleHash common.Hash) WasmKey {
return newWasmKey(activatedAsmPrefix, moduleHash)
}

func ActivatedModuleKey(moduleHash common.Hash) WasmKey {
return newWasmKey(activatedModulePrefix, moduleHash)
}

// key = prefix + moduleHash
func newWasmKey(prefix []byte, moduleHash common.Hash) WasmKey {
var key WasmKey
copy(key[:3], prefix)
copy(key[3:], moduleHash[:])
return key
}

func IsActivatedAsmKey(key []byte) (bool, common.Hash) {
return extractWasmKey(activatedAsmPrefix, key)
}

func IsActivatedModuleKey(key []byte) (bool, common.Hash) {
return extractWasmKey(activatedModulePrefix, key)
}

func extractWasmKey(prefix, key []byte) (bool, common.Hash) {
if !bytes.HasPrefix(key, prefix) || len(key) != WasmKeyLen {
return false, common.Hash{}
}
return true, common.BytesToHash(key[len(prefix):])
}
19 changes: 19 additions & 0 deletions core/state/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ import (
)

const (
// Arbitrum: Cache size granted for caching clean compiled wasm code.
activatedWasmCacheSize = 64 * 1024 * 1024

// Number of codehash->size associations to keep.
codeSizeCacheSize = 100000

Expand All @@ -48,6 +51,10 @@ const (

// Database wraps access to tries and contract code.
type Database interface {
// Arbitrum: Read activated Stylus contracts
ActivatedAsm(moduleHash common.Hash) (asm []byte, err error)
ActivatedModule(moduleHash common.Hash) (module []byte, err error)

// OpenTrie opens the main account trie.
OpenTrie(root common.Hash) (Trie, error)

Expand Down Expand Up @@ -152,6 +159,10 @@ func NewDatabase(db ethdb.Database) Database {
// large memory cache.
func NewDatabaseWithConfig(db ethdb.Database, config *trie.Config) Database {
cdb := &cachingDB{
// Arbitrum only
activatedAsmCache: lru.NewSizeConstrainedCache[common.Hash, []byte](activatedWasmCacheSize),
activatedModuleCache: lru.NewSizeConstrainedCache[common.Hash, []byte](activatedWasmCacheSize),

disk: db,
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
Expand All @@ -163,6 +174,10 @@ func NewDatabaseWithConfig(db ethdb.Database, config *trie.Config) Database {
// NewDatabaseWithNodeDB creates a state database with an already initialized node database.
func NewDatabaseWithNodeDB(db ethdb.Database, triedb *trie.Database) Database {
cdb := &cachingDB{
// Arbitrum only
activatedAsmCache: lru.NewSizeConstrainedCache[common.Hash, []byte](activatedWasmCacheSize),
activatedModuleCache: lru.NewSizeConstrainedCache[common.Hash, []byte](activatedWasmCacheSize),

disk: db,
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
Expand All @@ -172,6 +187,10 @@ func NewDatabaseWithNodeDB(db ethdb.Database, triedb *trie.Database) Database {
}

type cachingDB struct {
// Arbitrum
activatedAsmCache *lru.SizeConstrainedCache[common.Hash, []byte]
activatedModuleCache *lru.SizeConstrainedCache[common.Hash, []byte]

disk ethdb.KeyValueStore
codeSizeCache *lru.Cache[common.Hash, int]
codeCache *lru.SizeConstrainedCache[common.Hash, []byte]
Expand Down
40 changes: 40 additions & 0 deletions core/state/database_arbitrum.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package state

import (
"errors"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
)

func (db *cachingDB) ActivatedAsm(moduleHash common.Hash) ([]byte, error) {
if asm, _ := db.activatedAsmCache.Get(moduleHash); len(asm) > 0 {
return asm, nil
}
wasmKey := rawdb.ActivatedAsmKey(moduleHash)
asm, err := db.disk.Get(wasmKey[:])
if err != nil {
return nil, err
}
if len(asm) > 0 {
db.activatedAsmCache.Add(moduleHash, asm)
return asm, nil
}
return nil, errors.New("not found")
}

func (db *cachingDB) ActivatedModule(moduleHash common.Hash) ([]byte, error) {
if module, _ := db.activatedModuleCache.Get(moduleHash); len(module) > 0 {
return module, nil
}
wasmKey := rawdb.ActivatedModuleKey(moduleHash)
module, err := db.disk.Get(wasmKey[:])
if err != nil {
return nil, err
}
if len(module) > 0 {
db.activatedModuleCache.Add(moduleHash, module)
return module, nil
}
return nil, errors.New("not found")
}
50 changes: 50 additions & 0 deletions core/state/journal_arbitrum.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package state

import (
"github.com/ethereum/go-ethereum/common"
)

type wasmActivation struct {
moduleHash common.Hash
}

func (ch wasmActivation) revert(s *StateDB) {
delete(s.arbExtraData.activatedWasms, ch.moduleHash)
}

func (ch wasmActivation) dirtied() *common.Address {
return nil
}

// Updates the Rust-side recent program cache
var CacheWasmRust func(asm []byte, moduleHash common.Hash, version uint16, debug bool) = func([]byte, common.Hash, uint16, bool) {}
var EvictWasmRust func(moduleHash common.Hash, version uint16, debug bool) = func(common.Hash, uint16, bool) {}

type CacheWasm struct {
ModuleHash common.Hash
Version uint16
Debug bool
}

func (ch CacheWasm) revert(s *StateDB) {
EvictWasmRust(ch.ModuleHash, ch.Version, ch.Debug)
}

func (ch CacheWasm) dirtied() *common.Address {
return nil
}

type EvictWasm struct {
ModuleHash common.Hash
Version uint16
Debug bool
}

func (ch EvictWasm) revert(s *StateDB) {
asm := s.GetActivatedAsm(ch.ModuleHash) // only happens in native mode
CacheWasmRust(asm, ch.ModuleHash, ch.Version, ch.Debug)
}

func (ch EvictWasm) dirtied() *common.Address {
return nil
}
Loading

0 comments on commit da4c975

Please sign in to comment.