Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: adds proper handling for permissionless bold chains #45

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions packages/assertion-monitor/abi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ export const boldABI = [
stateMutability: 'view',
type: 'function',
},
{
inputs: [],
name: 'baseStake',
outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
stateMutability: 'view',
type: 'function',
},
] as const

export const ASSERTION_CREATED_EVENT = {
Expand Down
4 changes: 3 additions & 1 deletion packages/assertion-monitor/alerts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export const CREATION_EVENT_STUCK_ALERT = `Assertion event stuck in challenge pe

export const NON_BOLD_NO_RECENT_CREATION_ALERT = `No recent node creation events detected for non-BOLD chain`

export const VALIDATOR_WHITELIST_DISABLED_ALERT = `Validator whitelist disabled`
export const VALIDATOR_WHITELIST_DISABLED_ALERT = `Validator whitelist disabled - this may indicate security concerns for Classic chains`

export const BOLD_LOW_BASE_STAKE_ALERT = `BoLD chain has low base stake (below 1 ETH) which may indicate restricted validation`

export const NO_CONFIRMATION_BLOCKS_WITH_CONFIRMATION_EVENTS_ALERT = `No assertion confirmation blocks found but confirmation events detected`
40 changes: 39 additions & 1 deletion packages/assertion-monitor/blockchain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
boldABI,
rollupABI,
} from './abi'
import { CHUNK_SIZE } from './constants'
import { CHUNK_SIZE, MIN_BASE_STAKE_THRESHOLD } from './constants'
import { AssertionDataError } from './errors'
import { ChainState, ConfirmationEvent, CreationEvent } from './types'
import { extractBoldBlockHash, extractClassicBlockHash } from './utils'
Expand All @@ -39,6 +39,33 @@ export async function getValidatorWhitelistDisabled(
return contract.read.validatorWhitelistDisabled()
}

/**
* Checks if the baseStake for a BoLD chain is below a threshold that would indicate
* permissionless validation might be disabled or restricted.
* A very low baseStake could indicate that validation is not intended to be permissionless.
*/
export async function fetchIsBaseStakeBelowThreshold(
client: PublicClient,
rollupAddress: string,
thresholdInWei: bigint = MIN_BASE_STAKE_THRESHOLD
): Promise<boolean> {
try {
const contract = getContract({
address: rollupAddress as `0x${string}`,
abi: boldABI,
client,
})

const baseStake = await contract.read.baseStake()
console.log(`Base stake for rollup ${rollupAddress}: ${baseStake} wei`)
return baseStake < thresholdInWei
} catch (error) {
console.error(`Error checking baseStake: ${error}`)
// Default to false if we can't check
return false
}
}

/**
* Retrieves the latest block number that has been processed by the assertion chain.
* Uses block hash from assertion data to track L2/L3 state progression.
Expand Down Expand Up @@ -345,6 +372,15 @@ export const fetchChainState = async ({
})
}

const isValidatorWhitelistDisabled = await getValidatorWhitelistDisabled(
parentClient,
childChainInfo.ethBridge.rollup
)
const isBaseStakeBelowThreshold = await fetchIsBaseStakeBelowThreshold(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this checks now both BoLD and classic chains. This is not really needed for classic chains, but if you want to have the complete information, then we should change the comment in fetchIsBaseStakeBelowThreshold, since it assumes it's a BoLD-enabled chain. Otherwise, restrict it only for BoLD chains.

parentClient,
childChainInfo.ethBridge.rollup
)

const chainState: ChainState = {
childCurrentBlock,
childLatestCreatedBlock,
Expand All @@ -354,6 +390,8 @@ export const fetchChainState = async ({
parentBlockAtConfirmation,
recentCreationEvent,
recentConfirmationEvent,
isValidatorWhitelistDisabled,
isBaseStakeBelowThreshold,
}

console.log('Built chain state blocks:', {
Expand Down
3 changes: 3 additions & 0 deletions packages/assertion-monitor/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,8 @@ export const SEARCH_WINDOW_SECONDS = MAXIMUM_SEARCH_DAYS * SECONDS_IN_A_DAY
/** Recent activity threshold in seconds (4 hours) */
export const RECENT_ACTIVITY_SECONDS = RECENT_CREATION_CHECK_HOURS * 60 * 60

/** Minimum base stake threshold for BoLD chains (1 ETH in wei) */
export const MIN_BASE_STAKE_THRESHOLD = BigInt('1000000000000000000')

/** Convert hours to seconds for timestamp comparison */
export const hoursToSeconds = (hours: number) => hours * 60 * 60
9 changes: 1 addition & 8 deletions packages/assertion-monitor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ import {
import {
createChildChainClient,
fetchChainState,
getValidatorWhitelistDisabled,
isBoldEnabled,
isBoldEnabled
} from './blockchain'
import { getBlockTimeForChain, getChainFromId } from './chains'
import {
Expand Down Expand Up @@ -141,16 +140,10 @@ export const checkChainForAssertionIssues = async (
fromBlock,
toBlock,
})
// Get validator whitelist status
const validatorWhitelistDisabled = await getValidatorWhitelistDisabled(
parentClient,
childChainInfo.ethBridge.rollup
)

const alerts = await analyzeAssertionEvents(
chainState,
childChainInfo,
validatorWhitelistDisabled,
isBold
)
if (alerts.length > 0) {
Expand Down
26 changes: 24 additions & 2 deletions packages/assertion-monitor/monitoring.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ChildNetwork as ChainInfo } from '../utils'
import {
BOLD_LOW_BASE_STAKE_ALERT,
CHAIN_ACTIVITY_WITHOUT_ASSERTIONS_ALERT,
CONFIRMATION_DELAY_ALERT,
CREATION_EVENT_STUCK_ALERT,
Expand Down Expand Up @@ -34,7 +35,6 @@ import { isEventRecent } from './utils'
export const analyzeAssertionEvents = async (
chainState: ChainState,
chainInfo: ChainInfo,
validatorWhitelistDisabled: boolean,
isBold: boolean = true
): Promise<string[]> => {
const alerts: string[] = []
Expand All @@ -48,12 +48,18 @@ export const analyzeAssertionEvents = async (
confirmationDelayExceedsPeriod,
creationEventStuckInChallengePeriod,
nonBoldMissingRecentCreation,
isValidatorWhitelistDisabledOnClassic,
isBaseStakeBelowThresholdOnBold,
} = generateConditionsForAlerts(chainInfo, chainState, isBold)

if (validatorWhitelistDisabled) {
if (isValidatorWhitelistDisabledOnClassic) {
alerts.push(VALIDATOR_WHITELIST_DISABLED_ALERT)
}

if (isBaseStakeBelowThresholdOnBold) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the same thing still happens here, since it's not checking if the validator whitelist is disabled AND the baseStake is below the threshold 😅

alerts.push(BOLD_LOW_BASE_STAKE_ALERT)
}

if (!doesLatestChildCreatedBlockExist) {
alerts.push(NO_CREATION_EVENTS_ALERT)
}
Expand Down Expand Up @@ -214,6 +220,20 @@ export const generateConditionsForAlerts = (
(!childLatestCreatedBlock ||
(!hasRecentCreationEvents && hasActivityWithoutAssertions))

/**
* Whether a Classic chain's validator whitelist is disabled, allowing
* unauthorized validators to post assertions.
*/
const isValidatorWhitelistDisabledOnClassic =
!isBold && chainState.isValidatorWhitelistDisabled

/**
* Whether a BoLD chain's base stake is below threshold, indicating restricted
* validator participation in dispute resolution.
*/
const isBaseStakeBelowThresholdOnBold =
isBold && chainState.isBaseStakeBelowThreshold

return {
doesLatestChildCreatedBlockExist,
doesLatestChildConfirmedBlockExist,
Expand All @@ -224,5 +244,7 @@ export const generateConditionsForAlerts = (
confirmationDelayExceedsPeriod,
creationEventStuckInChallengePeriod,
nonBoldMissingRecentCreation,
isValidatorWhitelistDisabledOnClassic,
isBaseStakeBelowThresholdOnBold,
}
}
2 changes: 2 additions & 0 deletions packages/assertion-monitor/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,6 @@ export interface ChainState {
parentBlockAtConfirmation?: Block
recentCreationEvent: CreationEvent | null
recentConfirmationEvent: ConfirmationEvent | null
isValidatorWhitelistDisabled: boolean
isBaseStakeBelowThreshold: boolean
}