Skip to content

Commit

Permalink
Add random chance to panic mode
Browse files Browse the repository at this point in the history
  • Loading branch information
janezpodhostnik committed Jun 10, 2024
1 parent 1b212b9 commit e203a59
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 22 deletions.
121 changes: 102 additions & 19 deletions contracts/DependencyAudit.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -41,27 +41,99 @@ access(all) contract DependencyAudit {
}

if unstagedDependencies.length > 0 {
if DependencyAudit.panicOnUnstaged {
// If `panicOnUnstaged` is set to true, the transaction will panic if there are any unstaged dependencies
// the panic message will include the unstaged dependencies
var unstagedDependenciesString = ""
var numUnstagedDependencies = unstagedDependencies.length
var j = 0
while j < numUnstagedDependencies {
if j > 0 {
unstagedDependenciesString = unstagedDependenciesString.concat(", ")
}
unstagedDependenciesString = unstagedDependenciesString.concat(unstagedDependencies[j].toString())

j = j + 1
}

// the transactions will fail with a message that looks like this: `error: panic: Found unstaged dependencies: A.2ceae959ed1a7e7a.MigrationContractStaging, A.2ceae959ed1a7e7a.DependencyAudit`
panic("This transaction is using dependencies not staged for Crescendo upgrade coming soon! Learn more: https://bit.ly/FLOWCRESCENDO. Dependencies not staged: ".concat(unstagedDependenciesString))
} else {
emit UnstagedDependencies(dependencies: unstagedDependencies)
self.maybePanicOnUnstagedDependencies(unstagedDependencies)

emit UnstagedDependencies(dependencies: unstagedDependencies)
}
}

access(self) fun maybePanicOnUnstagedDependencies(_ unstagedDependencies: [Dependency]) {
// If `panicOnUnstaged` is set to false, the function will return without panicking
if !DependencyAudit.panicOnUnstaged {
return
}

// check if we should panic randomly
if !self.shouldPanicRandomly() {
return
}

var unstagedDependenciesString = ""
var numUnstagedDependencies = unstagedDependencies.length
var j = 0
while j < numUnstagedDependencies {
if j > 0 {
unstagedDependenciesString = unstagedDependenciesString.concat(", ")
}
unstagedDependenciesString = unstagedDependenciesString.concat(unstagedDependencies[j].toString())

j = j + 1
}

// the transactions will fail with a message that looks like this: `error: panic: Found unstaged dependencies: A.2ceae959ed1a7e7a.MigrationContractStaging, A.2ceae959ed1a7e7a.DependencyAudit`
panic("This transaction is using dependencies not staged for Crescendo upgrade coming soon! Learn more: https://bit.ly/FLOWCRESCENDO. Dependencies not staged: ".concat(unstagedDependenciesString))
}

// shouldPanicRandomly is used to randomly panic on unstaged dependencies
// The probability of panicking is based on the current block height and the start and end block heights
// If the start block height is greater than or equal to the end block height, the function will return true
// The function will always return true if the current block is more than the end block height
// The function will always return false if the current block is less than the start block height
// The function will return true if a random number between the start and end block heights is less than the current block height
// This means the probability of panicking increases linearly as the current block height approaches the end block height
access(self) fun shouldPanicRandomly(): Bool {
// get start block height or true
// get end block height or true
// get current block height
// get random number between start and end
// if random number is less than current block return true
// else return false
let maybeBoundaries = self.getBoundaries()
if maybeBoundaries == nil {
// if settings are invalid use default behaviour: panic true
return true
}
let boundaries = maybeBoundaries!

let startBlock: UInt64 = boundaries.start
let endBlock: UInt64 = boundaries.end
let currentBlock: UInt64 = getCurrentBlock().height

if startBlock >= endBlock {
// if settings are invalid use default behaviour: panic true
return true
}

let dif = endBlock - startBlock
var rnd = revertibleRandom() % dif
rnd = rnd + startBlock

// fail if the random number is less than the current block
return rnd < currentBlock
}

access(all) struct Boundaries {
access(all) let start: UInt64
access(all) let end: UInt64

init(start: UInt64, end: UInt64) {
self.start = start
self.end = end
}
}

access(self) fun getBoundaries(): Boundaries? {
return self.account.copy<Boundaries>(from: /storage/flowDependencyAuditBoundaries)
}

access(self) fun setBoundaries(boundaries: Boundaries) {
self.account.load<Boundaries>(from: /storage/flowDependencyAuditBoundaries)
self.account.save(boundaries, to: /storage/flowDependencyAuditBoundaries)
}

access(self) fun unsetBoundaries() {
self.account.load<Boundaries>(from: /storage/flowDependencyAuditBoundaries)
}

// The Administrator resorce can be used to add or remove addresses from the excludedAddresses dictionary
Expand All @@ -87,6 +159,17 @@ access(all) contract DependencyAudit {
emit PanicOnUnstagedDependenciesChanged(shouldPanic: shouldPanic)
}

// setStartEndBlock sets the start and end block heights for the `shouldPanicRandomly` function
access(all) fun setStartEndBlock(start: UInt64, end: UInt64) {
let boundaries = Boundaries(start: start, end: end)
DependencyAudit.setBoundaries(boundaries: boundaries)
}

// unsetStartEndBlock unsets the start and end block heights for the `shouldPanicRandomly` function
access(all) fun unsetStartEndBlock() {
DependencyAudit.unsetBoundaries()
}

// testCheckDependencies is used for testing purposes
// It will call the `checkDependencies` function with the provided dependencies
// `checkDependencies` is otherwise not callable from the outside
Expand Down
Loading

0 comments on commit e203a59

Please sign in to comment.