Skip to content

Commit

Permalink
Merge branch 'master' into patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuacolvin0 authored Apr 30, 2024
2 parents 58fd8bb + c74d874 commit 45648cb
Show file tree
Hide file tree
Showing 35 changed files with 352 additions and 174 deletions.
4 changes: 2 additions & 2 deletions arbnode/dataposter/data_poster.go
Original file line number Diff line number Diff line change
Expand Up @@ -845,7 +845,7 @@ func (p *DataPoster) sendTx(ctx context.Context, prevTx *storage.QueuedTransacti
return fmt.Errorf("couldn't get preceding tx in DataPoster to check if should send tx with nonce %d: %w", newTx.FullTx.Nonce(), err)
}
if precedingTx != nil && // precedingTx == nil -> the actual preceding tx was already confirmed
precedingTx.FullTx.Type() != newTx.FullTx.Type() {
(precedingTx.FullTx.Type() != newTx.FullTx.Type() || !precedingTx.Sent) {
latestBlockNumber, err := p.client.BlockNumber(ctx)
if err != nil {
return fmt.Errorf("couldn't get block number in DataPoster to check if should send tx with nonce %d: %w", newTx.FullTx.Nonce(), err)
Expand All @@ -857,7 +857,7 @@ func (p *DataPoster) sendTx(ctx context.Context, prevTx *storage.QueuedTransacti
}

if precedingTx.FullTx.Nonce() > reorgResistantNonce {
log.Info("DataPoster is holding off on sending a transaction of different type to the previous transaction until the previous transaction has been included in a reorg resistant block (it remains queued and will be retried)", "nonce", newTx.FullTx.Nonce(), "prevType", precedingTx.FullTx.Type(), "type", newTx.FullTx.Type())
log.Info("DataPoster is avoiding creating a mempool nonce gap (the tx remains queued and will be retried)", "nonce", newTx.FullTx.Nonce(), "prevType", precedingTx.FullTx.Type(), "type", newTx.FullTx.Type(), "prevSent", precedingTx.Sent)
return nil
}
}
Expand Down
48 changes: 30 additions & 18 deletions arbos/arbosState/arbosstate.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,24 +36,26 @@ import (
// persisted beyond the end of the test.)

type ArbosState struct {
arbosVersion uint64 // version of the ArbOS storage format and semantics
upgradeVersion storage.StorageBackedUint64 // version we're planning to upgrade to, or 0 if not planning to upgrade
upgradeTimestamp storage.StorageBackedUint64 // when to do the planned upgrade
networkFeeAccount storage.StorageBackedAddress
l1PricingState *l1pricing.L1PricingState
l2PricingState *l2pricing.L2PricingState
retryableState *retryables.RetryableState
addressTable *addressTable.AddressTable
chainOwners *addressSet.AddressSet
sendMerkle *merkleAccumulator.MerkleAccumulator
blockhashes *blockhash.Blockhashes
chainId storage.StorageBackedBigInt
chainConfig storage.StorageBackedBytes
genesisBlockNum storage.StorageBackedUint64
infraFeeAccount storage.StorageBackedAddress
brotliCompressionLevel storage.StorageBackedUint64 // brotli compression level used for pricing
backingStorage *storage.Storage
Burner burn.Burner
arbosVersion uint64 // version of the ArbOS storage format and semantics
maxArbosVersionSupported uint64 // maximum ArbOS version supported by this code
maxDebugArbosVersionSupported uint64 // maximum ArbOS version supported by this code in debug mode
upgradeVersion storage.StorageBackedUint64 // version we're planning to upgrade to, or 0 if not planning to upgrade
upgradeTimestamp storage.StorageBackedUint64 // when to do the planned upgrade
networkFeeAccount storage.StorageBackedAddress
l1PricingState *l1pricing.L1PricingState
l2PricingState *l2pricing.L2PricingState
retryableState *retryables.RetryableState
addressTable *addressTable.AddressTable
chainOwners *addressSet.AddressSet
sendMerkle *merkleAccumulator.MerkleAccumulator
blockhashes *blockhash.Blockhashes
chainId storage.StorageBackedBigInt
chainConfig storage.StorageBackedBytes
genesisBlockNum storage.StorageBackedUint64
infraFeeAccount storage.StorageBackedAddress
brotliCompressionLevel storage.StorageBackedUint64 // brotli compression level used for pricing
backingStorage *storage.Storage
Burner burn.Burner
}

var ErrUninitializedArbOS = errors.New("ArbOS uninitialized")
Expand All @@ -70,6 +72,8 @@ func OpenArbosState(stateDB vm.StateDB, burner burn.Burner) (*ArbosState, error)
}
return &ArbosState{
arbosVersion,
20,
20,
backingStorage.OpenStorageBackedUint64(uint64(upgradeVersionOffset)),
backingStorage.OpenStorageBackedUint64(uint64(upgradeTimestampOffset)),
backingStorage.OpenStorageBackedAddress(uint64(networkFeeAccountOffset)),
Expand Down Expand Up @@ -400,6 +404,14 @@ func (state *ArbosState) RetryableState() *retryables.RetryableState {
return state.retryableState
}

func (state *ArbosState) MaxArbosVersionSupported() uint64 {
return state.maxArbosVersionSupported
}

func (state *ArbosState) MaxDebugArbosVersionSupported() uint64 {
return state.maxDebugArbosVersionSupported
}

func (state *ArbosState) L1PricingState() *l1pricing.L1PricingState {
return state.l1PricingState
}
Expand Down
13 changes: 8 additions & 5 deletions cmd/daserver/daserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ import (
"context"
"errors"
"fmt"
"io"
"net/http"
"os"
"os/signal"
"syscall"
"time"

"golang.org/x/exp/slog"

koanfjson "github.com/knadh/koanf/parsers/json"
flag "github.com/spf13/pflag"

Expand Down Expand Up @@ -182,14 +185,14 @@ func startup() error {
confighelpers.PrintErrorAndExit(errors.New("please specify at least one of --enable-rest or --enable-rpc"), printSampleUsage)
}

logFormat, err := genericconf.ParseLogType(serverConfig.LogType)
handler, err := genericconf.HandlerFromLogType(serverConfig.LogType, io.Writer(os.Stderr))
if err != nil {
flag.Usage()
panic(fmt.Sprintf("Error parsing log type: %v", err))
return fmt.Errorf("error parsing log type when creating handler: %w", err)
}
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, logFormat))
glogger.Verbosity(log.Lvl(serverConfig.LogLevel))
log.Root().SetHandler(glogger)
glogger := log.NewGlogHandler(handler)
glogger.Verbosity(slog.Level(serverConfig.LogLevel))
log.SetDefault(log.NewLogger(glogger))

if err := startMetrics(serverConfig); err != nil {
return err
Expand Down
6 changes: 4 additions & 2 deletions cmd/deploy/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"encoding/json"
"flag"
"fmt"
"io"
"math/big"
"os"
"strings"
Expand All @@ -30,9 +31,10 @@ import (
)

func main() {
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
glogger := log.NewGlogHandler(
log.NewTerminalHandler(io.Writer(os.Stderr), false))
glogger.Verbosity(log.LvlDebug)
log.Root().SetHandler(glogger)
log.SetDefault(log.NewLogger(glogger))
log.Info("deploying rollup")

ctx := context.Background()
Expand Down
8 changes: 5 additions & 3 deletions cmd/genericconf/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ package genericconf

import (
"errors"
"io"
"time"

"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
flag "github.com/spf13/pflag"
"golang.org/x/exp/slog"
)

type ConfConfig struct {
Expand Down Expand Up @@ -63,11 +65,11 @@ var DefaultS3Config = S3Config{
SecretKey: "",
}

func ParseLogType(logType string) (log.Format, error) {
func HandlerFromLogType(logType string, output io.Writer) (slog.Handler, error) {
if logType == "plaintext" {
return log.TerminalFormat(false), nil
return log.NewTerminalHandler(output, false), nil
} else if logType == "json" {
return log.JSONFormat(), nil
return log.JSONHandler(output), nil
}
return nil, errors.New("invalid log type")
}
Expand Down
7 changes: 4 additions & 3 deletions cmd/genericconf/filehandler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,10 @@ func testFileHandler(t *testing.T, testCompressed bool) {
config.MaxSize = 1
config.Compress = testCompressed
config.File = testFile
fileHandler := globalFileHandlerFactory.newHandler(log.JSONFormat(), &config, testFile)
defer func() { testhelpers.RequireImpl(t, globalFileHandlerFactory.close()) }()
log.Root().SetHandler(fileHandler)
handler, err := HandlerFromLogType("json", globalFileLoggerFactory.newFileWriter(&config, testFile))
defer func() { testhelpers.RequireImpl(t, globalFileLoggerFactory.close()) }()
testhelpers.RequireImpl(t, err)
log.SetDefault(log.NewLogger(handler))
expected := []string{"dead", "beef", "ate", "bad", "beef"}
for _, e := range expected {
log.Warn(e)
Expand Down
99 changes: 57 additions & 42 deletions cmd/genericconf/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,47 @@ import (
"context"
"flag"
"fmt"
"io"
"os"
"sync"

"github.com/ethereum/go-ethereum/log"
"golang.org/x/exp/slog"
"gopkg.in/natefinch/lumberjack.v2"
)

var globalFileHandlerFactory = fileHandlerFactory{}
var globalFileLoggerFactory = fileLoggerFactory{}

type fileHandlerFactory struct {
writer *lumberjack.Logger
records chan *log.Record
cancel context.CancelFunc
type fileLoggerFactory struct {
// writerMutex is to avoid parallel writes to the file-logger
writerMutex sync.Mutex
writer *lumberjack.Logger

cancel context.CancelFunc

// writeStartPing and writeDonePing are used to simulate sending of data via a buffered channel
// when Write is called and receiving it on another go-routine to write it to the io.Writer.
writeStartPing chan struct{}
writeDonePing chan struct{}
}

// Write is essentially a wrapper for filewriter or lumberjack.Logger's Write method to implement
// config.BufSize functionality, data is dropped when l.writeStartPing channel (of size config.BuffSize) is full
func (l *fileLoggerFactory) Write(p []byte) (n int, err error) {
select {
case l.writeStartPing <- struct{}{}:
// Write data to the filelogger
l.writerMutex.Lock()
_, _ = l.writer.Write(p)
l.writerMutex.Unlock()
l.writeDonePing <- struct{}{}
default:
}
return len(p), nil
}

// newHandler is not threadsafe
func (l *fileHandlerFactory) newHandler(logFormat log.Format, config *FileLoggingConfig, filename string) log.Handler {
// newFileWriter is not threadsafe
func (l *fileLoggerFactory) newFileWriter(config *FileLoggingConfig, filename string) io.Writer {
l.close()
l.writer = &lumberjack.Logger{
Filename: filename,
Expand All @@ -28,40 +53,29 @@ func (l *fileHandlerFactory) newHandler(logFormat log.Format, config *FileLoggin
MaxAge: config.MaxAge,
Compress: config.Compress,
}
// capture copy of the pointer
writer := l.writer
// lumberjack.Logger already locks on Write, no need for SyncHandler proxy which is used in StreamHandler
unsafeStreamHandler := log.LazyHandler(log.FuncHandler(func(r *log.Record) error {
_, err := writer.Write(logFormat.Format(r))
return err
}))
l.records = make(chan *log.Record, config.BufSize)
l.writeStartPing = make(chan struct{}, config.BufSize)
l.writeDonePing = make(chan struct{}, config.BufSize)
// capture copy
records := l.records
writeStartPing := l.writeStartPing
writeDonePing := l.writeDonePing
var consumerCtx context.Context
consumerCtx, l.cancel = context.WithCancel(context.Background())
go func() {
// writeStartPing channel signals Write operations to correctly implement config.BufSize functionality
for {
select {
case r := <-records:
_ = unsafeStreamHandler.Log(r)
case <-writeStartPing:
<-writeDonePing
case <-consumerCtx.Done():
return
}
}
}()
return log.FuncHandler(func(r *log.Record) error {
select {
case records <- r:
return nil
default:
return fmt.Errorf("Buffer overflow, dropping record")
}
})
return l
}

// close is not threadsafe
func (l *fileHandlerFactory) close() error {
func (l *fileLoggerFactory) close() error {
if l.cancel != nil {
l.cancel()
l.cancel = nil
Expand All @@ -76,28 +90,29 @@ func (l *fileHandlerFactory) close() error {
}

// initLog is not threadsafe
func InitLog(logType string, logLevel log.Lvl, fileLoggingConfig *FileLoggingConfig, pathResolver func(string) string) error {
logFormat, err := ParseLogType(logType)
if err != nil {
flag.Usage()
return fmt.Errorf("error parsing log type: %w", err)
}
func InitLog(logType string, logLevel slog.Level, fileLoggingConfig *FileLoggingConfig, pathResolver func(string) string) error {
var glogger *log.GlogHandler
// always close previous instance of file logger
if err := globalFileHandlerFactory.close(); err != nil {
if err := globalFileLoggerFactory.close(); err != nil {
return fmt.Errorf("failed to close file writer: %w", err)
}
var output io.Writer
if fileLoggingConfig.Enable {
glogger = log.NewGlogHandler(
log.MultiHandler(
log.StreamHandler(os.Stderr, logFormat),
// on overflow records are dropped silently as MultiHandler ignores errors
globalFileHandlerFactory.newHandler(logFormat, fileLoggingConfig, pathResolver(fileLoggingConfig.File)),
))
output = io.MultiWriter(
io.Writer(os.Stderr),
// on overflow writeStartPing are dropped silently
globalFileLoggerFactory.newFileWriter(fileLoggingConfig, pathResolver(fileLoggingConfig.File)),
)
} else {
glogger = log.NewGlogHandler(log.StreamHandler(os.Stderr, logFormat))
output = io.Writer(os.Stderr)
}
handler, err := HandlerFromLogType(logType, output)
if err != nil {
flag.Usage()
return fmt.Errorf("error parsing log type when creating handler: %w", err)
}
glogger = log.NewGlogHandler(handler)
glogger.Verbosity(logLevel)
log.Root().SetHandler(glogger)
log.SetDefault(log.NewLogger(glogger))
return nil
}
5 changes: 3 additions & 2 deletions cmd/nitro-val/nitro_val.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/offchainlabs/nitro/cmd/util/confighelpers"
_ "github.com/offchainlabs/nitro/execution/nodeInterface"
"github.com/offchainlabs/nitro/validator/valnode"
"golang.org/x/exp/slog"
)

func printSampleUsage(name string) {
Expand Down Expand Up @@ -89,7 +90,7 @@ func mainImpl() int {
}
}

err = genericconf.InitLog(nodeConfig.LogType, log.Lvl(nodeConfig.LogLevel), &nodeConfig.FileLogging, pathResolver(nodeConfig.Persistent.LogDir))
err = genericconf.InitLog(nodeConfig.LogType, slog.Level(nodeConfig.LogLevel), &nodeConfig.FileLogging, pathResolver(nodeConfig.Persistent.LogDir))
if err != nil {
fmt.Fprintf(os.Stderr, "Error initializing logging: %v\n", err)
return 1
Expand All @@ -108,7 +109,7 @@ func mainImpl() int {
liveNodeConfig := genericconf.NewLiveConfig[*ValidationNodeConfig](args, nodeConfig, ParseNode)
liveNodeConfig.SetOnReloadHook(func(oldCfg *ValidationNodeConfig, newCfg *ValidationNodeConfig) error {

return genericconf.InitLog(newCfg.LogType, log.Lvl(newCfg.LogLevel), &newCfg.FileLogging, pathResolver(nodeConfig.Persistent.LogDir))
return genericconf.InitLog(newCfg.LogType, slog.Level(newCfg.LogLevel), &newCfg.FileLogging, pathResolver(nodeConfig.Persistent.LogDir))
})

valnode.EnsureValidationExposedViaAuthRPC(&stackConf)
Expand Down
11 changes: 11 additions & 0 deletions cmd/nitro/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,17 @@ func validateBlockChain(blockChain *core.BlockChain, chainConfig *params.ChainCo
return fmt.Errorf("invalid chain config, not compatible with previous: %w", err)
}
}
// Make sure we don't allow accidentally downgrading ArbOS
if chainConfig.DebugMode() {
if currentArbosState.ArbOSVersion() > currentArbosState.MaxDebugArbosVersionSupported() {
return fmt.Errorf("attempted to launch node in debug mode with ArbOS version %v on ArbOS state with version %v", currentArbosState.MaxDebugArbosVersionSupported(), currentArbosState.ArbOSVersion())
}
} else {
if currentArbosState.ArbOSVersion() > currentArbosState.MaxArbosVersionSupported() {
return fmt.Errorf("attempted to launch node with ArbOS version %v on ArbOS state with version %v", currentArbosState.MaxArbosVersionSupported(), currentArbosState.ArbOSVersion())
}

}

return nil
}
Expand Down
Loading

0 comments on commit 45648cb

Please sign in to comment.