From d6a95e0d035d8332ccadfebc0bc4459f3b062829 Mon Sep 17 00:00:00 2001 From: Zach Showalter Date: Tue, 2 Jul 2024 13:58:28 -0400 Subject: [PATCH 1/7] Update validator to handle preconditions and panics before entering the espresso STF logic. --- cmd/replay/espresso_validation.go | 39 +++++++++++++++++++++++++++++++ cmd/replay/main.go | 10 +++----- 2 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 cmd/replay/espresso_validation.go diff --git a/cmd/replay/espresso_validation.go b/cmd/replay/espresso_validation.go new file mode 100644 index 0000000000..8fb31c3b5a --- /dev/null +++ b/cmd/replay/espresso_validation.go @@ -0,0 +1,39 @@ +package main + +import ( + "fmt" + + "github.com/offchainlabs/nitro/arbos" + "github.com/offchainlabs/nitro/arbos/arbostypes" + "github.com/offchainlabs/nitro/wavmio" +) + +// / Perform Espresso +// / +// / Description: This function takes in the most recently recieved message (of type arbostypes.MessageWithMetadata), +// / and a boolean from the ChainConfig +// / and uses the parameters to perform all checks gating the modified STF logic in the arbitrum validator. +// / +// / Return: A boolean representing the result of a logical and of all checks (that don't result in panics) gating espressos STF logic. +// / +// / Panics: This function will panic if the message type is not an espresso message, but the HotShot height is non zero +// / as this is an invalid state for the STF to reside in. +// / +func handleEspressoPreConditions(message *arbostypes.MessageWithMetadata, isEnabled bool) bool { + //calculate and cache all values needed to determine if the preconditions are met to enter the Espresso STF logic + isNonEspressoMessage := arbos.IsL2NonEspressoMsg(message.Message) + hotShotHeight := wavmio.GetEspressoHeight() + validatingEspressoLivenessFailure := isNonEspressoMessage && (isEnabled || hotShotHeight != 0) + validatingAgainstEspresso := !isNonEspressoMessage && isEnabled + + // If conditions are such that we have been working in espresso mode, but we are suddenly receiving non espresso messages, something wrong + // something incorrect has occured and we must panic + if validatingEspressoLivenessFailure { + l1Block := message.Message.Header.BlockNumber + if wavmio.IsHotShotLive(l1Block) { + panic(fmt.Sprintf("getting the centralized message while hotshot is good, l1Height: %v", l1Block)) + } + panic("The messaged recieved by the STF is not an Espresso message, but the validator is running in Espresso mode") + } + return validatingAgainstEspresso +} diff --git a/cmd/replay/main.go b/cmd/replay/main.go index 63baac072a..2c0fa39032 100644 --- a/cmd/replay/main.go +++ b/cmd/replay/main.go @@ -279,8 +279,9 @@ func main() { return wavmio.ReadInboxMessage(batchNum), nil } - validatingAgainstEspresso := arbos.IsEspressoMsg(message.Message) && chainConfig.ArbitrumChainParams.EnableEspresso - validatingEspressoLivenessFailure := arbos.IsL2NonEspressoMsg(message.Message) && chainConfig.ArbitrumChainParams.EnableEspresso + // Handle the various pre-conditions and panics that can happen before we should enter the espresso logic in the validators STF + validatingAgainstEspresso := handleEspressoPreConditions(message, chainConfig.ArbitrumChainParams.EnableEspresso) + if validatingAgainstEspresso { txs, jst, err := arbos.ParseEspressoMsg(message.Message) if err != nil { @@ -325,11 +326,6 @@ func main() { espressocrypto.VerifyNamespace(chainConfig.ChainID.Uint64(), *jst.Proof, *jst.Header.PayloadCommitment, *jst.Header.NsTable, txs, *jst.VidCommon) } - } else if validatingEspressoLivenessFailure { - l1Block := message.Message.Header.BlockNumber - if wavmio.IsHotShotLive(l1Block) { - panic(fmt.Sprintf("getting the centralized message while hotshot is good, l1Height: %v", l1Block)) - } } newBlock, _, err = arbos.ProduceBlock(message.Message, message.DelayedMessagesRead, lastBlockHeader, statedb, chainContext, chainConfig, batchFetcher, false) From b628488b24260426ef4a1d25296ed416ae3fb7c0 Mon Sep 17 00:00:00 2001 From: Zach Showalter Date: Tue, 2 Jul 2024 16:39:00 -0400 Subject: [PATCH 2/7] Improve readability of conditions in `handleEspressoPreConditions` and update the functions comments. --- cmd/replay/espresso_validation.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/replay/espresso_validation.go b/cmd/replay/espresso_validation.go index 8fb31c3b5a..32566fd51c 100644 --- a/cmd/replay/espresso_validation.go +++ b/cmd/replay/espresso_validation.go @@ -8,7 +8,7 @@ import ( "github.com/offchainlabs/nitro/wavmio" ) -// / Perform Espresso +// / Handle Espresso Pre Conditions // / // / Description: This function takes in the most recently recieved message (of type arbostypes.MessageWithMetadata), // / and a boolean from the ChainConfig From 53c8841d965482bc1258183d3e5b185810f1c0da Mon Sep 17 00:00:00 2001 From: Zach Showalter Date: Tue, 2 Jul 2024 16:48:57 -0400 Subject: [PATCH 3/7] Further improve readability --- cmd/replay/espresso_validation.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/replay/espresso_validation.go b/cmd/replay/espresso_validation.go index 32566fd51c..efeee4123e 100644 --- a/cmd/replay/espresso_validation.go +++ b/cmd/replay/espresso_validation.go @@ -22,9 +22,10 @@ import ( func handleEspressoPreConditions(message *arbostypes.MessageWithMetadata, isEnabled bool) bool { //calculate and cache all values needed to determine if the preconditions are met to enter the Espresso STF logic isNonEspressoMessage := arbos.IsL2NonEspressoMsg(message.Message) + isEspressoMessage := !isNonEspressoMessage hotShotHeight := wavmio.GetEspressoHeight() validatingEspressoLivenessFailure := isNonEspressoMessage && (isEnabled || hotShotHeight != 0) - validatingAgainstEspresso := !isNonEspressoMessage && isEnabled + validatingAgainstEspresso := isEspressoMessage && isEnabled // If conditions are such that we have been working in espresso mode, but we are suddenly receiving non espresso messages, something wrong // something incorrect has occured and we must panic From 85d5f33806ef48c2c68029887f2924c0656bc128 Mon Sep 17 00:00:00 2001 From: Zach Showalter Date: Tue, 2 Jul 2024 19:53:53 -0400 Subject: [PATCH 4/7] Fix lint issue --- cmd/replay/espresso_validation.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/replay/espresso_validation.go b/cmd/replay/espresso_validation.go index efeee4123e..7bcb3c8a2c 100644 --- a/cmd/replay/espresso_validation.go +++ b/cmd/replay/espresso_validation.go @@ -20,7 +20,7 @@ import ( // / as this is an invalid state for the STF to reside in. // / func handleEspressoPreConditions(message *arbostypes.MessageWithMetadata, isEnabled bool) bool { - //calculate and cache all values needed to determine if the preconditions are met to enter the Espresso STF logic + // calculate and cache all values needed to determine if the preconditions are met to enter the Espresso STF logic isNonEspressoMessage := arbos.IsL2NonEspressoMsg(message.Message) isEspressoMessage := !isNonEspressoMessage hotShotHeight := wavmio.GetEspressoHeight() From 99eca6d1a9fd038a80c11c1429cec59319c05e54 Mon Sep 17 00:00:00 2001 From: Zach Showalter Date: Tue, 9 Jul 2024 13:22:26 -0400 Subject: [PATCH 5/7] Changes to `handleEspressoPreConditions` in `espresso_validation.go` to fix incorrect logic, and give more granular control to where and how the generated panic is handled in the validators STF via returned closures. --- cmd/replay/espresso_validation.go | 39 +++++++++++++++++++------------ cmd/replay/main.go | 6 +++-- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/cmd/replay/espresso_validation.go b/cmd/replay/espresso_validation.go index 7bcb3c8a2c..80658596cf 100644 --- a/cmd/replay/espresso_validation.go +++ b/cmd/replay/espresso_validation.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "github.com/offchainlabs/nitro/arbos" "github.com/offchainlabs/nitro/arbos/arbostypes" "github.com/offchainlabs/nitro/wavmio" @@ -10,31 +9,41 @@ import ( // / Handle Espresso Pre Conditions // / -// / Description: This function takes in the most recently recieved message (of type arbostypes.MessageWithMetadata), +// / Description: This function takes in the most recently received message (of type arbostypes.MessageWithMetadata), // / and a boolean from the ChainConfig // / and uses the parameters to perform all checks gating the modified STF logic in the arbitrum validator. // / // / Return: A boolean representing the result of a logical and of all checks (that don't result in panics) gating espressos STF logic. // / -// / Panics: This function will panic if the message type is not an espresso message, but the HotShot height is non zero +// / Panics: This function will panic if the message type is not an espresso message, but the HotShot height is non-zero // / as this is an invalid state for the STF to reside in. // / -func handleEspressoPreConditions(message *arbostypes.MessageWithMetadata, isEnabled bool) bool { +func handleEspressoPreConditions(message *arbostypes.MessageWithMetadata, isEnabled bool) (bool, func()) { // calculate and cache all values needed to determine if the preconditions are met to enter the Espresso STF logic isNonEspressoMessage := arbos.IsL2NonEspressoMsg(message.Message) - isEspressoMessage := !isNonEspressoMessage - hotShotHeight := wavmio.GetEspressoHeight() - validatingEspressoLivenessFailure := isNonEspressoMessage && (isEnabled || hotShotHeight != 0) - validatingAgainstEspresso := isEspressoMessage && isEnabled + hotshotHeight := wavmio.GetEspressoHeight() + + validatingEspressoLivenessFailure := isNonEspressoMessage && isEnabled + validatingEspressoHeightFailure := isNonEspressoMessage && hotshotHeight != 0 + validatingAgainstEspresso := arbos.IsEspressoMsg(message.Message) && isEnabled - // If conditions are such that we have been working in espresso mode, but we are suddenly receiving non espresso messages, something wrong - // something incorrect has occured and we must panic if validatingEspressoLivenessFailure { - l1Block := message.Message.Header.BlockNumber - if wavmio.IsHotShotLive(l1Block) { - panic(fmt.Sprintf("getting the centralized message while hotshot is good, l1Height: %v", l1Block)) + // previously this was the only other branch that was checked when `validatingAgainstEspresso` + return validatingAgainstEspresso, func() { + l1Block := message.Message.Header.BlockNumber + if wavmio.IsHotShotLive(l1Block) { + panic(fmt.Sprintf("getting the centralized message while hotshot is good, l1Height: %v", l1Block)) + } } - panic("The messaged recieved by the STF is not an Espresso message, but the validator is running in Espresso mode") + } else if validatingEspressoHeightFailure { + // If conditions are such that we have been working in espresso mode, but we are suddenly receiving non espresso messages, + // something incorrect has occurred and we must panic + return validatingAgainstEspresso, func() { + panic("The messaged received by the STF is not an Espresso message, but the validator is running in Espresso mode") + } + } + panicCase := func() { + // This no-op allows us to cause no panic in the code that receives the result of this function while keeping the function signature consistent. } - return validatingAgainstEspresso + return validatingAgainstEspresso, panicCase } diff --git a/cmd/replay/main.go b/cmd/replay/main.go index 2c0fa39032..6609966bba 100644 --- a/cmd/replay/main.go +++ b/cmd/replay/main.go @@ -280,8 +280,7 @@ func main() { } // Handle the various pre-conditions and panics that can happen before we should enter the espresso logic in the validators STF - validatingAgainstEspresso := handleEspressoPreConditions(message, chainConfig.ArbitrumChainParams.EnableEspresso) - + validatingAgainstEspresso, panicHandler := handleEspressoPreConditions(message, chainConfig.ArbitrumChainParams.EnableEspresso) if validatingAgainstEspresso { txs, jst, err := arbos.ParseEspressoMsg(message.Message) if err != nil { @@ -326,6 +325,9 @@ func main() { espressocrypto.VerifyNamespace(chainConfig.ChainID.Uint64(), *jst.Proof, *jst.Header.PayloadCommitment, *jst.Header.NsTable, txs, *jst.VidCommon) } + } else { + // Call the error case closure returned by handleEspressoPreconditions() + panicHandler() } newBlock, _, err = arbos.ProduceBlock(message.Message, message.DelayedMessagesRead, lastBlockHeader, statedb, chainContext, chainConfig, batchFetcher, false) From 01f1cdb3c586f260b939a7ba7872c7a5acb73a13 Mon Sep 17 00:00:00 2001 From: Zach Showalter Date: Wed, 10 Jul 2024 11:37:33 -0400 Subject: [PATCH 6/7] return nil when we need a no-op panic handler --- cmd/replay/espresso_validation.go | 5 +---- cmd/replay/main.go | 4 +++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/cmd/replay/espresso_validation.go b/cmd/replay/espresso_validation.go index 80658596cf..fb710c69ce 100644 --- a/cmd/replay/espresso_validation.go +++ b/cmd/replay/espresso_validation.go @@ -42,8 +42,5 @@ func handleEspressoPreConditions(message *arbostypes.MessageWithMetadata, isEnab panic("The messaged received by the STF is not an Espresso message, but the validator is running in Espresso mode") } } - panicCase := func() { - // This no-op allows us to cause no panic in the code that receives the result of this function while keeping the function signature consistent. - } - return validatingAgainstEspresso, panicCase + return validatingAgainstEspresso, nil // return nil for the panic handler such that it is a no-op in the caller if no errors need occur. } diff --git a/cmd/replay/main.go b/cmd/replay/main.go index 6609966bba..3c1925fe1f 100644 --- a/cmd/replay/main.go +++ b/cmd/replay/main.go @@ -327,7 +327,9 @@ func main() { } else { // Call the error case closure returned by handleEspressoPreconditions() - panicHandler() + if panicHandler != nil { + panicHandler() + } } newBlock, _, err = arbos.ProduceBlock(message.Message, message.DelayedMessagesRead, lastBlockHeader, statedb, chainContext, chainConfig, batchFetcher, false) From 966f22cf19b8805e9e18e23aba09a844b4578187 Mon Sep 17 00:00:00 2001 From: Zach Showalter Date: Wed, 10 Jul 2024 13:19:44 -0400 Subject: [PATCH 7/7] Fix lint errors --- cmd/replay/main.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/cmd/replay/main.go b/cmd/replay/main.go index 3c1925fe1f..a9bb6554af 100644 --- a/cmd/replay/main.go +++ b/cmd/replay/main.go @@ -325,11 +325,9 @@ func main() { espressocrypto.VerifyNamespace(chainConfig.ChainID.Uint64(), *jst.Proof, *jst.Header.PayloadCommitment, *jst.Header.NsTable, txs, *jst.VidCommon) } - } else { - // Call the error case closure returned by handleEspressoPreconditions() - if panicHandler != nil { - panicHandler() - } + } else if panicHandler != nil { + // Call the error case closure returned by handleEspressoPreconditions() if it isn't nil + panicHandler() } newBlock, _, err = arbos.ProduceBlock(message.Message, message.DelayedMessagesRead, lastBlockHeader, statedb, chainContext, chainConfig, batchFetcher, false)