Skip to content

feat(cu): create config allowing to disable checkpoins without hash chain #1167

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

Open
wants to merge 1 commit 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
2 changes: 2 additions & 0 deletions servers/cu/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ There are a few environment variables that you can set. Besides
`Checkpoint` creation to the file system. (You must explicitly enable
`Checkpoint` creation by setting - `DISABLE_PROCESS_FILE_CHECKPOINT_CREATION`
to `'false'`)
- `DISABLE_NON_HASH_CHAIN_CHECKPOINTS`: Whether to disable non-hash chain
checkpoints. Set to `true` to disable non-hash chain checkpoints.
- `EAGER_CHECKPOINT_ACCUMULATED_GAS_THRESHOLD`: If a process uses this amount of
gas, then it will immediately create a Checkpoint at the end of the evaluation
stream.
Expand Down
2 changes: 2 additions & 0 deletions servers/cu/src/bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ export const createApis = async (ctx) => {
})

ctx.logger('Process Arweave Checkpoint creation is set to "%s"', !ctx.DISABLE_PROCESS_CHECKPOINT_CREATION)
ctx.logger('Disabling non-hash chain checkpoints is set to "%s"', ctx.DISABLE_NON_HASH_CHAIN_CHECKPOINTS)
ctx.logger('Process File Checkpoint creation is set to "%s"', !ctx.DISABLE_PROCESS_FILE_CHECKPOINT_CREATION)
ctx.logger('Ignoring Arweave Checkpoints for processes [ %s ]', ctx.PROCESS_IGNORE_ARWEAVE_CHECKPOINTS.join(', '))
ctx.logger('Ignoring Arweave Checkpoints [ %s ]', ctx.IGNORE_ARWEAVE_CHECKPOINTS.join(', '))
Expand Down Expand Up @@ -333,6 +334,7 @@ export const createApis = async (ctx) => {
PROCESS_IGNORE_ARWEAVE_CHECKPOINTS: ctx.PROCESS_IGNORE_ARWEAVE_CHECKPOINTS,
IGNORE_ARWEAVE_CHECKPOINTS: ctx.IGNORE_ARWEAVE_CHECKPOINTS,
PROCESS_CHECKPOINT_TRUSTED_OWNERS: ctx.PROCESS_CHECKPOINT_TRUSTED_OWNERS,
DISABLE_NON_HASH_CHAIN_CHECKPOINTS: ctx.DISABLE_NON_HASH_CHAIN_CHECKPOINTS,
logger
}),
saveLatestProcessMemory: AoProcessClient.saveLatestProcessMemoryWith({
Expand Down
2 changes: 2 additions & 0 deletions servers/cu/src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ const CONFIG_ENVS = {
DISABLE_PROCESS_CHECKPOINT_CREATION: process.env.DISABLE_PROCESS_CHECKPOINT_CREATION !== 'false',
DISABLE_PROCESS_FILE_CHECKPOINT_CREATION: process.env.DISABLE_PROCESS_FILE_CHECKPOINT_CREATION !== 'false',
DISABLE_PROCESS_EVALUATION_CACHE: process.env.DISABLE_PROCESS_EVALUATION_CACHE,
DISABLE_NON_HASH_CHAIN_CHECKPOINTS: process.env.DISABLE_NON_HASH_CHAIN_CHECKPOINTS === 'true',
/**
* EAGER_CHECKPOINT_ACCUMULATED_GAS_THRESHOLD: Amount of gas for 2 hours of continuous compute (300_000_000_000_000)
* This was calculated by creating a process built to do continuous compute. After 2 hours, this process used
Expand Down Expand Up @@ -196,6 +197,7 @@ const CONFIG_ENVS = {
DISABLE_PROCESS_CHECKPOINT_CREATION: process.env.DISABLE_PROCESS_CHECKPOINT_CREATION !== 'false',
DISABLE_PROCESS_FILE_CHECKPOINT_CREATION: process.env.DISABLE_PROCESS_FILE_CHECKPOINT_CREATION !== 'false',
DISABLE_PROCESS_EVALUATION_CACHE: process.env.DISABLE_PROCESS_EVALUATION_CACHE,
DISABLE_NON_HASH_CHAIN_CHECKPOINTS: process.env.DISABLE_NON_HASH_CHAIN_CHECKPOINTS === 'true',
/**
* EAGER_CHECKPOINT_ACCUMULATED_GAS_THRESHOLD: Amount of gas for 2 hours of continuous compute (300_000_000_000_000)
* This was calculated by creating a process built to do continuous compute by adding and clearing a table.
Expand Down
4 changes: 4 additions & 0 deletions servers/cu/src/domain/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ export const domainConfigSchema = z.object({
* a RU
*/
DISABLE_PROCESS_EVALUATION_CACHE: z.preprocess((val) => !!val, z.boolean()),
/**
* Whether to disable non-hash chain checkpoints
*/
DISABLE_NON_HASH_CHAIN_CHECKPOINTS: z.preprocess((val) => !!val, z.boolean()),
/**
* If a process uses this amount of
* gas, then it will immediately create a Checkpoint at the end of the
Expand Down
12 changes: 12 additions & 0 deletions servers/cu/src/effects/ao-process.js
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,7 @@ export function findLatestProcessMemoryWith ({
PROCESS_IGNORE_ARWEAVE_CHECKPOINTS,
IGNORE_ARWEAVE_CHECKPOINTS,
PROCESS_CHECKPOINT_TRUSTED_OWNERS,
DISABLE_NON_HASH_CHAIN_CHECKPOINTS,
logger: _logger
}) {
const logger = _logger.child('ao-process:findLatestProcessMemory')
Expand Down Expand Up @@ -852,6 +853,17 @@ export function findLatestProcessMemoryWith ({
return transduce(
compose(
map(prop('node')),
filter((node) => {
if (DISABLE_NON_HASH_CHAIN_CHECKPOINTS) {
const hasAssignment = node.tags.find((tag) => tag.name === 'Assignment')
const hasHashChain = node.tags.find((tag) => tag.name === 'Hash-Chain')
if (!hasAssignment || !hasHashChain) {
logger('Encountered Checkpoint "%s" from Arweave without Assignment or Hash-Chain. Skipping...', node.id)
return false
}
}
return true
}),
filter((node) => {
const isIgnored = isCheckpointIgnored(node.id)
if (isIgnored) logger('Encountered Ignored Checkpoint "%s" from Arweave. Skipping...', node.id)
Expand Down
105 changes: 100 additions & 5 deletions servers/cu/src/effects/ao-process.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ describe('ao-process', () => {
PROCESS_IGNORE_ARWEAVE_CHECKPOINTS: [],
IGNORE_ARWEAVE_CHECKPOINTS: [],
PROCESS_CHECKPOINT_TRUSTED_OWNERS: [],
DISABLE_NON_HASH_CHAIN_CHECKPOINTS: false,
DIR: 'fake/directory/'
}
const findLatestProcessMemory = findLatestProcessMemorySchema.implement(findLatestProcessMemoryWith(deps))
Expand Down Expand Up @@ -500,7 +501,8 @@ describe('ao-process', () => {
logger,
PROCESS_IGNORE_ARWEAVE_CHECKPOINTS: [],
IGNORE_ARWEAVE_CHECKPOINTS: [],
PROCESS_CHECKPOINT_TRUSTED_OWNERS: []
PROCESS_CHECKPOINT_TRUSTED_OWNERS: [],
DISABLE_NON_HASH_CHAIN_CHECKPOINTS: false
}
const findLatestProcessMemory = findLatestProcessMemorySchema.implement(findLatestProcessMemoryWith(deps))

Expand Down Expand Up @@ -618,6 +620,7 @@ describe('ao-process', () => {
PROCESS_IGNORE_ARWEAVE_CHECKPOINTS: [],
IGNORE_ARWEAVE_CHECKPOINTS: [],
PROCESS_CHECKPOINT_TRUSTED_OWNERS: [],
DISABLE_NON_HASH_CHAIN_CHECKPOINTS: false,
DIR: 'fake/directory/'
}
const findLatestProcessMemory = findLatestProcessMemorySchema.implement(findLatestProcessMemoryWith(deps))
Expand Down Expand Up @@ -759,7 +762,8 @@ describe('ao-process', () => {
logger,
PROCESS_IGNORE_ARWEAVE_CHECKPOINTS: [],
IGNORE_ARWEAVE_CHECKPOINTS: [],
PROCESS_CHECKPOINT_TRUSTED_OWNERS: []
PROCESS_CHECKPOINT_TRUSTED_OWNERS: [],
DISABLE_NON_HASH_CHAIN_CHECKPOINTS: false
}
const findLatestProcessMemory = findLatestProcessMemorySchema.implement(findLatestProcessMemoryWith(deps))

Expand Down Expand Up @@ -859,6 +863,7 @@ describe('ao-process', () => {
const findLatestProcessMemory = findLatestProcessMemorySchema.implement(findLatestProcessMemoryWith({
...deps,
PROCESS_CHECKPOINT_TRUSTED_OWNERS: ['wallet-123', 'wallet-456'],
DISABLE_NON_HASH_CHAIN_CHECKPOINTS: false,
queryGateway: async ({ query, variables }) => {
try {
assert.deepStrictEqual(variables, { owners: ['wallet-123', 'wallet-456'], processId: 'process-123', limit: 50 })
Expand Down Expand Up @@ -993,6 +998,91 @@ describe('ao-process', () => {
assert.deepStrictEqual(res.ordinate, '11')
})

test('should use the latest retrieved checkpoint that is NOT ignored and HAS an assignment and hash-chain', async () => {
const findLatestProcessMemory = findLatestProcessMemorySchema.implement(findLatestProcessMemoryWith({
...deps,
queryGateway: async () => ({
data: {
transactions: {
edges: [
edges[0], // node to be used
{
// node to be ignored due to 'ignored' id
node: {
...edges[0].node,
id: 'ignored',
tags: [
{ name: 'Module', value: `${cachedEval.moduleId}` },
{ name: 'Assignment', value: `${cachedEval.assignmentId}` },
{ name: 'Hash-Chain', value: `${cachedEval.hashChain}` },
{ name: 'Timestamp', value: `${cachedEval.timestamp + 1000}` },
{ name: 'Epoch', value: `${cachedEval.epoch}` },
{ name: 'Nonce', value: '12' },
{ name: 'Block-Height', value: `${cachedEval.blockHeight}` },
{ name: 'Content-Encoding', value: `${cachedEval.encoding}` }
]
}
},
{
// node to be ignored due to missing assignment and hash-chain
node: {
...edges[0].node,
id: 'tx-456',
tags: [
{ name: 'Module', value: `${cachedEval.moduleId}` },
{ name: 'Timestamp', value: `${cachedEval.timestamp + 2000}` },
{ name: 'Epoch', value: `${cachedEval.epoch}` },
{ name: 'Nonce', value: '13' },
{ name: 'Block-Height', value: `${cachedEval.blockHeight}` },
{ name: 'Content-Encoding', value: `${cachedEval.encoding}` }
]
}
},
{
// node to be ignored due to missing assignment
node: {
...edges[0].node,
id: 'tx-456',
tags: [
{ name: 'Module', value: `${cachedEval.moduleId}` },
{ name: 'Hash-Chain', value: `${cachedEval.hashChain}` },
{ name: 'Timestamp', value: `${cachedEval.timestamp + 3000}` },
{ name: 'Epoch', value: `${cachedEval.epoch}` },
{ name: 'Nonce', value: '14' },
{ name: 'Block-Height', value: `${cachedEval.blockHeight}` },
{ name: 'Content-Encoding', value: `${cachedEval.encoding}` }
]
}
},
{
// node to be ignored due to missing hash-chain
node: {
...edges[0].node,
id: 'tx-456',
tags: [
{ name: 'Module', value: `${cachedEval.moduleId}` },
{ name: 'Assignment', value: `${cachedEval.assignmentId}` },
{ name: 'Timestamp', value: `${cachedEval.timestamp + 4000}` },
{ name: 'Epoch', value: `${cachedEval.epoch}` },
{ name: 'Nonce', value: '15' },
{ name: 'Block-Height', value: `${cachedEval.blockHeight}` },
{ name: 'Content-Encoding', value: `${cachedEval.encoding}` }
]
}
}
]
}
}
}),
IGNORE_ARWEAVE_CHECKPOINTS: ['ignored'],
DISABLE_NON_HASH_CHAIN_CHECKPOINTS: true
}))

const res = await findLatestProcessMemory(target)

assert.deepStrictEqual(res.ordinate, '11')
})

test('should retry querying the gateway', async () => {
let count = 1
const findLatestProcessMemory = findLatestProcessMemorySchema.implement(findLatestProcessMemoryWith({
Expand Down Expand Up @@ -1094,7 +1184,8 @@ describe('ao-process', () => {
logger,
PROCESS_IGNORE_ARWEAVE_CHECKPOINTS: [],
IGNORE_ARWEAVE_CHECKPOINTS: [],
PROCESS_CHECKPOINT_TRUSTED_OWNERS: []
PROCESS_CHECKPOINT_TRUSTED_OWNERS: [],
DISABLE_NON_HASH_CHAIN_CHECKPOINTS: false
}
const COLDSTART = {
src: 'cold_start',
Expand Down Expand Up @@ -1170,7 +1261,8 @@ describe('ao-process', () => {
logger,
PROCESS_IGNORE_ARWEAVE_CHECKPOINTS: [],
IGNORE_ARWEAVE_CHECKPOINTS: [],
PROCESS_CHECKPOINT_TRUSTED_OWNERS: []
PROCESS_CHECKPOINT_TRUSTED_OWNERS: [],
DISABLE_NON_HASH_CHAIN_CHECKPOINTS: false
}

const findLatestProcessMemory = findLatestProcessMemorySchema.implement(findLatestProcessMemoryWith(deps))
Expand Down Expand Up @@ -1207,7 +1299,8 @@ describe('ao-process', () => {
logger,
PROCESS_IGNORE_ARWEAVE_CHECKPOINTS: [],
IGNORE_ARWEAVE_CHECKPOINTS: [],
PROCESS_CHECKPOINT_TRUSTED_OWNERS: []
PROCESS_CHECKPOINT_TRUSTED_OWNERS: [],
DISABLE_NON_HASH_CHAIN_CHECKPOINTS: false
}

const findLatestProcessMemory = findLatestProcessMemorySchema.implement(findLatestProcessMemoryWith(deps))
Expand Down Expand Up @@ -1247,6 +1340,7 @@ describe('ao-process', () => {
PROCESS_IGNORE_ARWEAVE_CHECKPOINTS: [],
IGNORE_ARWEAVE_CHECKPOINTS: [],
PROCESS_CHECKPOINT_TRUSTED_OWNERS: [],
DISABLE_NON_HASH_CHAIN_CHECKPOINTS: false,
fileExists: () => true,
DIR: 'fake/directory/'
}
Expand Down Expand Up @@ -1301,6 +1395,7 @@ describe('ao-process', () => {
logger,
PROCESS_IGNORE_ARWEAVE_CHECKPOINTS: [],
PROCESS_CHECKPOINT_TRUSTED_OWNERS: [],
DISABLE_NON_HASH_CHAIN_CHECKPOINTS: false,
fileExists: () => true,
DIR: 'fake/directory/'
}
Expand Down