diff --git a/.github/workflows/weavedrive.yml b/.github/workflows/weavedrive.yml new file mode 100644 index 00000000..f76c85de --- /dev/null +++ b/.github/workflows/weavedrive.yml @@ -0,0 +1,109 @@ +name: πŸ§ΆπŸ’Ύ Build & Release WeaveDrive + +on: + pull_request: + branches: + - main + paths: + - "extensions/weavedrive/**" + push: + branches: + - main + paths: + - "extensions/weavedrive/**" + + # Perform a release using a workflow dispatch + workflow_dispatch: + inputs: + version: + description: "semver version to bump to" + required: true + +defaults: + run: + shell: bash + +jobs: + test: + if: github.event_name != 'workflow_dispatch' + runs-on: ubuntu-latest + steps: + - name: ⬇️ Checkout repo + uses: actions/checkout@v4 + + - name: βŽ” Setup node + uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: πŸ“₯ Download deps + working-directory: extensions/weavedrive + run: | + npm i + + - name: ⚑ Run Tests + working-directory: extensions/weavedrive + run: | + npm test + env: + CI: true + + release: + # Releases are performed via a workflow dispatch + if: github.event_name == 'workflow_dispatch' + runs-on: ubuntu-latest + timeout-minutes: 10 + concurrency: + group: release + steps: + - name: ⬇️ Checkout repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: main + + - name: βŽ” Setup node + uses: actions/setup-node@v4 + with: + node-version: 22 + registry-url: "https://registry.npmjs.org" + + - name: πŸ‘€ Env + run: | + echo "Event name: ${{ github.event_name }}" + echo "Git ref: ${{ github.ref }}" + echo "GH actor: ${{ github.actor }}" + echo "SHA: ${{ github.sha }}" + VER=`node --version`; echo "Node ver: $VER" + VER=`npm --version`; echo "npm ver: $VER" + + - name: πŸ€“ Set Git User + run: | + git config --global user.name "${{ github.actor }}" + git config --global user.email "${{ github.actor }}@users.noreply.github.com" + + - name: ✊ Bump + id: bump + uses: hyper63/hyper-ci-bump@v2.1.0 + with: + bump-to: ${{ github.event.inputs.version }} + package: weavedrive + + - name: ⬆️ Push + run: | + git push + git push --tags + + - name: πŸ“₯ Download deps + working-directory: extensions/weavedrive + run: | + npm i + + # Build aos + - name: 🦠 Publish to NPM + working-directory: extensions/weavedrive + run: | + npm run build + npm publish --access=public + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/extensions/weavedrive/package-lock.json b/extensions/weavedrive/package-lock.json index 20ede3e3..cb280fd8 100644 --- a/extensions/weavedrive/package-lock.json +++ b/extensions/weavedrive/package-lock.json @@ -12,7 +12,7 @@ "arweave": "^1.15.5" }, "devDependencies": { - "@permaweb/ao-loader": "^0.0.39", + "@permaweb/ao-loader": "^0.0.43", "esbuild": "^0.24.0" } }, @@ -425,9 +425,9 @@ } }, "node_modules/@permaweb/ao-loader": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@permaweb/ao-loader/-/ao-loader-0.0.39.tgz", - "integrity": "sha512-VPY26/6/RDfVQ9jIhEGrO55FDB9RWjHn5YUkfltGB6fXIScPdPifsSbtTMWhJAjO+ZcamTPkSk6F02hw7VGARg==", + "version": "0.0.43", + "resolved": "https://registry.npmjs.org/@permaweb/ao-loader/-/ao-loader-0.0.43.tgz", + "integrity": "sha512-xPYzyKSCqtL0U8oUcCrW+uPpm7IcMncM5IPVGCGKljxA3IQA/HI8S5XA6tcZUaDRCl8VSVsJzqOgkdzy1JGi5w==", "dev": true, "dependencies": { "@permaweb/wasm-metering": "^0.2.2" diff --git a/extensions/weavedrive/package.json b/extensions/weavedrive/package.json index fb4d2f88..3b14bcf3 100644 --- a/extensions/weavedrive/package.json +++ b/extensions/weavedrive/package.json @@ -14,7 +14,7 @@ "arweave": "^1.15.5" }, "devDependencies": { - "@permaweb/ao-loader": "^0.0.39", + "@permaweb/ao-loader": "^0.0.43", "esbuild": "^0.24.0" } } diff --git a/extensions/weavedrive/src/index.js b/extensions/weavedrive/src/index.js index a06e83dc..84d7bb92 100644 --- a/extensions/weavedrive/src/index.js +++ b/extensions/weavedrive/src/index.js @@ -441,7 +441,7 @@ module.exports = function weaveDrive(mod, FS) { const blockHeight = mod.blockHeight const moduleExtensions = this.getTagValues("Extension", mod.module.tags) const moduleHasWeaveDrive = moduleExtensions.includes("WeaveDrive") - const processExtensions = this.getTagValues("Extension", mod.module.tags) + const processExtensions = this.getTagValues("Extension", mod.spawn.tags) const processHasWeaveDrive = moduleHasWeaveDrive || processExtensions.includes("WeaveDrive") if (!processHasWeaveDrive) { @@ -471,7 +471,7 @@ module.exports = function weaveDrive(mod, FS) { [ this.getTagValue('Scheduler', mod.spawn.tags), ...this.getTagValues("Attestor", mod.spawn.tags) - ] + ].filter(t => !!t) ) // Init a set of GraphQL queries to run in order to find a valid attestation @@ -510,7 +510,7 @@ module.exports = function weaveDrive(mod, FS) { owners: ${attestors}, block: {min: 0, max: ${blockHeight}}, tags: [ - { name: "Data-Protocol", values: ["WeaveDrive"], + { name: "Data-Protocol", values: ["WeaveDrive"] }, { name: "Type", values: ["Available"]}, { name: "ID", values: ["${ID}"]} ] @@ -564,10 +564,11 @@ module.exports = function weaveDrive(mod, FS) { return values.pop() }, - async queryHasResult(query) { - const results = await mod.arweave.api.post('/graphql', query); - const json = JSON.parse(results) - return json.data.transactions.edges.length > 0 + async queryHasResult(query, variables) { + const json = await this.gqlQuery(query, variables) + .then((res) => res.json()) + + return !!json?.data?.transactions?.edges?.length }, async gqlExists() { diff --git a/extensions/weavedrive/test/index.test.js b/extensions/weavedrive/test/index.test.js index 15facd1f..9adcb5f7 100644 --- a/extensions/weavedrive/test/index.test.js +++ b/extensions/weavedrive/test/index.test.js @@ -1,6 +1,6 @@ const AoLoader = require('@permaweb/ao-loader') const fs = require('fs') -const { test } = require('node:test') +const { describe, test } = require('node:test') const assert = require('assert') const weaveDrive = require('../src/index.js') const wasm = fs.readFileSync('./process.wasm') @@ -28,7 +28,7 @@ const Process = { { name: 'Type', value: 'Process' }, { name: 'Extension', value: 'WeaveDrive' }, { name: 'Module', value: 'MODULE' }, - { name: 'Authority', value: 'PROCESS' }, + { name: 'Authority', value: 'PROCESS' } ] } @@ -47,8 +47,6 @@ const Msg = { Timestamp: Date.now() } -const BootLoadedFromTx = 'Fmtgzy1Chs-5ZuUwHpQjQrQ7H7v1fjsP0Bi8jVaDIKA' - const options = { format: 'wasm64-unknown-emscripten-draft_2024_02_15', WeaveDrive: weaveDrive, @@ -56,19 +54,17 @@ const options = { mode: "test", blockHeight: 1000, spawn: { - tags: [ - { name: 'Scheduler', value: 'TEST_SCHED_ADDR' }, - { name: 'On-Boot', value: BootLoadedFromTx } - ], + tags: Process.Tags }, module: { - tags: [] + tags: Module.Tags } } +const drive = fs.readFileSync('./client/main.lua', 'utf-8') + test('load client source', async () => { const handle = await AoLoader(wasm, options) - const drive = fs.readFileSync('./client/main.lua', 'utf-8') const result = await handle(memory, { ...Msg, Data: ` @@ -153,6 +149,154 @@ return require('json').encode({ A = #results, B = #results2 }) assert.equal(res.A, res.B) }) +describe('Assignments mode', () => { + const TX_ID_TO_LOAD = 'iaiAqmcYrviugZq9biUZKJIAi_zIT_mgFHAWZzMvDuk' + const blockHeight = 1536315 + const mode = 'Assignments' + + const ProcessAssignmentsMode = { + Id: 'PROCESS', + Owner: 'PROCESS', + Target: 'PROCESS', + Tags: [ + { name: 'Data-Protocol', value: 'ao' }, + { name: 'Variant', value: 'ao.TN.1' }, + { name: 'Type', value: 'Process' }, + { name: 'Extension', value: 'WeaveDrive' }, + { name: 'Module', value: 'MODULE' }, + { name: 'Authority', value: 'PROCESS' }, + { name: 'Availability-Type', value: mode } + ], + Data: `Test = 1`, + From: 'PROCESS', + Module: 'MODULE', + "Block-Height": 4567, + Timestamp: Date.now() + } + + test('read tx attested by Scheduler', async () => { + ProcessSchedulerAttested = { + ...ProcessAssignmentsMode, + Tags: [ + ...ProcessAssignmentsMode.Tags, + { name: 'Scheduler', value: 'kdUCABg56Jroco1kMwfF-YIjah9wBbZ1BhyOnwLwOY0' }, + ] + } + + const handle = await AoLoader(wasm, { + ...options, spawn: { + id: ProcessSchedulerAttested.Id, + owner: ProcessSchedulerAttested.Owner, + tags: ProcessSchedulerAttested.Tags + }, + mode + }) + const result = await handle(null, { + ...Msg, + 'Block-Height': blockHeight + 2, + Data: ` + local function _load() ${drive} end + _G.package.loaded['WeaveDrive'] = _load() + local drive = require('WeaveDrive') + return drive.getData("${TX_ID_TO_LOAD}") + ` + }, { Process: ProcessSchedulerAttested, Module }) + + assert.equal(result.Output.data, 'hello from attested') + }) + + test('read tx attested by Attestor', async () => { + const ProcessAttestorAttested = { + ...ProcessAssignmentsMode, + Tags: [ + ...ProcessAssignmentsMode.Tags, + { name: 'Scheduler', value: 'something-else' }, + { name: 'Attestor', value: 'kdUCABg56Jroco1kMwfF-YIjah9wBbZ1BhyOnwLwOY0' }, + ] + } + + const handle = await AoLoader(wasm, { + ...options, + spawn: { + id: ProcessAttestorAttested.Id, + owner: ProcessAttestorAttested.Owner, + tags: ProcessAttestorAttested.Tags + }, + mode + }) + const result = await handle(null, { + ...Msg, + 'Block-Height': blockHeight + 2, + Data: ` + local function _load() ${drive} end + _G.package.loaded['WeaveDrive'] = _load() + local drive = require('WeaveDrive') + return drive.getData("${TX_ID_TO_LOAD}") + ` + }, { Process: ProcessAttestorAttested, Module }) + + assert.equal(result.Output.data, 'hello from attested') + }) +}) + +describe('Individual Mode', () => { + const TX_ID_TO_LOAD = 'msEHJnwpmxR0RP-YqeCk91l_x8O9QNOP8RZYG_1prYE' + const blockHeight = 1536315 + const mode = 'Individual' + + const ProcessIndividualMode = { + Id: 'PROCESS', + Owner: 'PROCESS', + Target: 'PROCESS', + Tags: [ + { name: 'Data-Protocol', value: 'ao' }, + { name: 'Variant', value: 'ao.TN.1' }, + { name: 'Type', value: 'Process' }, + { name: 'Extension', value: 'WeaveDrive' }, + { name: 'Module', value: 'MODULE' }, + { name: 'Authority', value: 'PROCESS' }, + { name: 'Availability-Type', value: mode }, + ], + Data: `Test = 1`, + From: 'PROCESS', + Module: 'MODULE', + "Block-Height": 4567, + Timestamp: Date.now() + } + + test('read tx attested by Scheduler', async () => { + const ProcessSchedulerAttested = { + ...ProcessIndividualMode, + Tags: [ + ...ProcessIndividualMode.Tags, + { name: 'Scheduler', value: 'kdUCABg56Jroco1kMwfF-YIjah9wBbZ1BhyOnwLwOY0' }, + ] + } + + const handle = await AoLoader(wasm, { + ...options, + spawn: { + id: ProcessSchedulerAttested.Id, + owner: ProcessSchedulerAttested.Owner, + tags: ProcessSchedulerAttested.Tags + }, + mode + }) + const result = await handle(null, { + ...Msg, + 'Block-Height': blockHeight + 2, + Data: ` + local function _load() ${drive} end + _G.package.loaded['WeaveDrive'] = _load() + local drive = require('WeaveDrive') + return drive.getData("${TX_ID_TO_LOAD}") + ` + }, { Process: ProcessSchedulerAttested, Module }) + + assert.equal(result.Output.data, '1234') + }) +}) + // test weavedrive feature of acceptint multiple gateways test('read block, multi url', async () => { const handle = await AoLoader(wasm, { @@ -225,7 +369,6 @@ return result }, { Process, Module }) memory = result.Memory - console.log({ result }) assert.equal(result.Output.data, '') }) @@ -247,72 +390,79 @@ return result assert.equal(result.Output.data, '') }) -let memoryBootLoader = null - -/* - * The Process is also the first message when aop 6 boot loader - * is enabled in the network - */ -const ProcessBootLoaderData = { - Id: 'PROCESS', - Owner: 'PROCESS', - Target: 'PROCESS', - Tags: [ - { name: 'Data-Protocol', value: 'ao' }, - { name: 'Variant', value: 'ao.TN.1' }, - { name: 'Type', value: 'Process' }, - { name: 'Extension', value: 'WeaveDrive' }, - { name: 'On-Boot', value: 'Data' }, - { name: 'Module', value: 'MODULE' }, - { name: 'Authority', value: 'PROCESS' } - ], - Data: ` -Test = 1 -print("Test " .. Test) - `, - From: 'PROCESS', - Module: 'MODULE', - "Block-Height": 1000, - Timestamp: Date.now() -} +test('boot loader set to Data', async function () { + /** + * The Process is also the first message when aop 6 boot loader + * is enabled in the network + */ + const ProcessBootLoaderData = { + Id: 'PROCESS', + Owner: 'PROCESS', + Target: 'PROCESS', + Tags: [ + { name: 'Data-Protocol', value: 'ao' }, + { name: 'Variant', value: 'ao.TN.1' }, + { name: 'Type', value: 'Process' }, + { name: 'Extension', value: 'WeaveDrive' }, + { name: 'On-Boot', value: 'Data' }, + { name: 'Module', value: 'MODULE' }, + { name: 'Authority', value: 'PROCESS' } + ], + Data: ` + Test = 1 + print("Test " .. Test) + `, + From: 'PROCESS', + Module: 'MODULE', + "Block-Height": 1234, + Timestamp: Date.now() + } -const optionsBootLoaderData = { ...options, mode: null } + const optionsBootLoaderData = { ...options, mode: null } -test('boot loader set to Data', async function () { const handle = await AoLoader(bootLoaderWasm, optionsBootLoaderData) - const result = await handle(memoryBootLoader, { + const result = await handle(null, { ...ProcessBootLoaderData }, { Process: ProcessBootLoaderData, Module }) assert.equal(result.Output.data, 'Test 1') }) -const ProcessBootLoaderTx = { - Id: 'PROCESS', - Owner: 'PROCESS', - Target: 'PROCESS', - Tags: [ - { name: 'Data-Protocol', value: 'ao' }, - { name: 'Variant', value: 'ao.TN.1' }, - { name: 'Type', value: 'Process' }, - { name: 'Extension', value: 'WeaveDrive' }, - { name: 'On-Boot', value: BootLoadedFromTx }, - { name: 'Module', value: 'MODULE' }, - { name: 'Authority', value: 'PROCESS' } - ], - Data: ` -Test = 1 - `, - From: 'PROCESS', - Module: 'MODULE', - "Block-Height": 1000, - Timestamp: Date.now() -} +test('boot loader set to tx id', async function () { + const BootLoadedFromTx = 'Fmtgzy1Chs-5ZuUwHpQjQrQ7H7v1fjsP0Bi8jVaDIKA' + const ProcessBootLoaderTx = { + Id: 'PROCESS', + Owner: 'PROCESS', + Target: 'PROCESS', + Tags: [ + { name: 'Data-Protocol', value: 'ao' }, + { name: 'Variant', value: 'ao.TN.1' }, + { name: 'Type', value: 'Process' }, + { name: 'Extension', value: 'WeaveDrive' }, + { name: 'On-Boot', value: BootLoadedFromTx }, + { name: 'Module', value: 'MODULE' }, + { name: 'Authority', value: 'PROCESS' } + ], + Data: ` + Test = 1 + `, + From: 'PROCESS', + Module: 'MODULE', + "Block-Height": 4567, + Timestamp: Date.now() + } -const optionsBootLoaderTx = { ...options, mode: null } + const optionsBootLoaderTx = { + ...options, + spawn: { + id: ProcessBootLoaderTx.Id, + owner: ProcessBootLoaderTx.Owner, + tags: ProcessBootLoaderTx.Tags + }, + mode: null + } -test('boot loader set to tx id', async function () { const handle = await AoLoader(bootLoaderWasm, optionsBootLoaderTx) - const { Memory } = await handle(memoryBootLoader, { + const { Memory } = await handle(null, { ...ProcessBootLoaderTx }, { Process: ProcessBootLoaderTx, Module })