Skip to content

Commit

Permalink
feat(cu)!: validate proper tags on process #205
Browse files Browse the repository at this point in the history
  • Loading branch information
TillaTheHun0 committed Dec 12, 2023
1 parent 436863a commit 84d4368
Show file tree
Hide file tree
Showing 13 changed files with 142 additions and 142 deletions.
2 changes: 1 addition & 1 deletion servers/cu/src/domain/client/ao-su.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Transform, pipeline } from 'node:stream'
import { of } from 'hyper-async'
import { always, applySpec, evolve, filter, isNotNil, last, path, pathOr, pipe, prop } from 'ramda'

import { findRawTag, padBlockHeight } from '../lib/utils.js'
import { findRawTag, padBlockHeight } from '../utils.js'

export const loadMessagesWith = ({ fetch, SU_URL, logger: _logger, pageSize }) => {
const logger = _logger.child('ao-su:loadMessages')
Expand Down
4 changes: 2 additions & 2 deletions servers/cu/src/domain/lib/evaluate.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const ctxSchema = z.object({
*/

function addHandler (ctx) {
return of(ctx.src)
return of(ctx.module)
.chain(fromPromise(AoLoader))
.map((handle) => ({ handle, ...ctx }))
}
Expand Down Expand Up @@ -64,7 +64,7 @@ function doesMessageIdExistWith ({ findMessageId }) {
* @property {string} id - the contract id
* @property {Record<string, any>} state - the initial state
* @property {string} from - the initial state sortKey
* @property {ArrayBuffer} src - the contract wasm as an array buffer
* @property {ArrayBuffer} module - the contract wasm as an array buffer
* @property {Record<string, any>[]} action - an array of interactions to apply
*
* @callback Evaluate
Expand Down
16 changes: 8 additions & 8 deletions servers/cu/src/domain/lib/evaluate.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('evaluate', () => {
ctx = {
id: 'ctr-1234',
from: 'sort-key-start',
src: readFileSync('./test/processes/happy/process.wasm'),
module: readFileSync('./test/processes/happy/process.wasm'),
buffer: null,
messages: toAsyncIterable([
{
Expand Down Expand Up @@ -142,7 +142,7 @@ describe('evaluate', () => {
const ctx = {
id: 'ctr-1234',
from: 'sort-key-start',
src: readFileSync('./test/processes/happy/process.wasm'),
module: readFileSync('./test/processes/happy/process.wasm'),
buffer: null,
messages: toAsyncIterable([
{
Expand Down Expand Up @@ -197,7 +197,7 @@ describe('evaluate', () => {
const ctx = {
id: 'ctr-1234',
from: 'sort-key-start',
src: readFileSync('./test/processes/happy/process.wasm'),
module: readFileSync('./test/processes/happy/process.wasm'),
buffer: null,
messages: toAsyncIterable([
{
Expand Down Expand Up @@ -255,7 +255,7 @@ describe('evaluate', () => {
const ctx = {
id: 'ctr-1234',
from: 'sort-key-start',
src: readFileSync('./test/processes/happy/process.wasm'),
module: readFileSync('./test/processes/happy/process.wasm'),
/**
* In reality this would be an illegible byte array, since it's format
* will be determined by whatever the underlying runtime is, in this case,
Expand Down Expand Up @@ -291,7 +291,7 @@ describe('evaluate', () => {
const ctx = {
id: 'ctr-1234',
from: 'sort-key-start',
src: readFileSync('./test/processes/sad/process.wasm'),
module: readFileSync('./test/processes/sad/process.wasm'),
buffer: Buffer.from('Hello', 'utf-8'),
messages: toAsyncIterable([
{
Expand Down Expand Up @@ -338,7 +338,7 @@ describe('evaluate', () => {
const ctx = {
id: 'ctr-1234',
from: 'sort-key-start',
src: readFileSync('./test/processes/sad/process.wasm'),
module: readFileSync('./test/processes/sad/process.wasm'),
buffer: Buffer.from('Hello', 'utf-8'),
messages: toAsyncIterable([
{
Expand Down Expand Up @@ -378,7 +378,7 @@ describe('evaluate', () => {
const ctx = {
id: 'ctr-1234',
from: 'sort-key-start',
src: readFileSync('./test/processes/sad/process.wasm'),
module: readFileSync('./test/processes/sad/process.wasm'),
buffer: Buffer.from('Hello', 'utf-8'),
messages: toAsyncIterable([
{
Expand Down Expand Up @@ -417,7 +417,7 @@ describe('evaluate', () => {
const ctx = {
id: 'ctr-1234',
from: 'sort-key-start',
src: readFileSync('./test/processes/sad/process.wasm'),
module: readFileSync('./test/processes/sad/process.wasm'),
buffer: null,
messages: toAsyncIterable([
{
Expand Down
2 changes: 1 addition & 1 deletion servers/cu/src/domain/lib/hydrateMessages.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import WarpArBundles from 'warp-arbundles'

import { loadTransactionDataSchema, loadTransactionMetaSchema } from '../dal.js'
import { streamSchema } from '../model.js'
import { findRawTag } from './utils.js'
import { findRawTag } from '../utils.js'

const { createData } = WarpArBundles

Expand Down
2 changes: 1 addition & 1 deletion servers/cu/src/domain/lib/loadMessages.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import ms from 'ms'

import { messageSchema, streamSchema } from '../model.js'
import { loadBlocksMetaSchema, loadMessagesSchema, loadTimestampSchema } from '../dal.js'
import { padBlockHeight } from './utils.js'
import { padBlockHeight } from '../utils.js'

/**
* - { name: 'Cron-Interval', value: 'interval' }
Expand Down
3 changes: 2 additions & 1 deletion servers/cu/src/domain/lib/loadMessages.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import * as assert from 'node:assert'
import ms from 'ms'
import { countBy, prop, uniqBy } from 'ramda'

import { padBlockHeight } from '../utils.js'

import { CRON_INTERVAL, parseCrons, isBlockOnSchedule, isTimestampOnSchedule, scheduleMessagesBetweenWith } from './loadMessages.js'
import { padBlockHeight } from './utils.js'

describe('loadMessages', () => {
describe('parseCrons', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { mergeRight, prop } from 'ramda'
import { z } from 'zod'

import { loadTransactionDataSchema } from '../dal.js'
import { parseTags } from './utils.js'
import { parseTags } from '../utils.js'

/**
* The result that is produced from this step
Expand All @@ -13,26 +13,26 @@ import { parseTags } from './utils.js'
* is always added to context
*/
const ctxSchema = z.object({
src: z.any().refine((val) => !!val, {
message: 'process src must be attached to context'
module: z.any().refine((val) => !!val, {
message: 'process module must be attached to context'
}),
srcId: z.string().refine((val) => !!val, {
message: 'process srcId must be attached to context'
moduleId: z.string().refine((val) => !!val, {
message: 'process moduleId must be attached to context'
})
}).passthrough()

function getSourceBufferWith ({ loadTransactionData }) {
function getModuleBufferWith ({ loadTransactionData }) {
loadTransactionData = fromPromise(loadTransactionDataSchema.implement(loadTransactionData))

return (tags) => {
return of(tags)
.map(parseTags)
.map(prop('Contract-Src'))
.chain(srcId =>
of(srcId)
.map(prop('Module'))
.chain(moduleId =>
of(moduleId)
.chain(loadTransactionData)
.chain(fromPromise((res) => res.arrayBuffer()))
.map(src => ({ src, srcId }))
.map(module => ({ module, moduleId }))
)
}
}
Expand All @@ -42,25 +42,25 @@ function getSourceBufferWith ({ loadTransactionData }) {
* @property {string} id - the id of the process
*
* @typedef Result
* @property {string} srcId - the id of the process source
* @property {ArrayBuffer} src - an array buffer that contains the Contract Wasm Src
* @property {string} moduleId - the id of the process source
* @property {ArrayBuffer} module - an array buffer that contains the Contract Wasm Src
*
* @callback LoadSource
* @callback LoadModule
* @param {Args} args
* @returns {Async<Result & Args>}
*
* @param {any} env
* @returns {LoadSource}
* @returns {LoadModule}
*/
export function loadSourceWith (env) {
const logger = env.logger.child('loadSource')
export function loadModuleWith (env) {
const logger = env.logger.child('loadModule')
env = { ...env, logger }

const getSourceBuffer = getSourceBufferWith(env)
const getModuleBuffer = getModuleBufferWith(env)

return (ctx) => {
return of(ctx.tags)
.chain(getSourceBuffer)
.chain(getModuleBuffer)
.map(mergeRight(ctx))
.map(ctxSchema.parse)
.map(ctx => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@ import { describe, test } from 'node:test'
import * as assert from 'node:assert'

import { createLogger } from '../logger.js'
import { loadSourceWith } from './loadSource.js'
import { loadModuleWith } from './loadModule.js'

const PROCESS = 'contract-123-9HdeqeuYQOgMgWucro'
const logger = createLogger('ao-cu:readState')

describe('loadSource', () => {
test('append process source and process source id', async () => {
const loadSource = loadSourceWith({
describe('loadModule', () => {
test('append module and module id', async () => {
const loadModule = loadModuleWith({
loadTransactionData: async (_id) =>
new Response(JSON.stringify({ hello: 'world' })),
logger
})

const result = await loadSource({ id: PROCESS, tags: [{ name: 'Contract-Src', value: 'foobar' }] }).toPromise()
assert.equal(result.src.byteLength, 17)
assert.equal(result.srcId, 'foobar')
const result = await loadModule({ id: PROCESS, tags: [{ name: 'Module', value: 'foobar' }] }).toPromise()
assert.equal(result.module.byteLength, 17)
assert.equal(result.moduleId, 'foobar')
assert.equal(result.id, PROCESS)
})
})
26 changes: 9 additions & 17 deletions servers/cu/src/domain/lib/loadProcess.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { Rejected, Resolved, fromPromise, of } from 'hyper-async'
import { F, T, always, cond, equals, includes, is, isNotNil, mergeRight, omit } from 'ramda'
import { always, isNotNil, mergeRight, omit } from 'ramda'
import { z } from 'zod'

import { findLatestEvaluationSchema, findProcessSchema, loadProcessSchema, saveProcessSchema } from '../dal.js'
import { rawBlockSchema, rawTagSchema } from '../model.js'
import { parseTags } from './utils.js'
import { eqOrIncludes, parseTags } from '../utils.js'

function getProcessMetaWith ({ loadProcess, findProcess, saveProcess, logger }) {
findProcess = fromPromise(findProcessSchema.implement(findProcess))
saveProcess = fromPromise(saveProcessSchema.implement(saveProcess))
loadProcess = fromPromise(loadProcessSchema.implement(loadProcess))

const checkTag = (name, pred) => (tags) => pred(tags[name])
const checkTag = (name, pred, err) => tags => pred(tags[name])
? Resolved(tags)
: Rejected(`Tag '${name}' of value '${tags[name]}' was not valid on transaction`)
: Rejected(`Tag '${name}': ${err}`)

/**
* Load the process from the SU, extracting the metadata,
Expand All @@ -27,17 +27,9 @@ function getProcessMetaWith ({ loadProcess, findProcess, saveProcess, logger })
.chain(ctx =>
of(ctx.tags)
.map(parseTags)
/**
* The process could implement multiple Data-Protocols,
* so check in the case of a single value or an array of values
*/
.chain(checkTag('Data-Protocol', cond([
[is(String), equals('ao')],
[is(Array), includes('ao')],
[T, F]
])))
.chain(checkTag('ao-type', equals('process')))
.chain(checkTag('Contract-Src', isNotNil))
.chain(checkTag('Data-Protocol', eqOrIncludes('ao'), 'value \'ao\' was not found on process'))
.chain(checkTag('Type', eqOrIncludes('Process'), 'value \'Process\' was not found on process'))
.chain(checkTag('Module', isNotNil, 'was not found on process'))
.map(always({ id: processId, ...ctx }))
.bimap(
logger.tap('Verifying process failed: %s'),
Expand Down Expand Up @@ -175,10 +167,10 @@ const ctxSchema = z.object({

/**
* @typedef Args
* @property {string} id - the id of the contract
* @property {string} id - the id of the process
*
* @typedef Result
* @property {string} id - the id of the contract
* @property {string} id - the id of the process
* @property {string} owner
* @property {any} tags
* @property {{ height: number, timestamp: number }} block
Expand Down
Loading

0 comments on commit 84d4368

Please sign in to comment.