Skip to content

Commit

Permalink
Redo the validator
Browse files Browse the repository at this point in the history
  • Loading branch information
ImJeremyHe committed Sep 11, 2024
1 parent dcbf07b commit a40ab8e
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 126 deletions.
10 changes: 0 additions & 10 deletions arbnode/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"strings"
"time"

lightclient "github.com/EspressoSystems/espresso-sequencer-go/light-client"
flag "github.com/spf13/pflag"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
Expand Down Expand Up @@ -573,18 +572,9 @@ func createNodeImpl(

var statelessBlockValidator *staker.StatelessBlockValidator
if config.BlockValidator.RedisValidationClientConfig.Enabled() || config.BlockValidator.ValidationServerConfigs[0].URL != "" {
var lightClientReader *lightclient.LightClientReader
if config.BlockValidator.Espresso {
addr := common.HexToAddress(config.BlockValidator.LightClientAddress)
lightClientReader, err = lightclient.NewLightClientReader(addr, l1client)
if err != nil {
return nil, err
}
}
statelessBlockValidator, err = staker.NewStatelessBlockValidator(
inboxReader,
inboxTracker,
lightClientReader,
txStreamer,
exec,
rawdb.NewTable(arbDb, storage.BlockValidatorPrefix),
Expand Down
32 changes: 2 additions & 30 deletions staker/block_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,12 @@ import (
"testing"
"time"

espressoTypes "github.com/EspressoSystems/espresso-sequencer-go/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/rlp"
"github.com/offchainlabs/nitro/arbnode/resourcemanager"
"github.com/offchainlabs/nitro/arbos"
"github.com/offchainlabs/nitro/arbutil"
"github.com/offchainlabs/nitro/util/containers"
"github.com/offchainlabs/nitro/util/rpcclient"
Expand Down Expand Up @@ -108,10 +106,6 @@ type BlockValidatorConfig struct {
ValidationServerConfigsList string `koanf:"validation-server-configs-list"`

memoryFreeLimit int

// Espresso specific flags
Espresso bool `koanf:"espresso"`
LightClientAddress string `koanf:"light-client-address"` //nolint
}

func (c *BlockValidatorConfig) Validate() error {
Expand Down Expand Up @@ -159,9 +153,7 @@ func BlockValidatorConfigAddOptions(prefix string, f *pflag.FlagSet) {
f.Uint64(prefix+".prerecorded-blocks", DefaultBlockValidatorConfig.PrerecordedBlocks, "record that many blocks ahead of validation (larger footprint)")
f.String(prefix+".current-module-root", DefaultBlockValidatorConfig.CurrentModuleRoot, "current wasm module root ('current' read from chain, 'latest' from machines/latest dir, or provide hash)")
f.String(prefix+".pending-upgrade-module-root", DefaultBlockValidatorConfig.PendingUpgradeModuleRoot, "pending upgrade wasm module root to additionally validate (hash, 'latest' or empty)")
f.String(prefix+".light-client-address", DefaultBlockValidatorConfig.LightClientAddress, "address of the hotshot light client contract")
f.Bool(prefix+".failure-is-fatal", DefaultBlockValidatorConfig.FailureIsFatal, "failing a validation is treated as a fatal error")
f.Bool(prefix+".espresso", DefaultBlockValidatorConfig.Espresso, "if true, hotshot header preimages will be added to validation entries to verify that transactions have been sequenced by espresso")
BlockValidatorDangerousConfigAddOptions(prefix+".dangerous", f)
f.String(prefix+".memory-free-limit", DefaultBlockValidatorConfig.MemoryFreeLimit, "minimum free-memory limit after reaching which the blockvalidator pauses validation. Enabled by default as 1GB, to disable provide empty string")
}
Expand Down Expand Up @@ -440,7 +432,7 @@ func GlobalStateToMsgCount(tracker InboxTrackerInterface, streamer TransactionSt
return false, 0, err
}
if res.BlockHash != gs.BlockHash || res.SendRoot != gs.SendRoot {
return false, count, fmt.Errorf("%w: count %d hash %v expected %v, sendroot %v expected %v", ErrGlobalStateNotInChain, count, gs.BlockHash, res.BlockHash, gs.SendRoot, res.SendRoot)
return false, 0, fmt.Errorf("%w: count %d hash %v expected %v, sendroot %v expected %v", ErrGlobalStateNotInChain, count, gs.BlockHash, res.BlockHash, gs.SendRoot, res.SendRoot)
}
return true, count, nil
}
Expand Down Expand Up @@ -582,29 +574,9 @@ func (v *BlockValidator) createNextValidationEntry(ctx context.Context) (bool, e
} else {
return false, fmt.Errorf("illegal batch msg count %d pos %d batch %d", v.nextCreateBatchMsgCount, pos, endGS.Batch)
}
var comm espressoTypes.Commitment
var isHotShotLive bool
var blockHeight uint64
if arbos.IsEspressoMsg(msg.Message) {
_, jst, err := arbos.ParseEspressoMsg(msg.Message)
if err != nil {
return false, err
}
blockHeight = jst.Header.Height
snapShot, err := v.lightClientReader.FetchMerkleRoot(blockHeight, nil)
if err != nil {
log.Error("error attempting to fetch block merkle root from the light client contract", "blockHeight", blockHeight)
return false, err
}
comm = snapShot.Root
isHotShotLive = true
} else if arbos.IsL2NonEspressoMsg(msg.Message) {
isHotShotLive = false
blockHeight = msg.Message.Header.BlockNumber
}
chainConfig := v.streamer.ChainConfig()
entry, err := newValidationEntry(
pos, v.nextCreateStartGS, endGS, msg, v.nextCreateBatch, v.nextCreateBatchBlockHash, v.nextCreatePrevDelayed, chainConfig, &comm, isHotShotLive, blockHeight,
pos, v.nextCreateStartGS, endGS, msg, v.nextCreateBatch, v.nextCreateBatchBlockHash, v.nextCreatePrevDelayed, chainConfig,
)
if err != nil {
return false, err
Expand Down
118 changes: 32 additions & 86 deletions staker/stateless_block_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,7 @@ import (
"fmt"
"testing"

lightclient "github.com/EspressoSystems/espresso-sequencer-go/light-client"
espressoTypes "github.com/EspressoSystems/espresso-sequencer-go/types"
"github.com/offchainlabs/nitro/arbos"
"github.com/offchainlabs/nitro/execution"
"github.com/offchainlabs/nitro/util/rpcclient"

"github.com/offchainlabs/nitro/arbstate/daprovider"
"github.com/offchainlabs/nitro/arbutil"
"github.com/offchainlabs/nitro/validator"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
Expand All @@ -26,6 +18,10 @@ import (
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
"github.com/offchainlabs/nitro/arbos/arbostypes"
"github.com/offchainlabs/nitro/arbutil"
"github.com/offchainlabs/nitro/execution"
"github.com/offchainlabs/nitro/util/rpcclient"
"github.com/offchainlabs/nitro/validator"
"github.com/offchainlabs/nitro/validator/client/redis"

validatorclient "github.com/offchainlabs/nitro/validator/client"
Expand All @@ -44,8 +40,6 @@ type StatelessBlockValidator struct {
streamer TransactionStreamerInterface
db ethdb.Database
dapReaders []daprovider.Reader

lightClientReader lightclient.LightClientReaderInterface
}

type BlockValidatorRegistrer interface {
Expand Down Expand Up @@ -137,32 +131,22 @@ type validationEntry struct {
Preimages map[arbutil.PreimageType]map[common.Hash][]byte
UserWasms state.UserWasms
DelayedMsg []byte

// If hotshot is down, this is the l1 height associated with the arbitrum original message.
// We use this to validate the hotshot liveness
// If hotshot is up, this is the hotshot height.
BlockHeight uint64
HotShotCommitment espressoTypes.Commitment
IsHotShotLive bool
}

func (e *validationEntry) ToInput() (*validator.ValidationInput, error) {
if e.Stage != Ready {
return nil, errors.New("cannot create input from non-ready entry")
}
return &validator.ValidationInput{
Id: uint64(e.Pos),
HasDelayedMsg: e.HasDelayedMsg,
DelayedMsgNr: e.DelayedMsgNr,
Preimages: e.Preimages,
UserWasms: e.UserWasms,
BatchInfo: e.BatchInfo,
DelayedMsg: e.DelayedMsg,
StartState: e.Start,
DebugChain: e.ChainConfig.DebugMode(),
BlockHeight: e.BlockHeight,
HotShotCommitment: e.HotShotCommitment,
HotShotLiveness: e.IsHotShotLive,
Id: uint64(e.Pos),
HasDelayedMsg: e.HasDelayedMsg,
DelayedMsgNr: e.DelayedMsgNr,
Preimages: e.Preimages,
UserWasms: e.UserWasms,
BatchInfo: e.BatchInfo,
DelayedMsg: e.DelayedMsg,
StartState: e.Start,
DebugChain: e.ChainConfig.DebugMode(),
}, nil
}

Expand All @@ -175,9 +159,6 @@ func newValidationEntry(
batchBlockHash common.Hash,
prevDelayed uint64,
chainConfig *params.ChainConfig,
hotShotCommitment *espressoTypes.Commitment,
isHotShotLive bool,
l1BlockHeight uint64,
) (*validationEntry, error) {
batchInfo := validator.BatchInfo{
Number: start.Batch,
Expand All @@ -193,36 +174,28 @@ func newValidationEntry(
return nil, fmt.Errorf("illegal validation entry delayedMessage %d, previous %d", msg.DelayedMessagesRead, prevDelayed)
}
return &validationEntry{
Stage: ReadyForRecord,
Pos: pos,
Start: start,
End: end,
HasDelayedMsg: hasDelayed,
DelayedMsgNr: delayedNum,
msg: msg,
BatchInfo: []validator.BatchInfo{batchInfo},
ChainConfig: chainConfig,
BlockHeight: l1BlockHeight,
HotShotCommitment: *hotShotCommitment,
IsHotShotLive: isHotShotLive,
Stage: ReadyForRecord,
Pos: pos,
Start: start,
End: end,
HasDelayedMsg: hasDelayed,
DelayedMsgNr: delayedNum,
msg: msg,
BatchInfo: []validator.BatchInfo{batchInfo},
ChainConfig: chainConfig,
}, nil
}

func NewStatelessBlockValidator(
inboxReader InboxReaderInterface,
inbox InboxTrackerInterface,
lightClientReader lightclient.LightClientReaderInterface,
streamer TransactionStreamerInterface,
recorder execution.ExecutionRecorder,
arbdb ethdb.Database,
dapReaders []daprovider.Reader,
config func() *BlockValidatorConfig,
stack *node.Node,
) (*StatelessBlockValidator, error) {
// Sanity check, also used to surpress the unused koanf field lint error
if config().Espresso && config().LightClientAddress == "" {
return nil, errors.New("cannot create a new stateless block validator in espresso mode without a hotshot reader")
}
var executionSpawners []validator.ExecutionSpawner
var redisValClient *redis.ValidationClient

Expand All @@ -245,16 +218,15 @@ func NewStatelessBlockValidator(
}

return &StatelessBlockValidator{
config: config(),
recorder: recorder,
redisValidator: redisValClient,
inboxReader: inboxReader,
lightClientReader: lightClientReader,
inboxTracker: inbox,
streamer: streamer,
db: arbdb,
dapReaders: dapReaders,
execSpawners: executionSpawners,
config: config(),
recorder: recorder,
redisValidator: redisValClient,
inboxReader: inboxReader,
inboxTracker: inbox,
streamer: streamer,
db: arbdb,
dapReaders: dapReaders,
execSpawners: executionSpawners,
}, nil
}

Expand Down Expand Up @@ -289,7 +261,6 @@ func (v *StatelessBlockValidator) ValidationEntryRecord(ctx context.Context, e *
}
e.DelayedMsg = delayedMsg
}

for _, batch := range e.BatchInfo {
if len(batch.Data) <= 40 {
continue
Expand Down Expand Up @@ -382,27 +353,7 @@ func (v *StatelessBlockValidator) CreateReadyValidationEntry(ctx context.Context
if err != nil {
return nil, err
}
var comm espressoTypes.Commitment
var isHotShotLive bool
var blockHeight uint64
if arbos.IsEspressoMsg(msg.Message) {
_, jst, err := arbos.ParseEspressoMsg(msg.Message)
if err != nil {
return nil, err
}
blockHeight = jst.Header.Height
snapShot, err := v.lightClientReader.FetchMerkleRoot(blockHeight, nil)
if err != nil {
log.Error("error fetching light client commitment", "hotshot block height", blockHeight, "%v", err)
return nil, err
}
comm = snapShot.Root
isHotShotLive = true
} else if arbos.IsL2NonEspressoMsg(msg.Message) {
isHotShotLive = false
blockHeight = msg.Message.Header.BlockNumber
}
entry, err := newValidationEntry(pos, start, end, msg, seqMsg, batchBlockHash, prevDelayed, v.streamer.ChainConfig(), &comm, isHotShotLive, blockHeight)
entry, err := newValidationEntry(pos, start, end, msg, seqMsg, batchBlockHash, prevDelayed, v.streamer.ChainConfig())
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -493,8 +444,3 @@ func (v *StatelessBlockValidator) Stop() {
v.redisValidator.Stop()
}
}

// This method should be only used in tests.
func (s *StatelessBlockValidator) DebugEspresso_SetLightClientReader(reader lightclient.LightClientReaderInterface, t *testing.T) {
s.lightClientReader = reader
}

0 comments on commit a40ab8e

Please sign in to comment.