diff --git a/src/__tests__/integration/data/wasm/counter.wasm b/src/__tests__/integration/data/wasm/assemblyscript-counter.wasm similarity index 100% rename from src/__tests__/integration/data/wasm/counter.wasm rename to src/__tests__/integration/data/wasm/assemblyscript-counter.wasm diff --git a/src/__tests__/integration/data/wasm/pst-init-state.json b/src/__tests__/integration/data/wasm/pst-init-state.json new file mode 100644 index 0000000..b30a2c9 --- /dev/null +++ b/src/__tests__/integration/data/wasm/pst-init-state.json @@ -0,0 +1,9 @@ +{ + "ticker": "EXAMPLE_PST_TOKEN", + "name": "token name", + "owner": "uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M", + "balances": { + "uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M": 10000000, + "33F0QHcb22W7LwWR1iRC8Az1ntZG09XQ03YWuw2ABqA": 23111222 + } +} diff --git a/src/__tests__/integration/data/wasm/rust-counter.wasm b/src/__tests__/integration/data/wasm/rust-counter.wasm new file mode 100644 index 0000000..c5c454c Binary files /dev/null and b/src/__tests__/integration/data/wasm/rust-counter.wasm differ diff --git a/src/__tests__/integration/data/wasm/rust-pst.wasm b/src/__tests__/integration/data/wasm/rust-pst.wasm new file mode 100644 index 0000000..a9ff023 Binary files /dev/null and b/src/__tests__/integration/data/wasm/rust-pst.wasm differ diff --git a/src/__tests__/integration/data/wasm/smartweave_contract_bg.wasm b/src/__tests__/integration/data/wasm/smartweave_contract_bg.wasm new file mode 100644 index 0000000..53d20af Binary files /dev/null and b/src/__tests__/integration/data/wasm/smartweave_contract_bg.wasm differ diff --git a/src/__tests__/integration/wasm-deploy-write-read.test.ts b/src/__tests__/integration/wasm/as-deploy-write-read.test.ts similarity index 91% rename from src/__tests__/integration/wasm-deploy-write-read.test.ts rename to src/__tests__/integration/wasm/as-deploy-write-read.test.ts index 3edf7b0..410e592 100644 --- a/src/__tests__/integration/wasm-deploy-write-read.test.ts +++ b/src/__tests__/integration/wasm/as-deploy-write-read.test.ts @@ -5,7 +5,7 @@ import Arweave from 'arweave'; import { JWKInterface } from 'arweave/node/lib/wallet'; import { Contract, getTag, LoggerFactory, SmartWeave, SmartWeaveNodeFactory, SmartWeaveTags } from '@smartweave'; import path from 'path'; -import { addFunds, mineBlock } from './_helpers'; +import { addFunds, mineBlock } from '../_helpers'; interface ExampleContractState { counter: number; @@ -13,7 +13,7 @@ interface ExampleContractState { lastName: string; } -describe('Testing the SmartWeave client for WASM contract', () => { +describe('Testing the SmartWeave client for AssemblyScript WASM contract', () => { let contractSrc: Buffer; let initialState: string; let contractTxId: string; @@ -44,8 +44,8 @@ describe('Testing the SmartWeave client for WASM contract', () => { wallet = await arweave.wallets.generate(); await addFunds(arweave, wallet); - contractSrc = fs.readFileSync(path.join(__dirname, 'data/wasm/counter.wasm')); - initialState = fs.readFileSync(path.join(__dirname, 'data/wasm/counter-init-state.json'), 'utf8'); + contractSrc = fs.readFileSync(path.join(__dirname, '../data/wasm/assemblyscript-counter.wasm')); + initialState = fs.readFileSync(path.join(__dirname, '../data/wasm/counter-init-state.json'), 'utf8'); // deploying contract using the new SDK. contractTxId = await smartweave.createContract.deploy({ @@ -69,6 +69,8 @@ describe('Testing the SmartWeave client for WASM contract', () => { it('should properly deploy contract', async () => { const contractTx = await arweave.transactions.get(contractTxId); + console.log(contractTx.id); + expect(contractTx).not.toBeNull(); expect(getTag(contractTx, SmartWeaveTags.CONTRACT_TYPE)).toEqual('wasm'); expect(getTag(contractTx, SmartWeaveTags.WASM_LANG)).toEqual('assemblyscript'); @@ -89,7 +91,7 @@ describe('Testing the SmartWeave client for WASM contract', () => { for (let i = 0; i < 100; i++) { await contract.writeInteraction({ function: 'increment' }); } - }); + }, 10000); it('should properly read state after adding interactions', async () => { await mineBlock(arweave); diff --git a/src/__tests__/integration/wasm/rust-deploy-write-read.test.ts b/src/__tests__/integration/wasm/rust-deploy-write-read.test.ts new file mode 100644 index 0000000..ee78723 --- /dev/null +++ b/src/__tests__/integration/wasm/rust-deploy-write-read.test.ts @@ -0,0 +1,127 @@ +import fs from 'fs'; + +import ArLocal from 'arlocal'; +import Arweave from 'arweave'; +import {JWKInterface} from 'arweave/node/lib/wallet'; +import { + getTag, + InteractionResult, + LoggerFactory, + PstContract, + PstState, + SmartWeave, + SmartWeaveNodeFactory, SmartWeaveTags +} from '@smartweave'; +import path from 'path'; +import {addFunds, mineBlock} from "../_helpers"; + +describe('Testing the Rust WASM Profit Sharing Token', () => { + let contractSrc: string; + + let wallet: JWKInterface; + let walletAddress: string; + + let initialState: PstState; + + let arweave: Arweave; + let arlocal: ArLocal; + let smartweave: SmartWeave; + let pst: PstContract; + + let contractTxId: string; + beforeAll(async () => { + // note: each tests suit (i.e. file with tests that Jest is running concurrently + // with another files has to have ArLocal set to a different port!) + arlocal = new ArLocal(1301, false); + await arlocal.start(); + + arweave = Arweave.init({ + host: 'localhost', + port: 1301, + protocol: 'http' + }); + + LoggerFactory.INST.logLevel('error'); + + smartweave = SmartWeaveNodeFactory.memCached(arweave); + + wallet = await arweave.wallets.generate(); + await addFunds(arweave, wallet); + walletAddress = await arweave.wallets.jwkToAddress(wallet); + + const contractSrc = fs.readFileSync(path.join(__dirname, '../data/wasm/smartweave_contract_bg.wasm')); + const stateFromFile: PstState = JSON.parse(fs.readFileSync(path.join(__dirname, '../data/token-pst.json'), 'utf8')); + + initialState = { + ...stateFromFile, + ...{ + owner: walletAddress, + balances: { + ...stateFromFile.balances, + [walletAddress]: 555669 + } + } + }; + + // deploying contract using the new SDK. + contractTxId = await smartweave.createContract.deploy({ + wallet, + initState: JSON.stringify(initialState), + src: contractSrc + }); + + // connecting to the PST contract + pst = smartweave.pst(contractTxId); + + // connecting wallet to the PST contract + pst.connect(wallet); + + await mineBlock(arweave); + }); + + afterAll(async () => { + await arlocal.stop(); + }); + + it('should properly deploy contract', async () => { + const contractTx = await arweave.transactions.get(contractTxId); + + console.log(contractTx.id); + + expect(contractTx).not.toBeNull(); + expect(getTag(contractTx, SmartWeaveTags.CONTRACT_TYPE)).toEqual('wasm'); + expect(getTag(contractTx, SmartWeaveTags.WASM_LANG)).toEqual('rust'); + + const contractSrcTx = await arweave.transactions.get(getTag(contractTx, SmartWeaveTags.CONTRACT_SRC_TX_ID)); + expect(getTag(contractSrcTx, SmartWeaveTags.CONTENT_TYPE)).toEqual('application/wasm'); + expect(getTag(contractSrcTx, SmartWeaveTags.WASM_LANG)).toEqual('rust'); + }); + + it('should read pst state and balance data', async () => { + expect(await pst.currentState()).toEqual(initialState); + + expect((await pst.currentBalance('uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M'))).toEqual(10000000); + expect((await pst.currentBalance('33F0QHcb22W7LwWR1iRC8Az1ntZG09XQ03YWuw2ABqA'))).toEqual(23111222); + expect((await pst.currentBalance(walletAddress))).toEqual(555669); + + }); + + it('should properly transfer tokens', async () => { + await pst.transfer({ + target: 'uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M', + qty: 555 + }); + + await mineBlock(arweave); + + expect((await pst.currentState()).balances[walletAddress]).toEqual(555669 - 555); + expect((await pst.currentState()).balances['uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M']).toEqual(10000000 + 555); + }); + + + it('should properly view contract state', async () => { + const result = await pst.currentBalance('uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M'); + expect(result).toEqual(10000000 + 555); + }); + +}); diff --git a/src/__tests__/regression/read-state.test.ts b/src/__tests__/regression/read-state.test.ts index 55eb4be..79662ce 100644 --- a/src/__tests__/regression/read-state.test.ts +++ b/src/__tests__/regression/read-state.test.ts @@ -67,7 +67,7 @@ describe.each(chunked)('v1 compare.suite %#', (contracts: string[]) => { ); }); -describe.each(chunkedGw)('gateways compare.suite %#', (contracts: string[]) => { +fdescribe.each(chunkedGw)('gateways compare.suite %#', (contracts: string[]) => { // note: concurrent doesn't seem to be working here, duh... // will probably need to manually split all the test cases to separate test files it.concurrent.each(contracts)( diff --git a/src/core/modules/impl/CacheableStateEvaluator.ts b/src/core/modules/impl/CacheableStateEvaluator.ts index 2d83f38..d3e4ac4 100644 --- a/src/core/modules/impl/CacheableStateEvaluator.ts +++ b/src/core/modules/impl/CacheableStateEvaluator.ts @@ -101,6 +101,7 @@ export class CacheableStateEvaluator extends DefaultStateEvaluator { const baseState = cachedState == null ? executionContext.contractDefinition.initState : cachedState.cachedValue.state; + const baseValidity = cachedState == null ? {} : cachedState.cachedValue.validity; // eval state for the missing transactions - starting from latest value from cache. diff --git a/src/core/modules/impl/DefaultCreateContract.ts b/src/core/modules/impl/DefaultCreateContract.ts index 42877a9..8cf6b49 100644 --- a/src/core/modules/impl/DefaultCreateContract.ts +++ b/src/core/modules/impl/DefaultCreateContract.ts @@ -1,8 +1,9 @@ /* eslint-disable */ -import { ContractData, ContractType, CreateContract, FromSrcTxContractData, SmartWeaveTags } from '@smartweave/core'; +import {ContractData, ContractType, CreateContract, FromSrcTxContractData, SmartWeaveTags} from '@smartweave/core'; import Arweave from 'arweave'; -import { LoggerFactory } from '@smartweave/logging'; -import { imports } from './wasmImports'; +import {LoggerFactory} from '@smartweave/logging'; +import {asWasmImports} from './wasm/as-wasm-imports'; +import {rustWasmImports} from "./wasm/rust-wasm-imports"; const wasmTypeMapping: Map = new Map([ [1, 'assemblyscript'], @@ -22,9 +23,9 @@ export class DefaultCreateContract implements CreateContract { async deploy(contractData: ContractData): Promise { this.logger.debug('Creating new contract'); - const { wallet, src, initState, tags, transfer } = contractData; + const {wallet, src, initState, tags, transfer} = contractData; - const srcTx = await this.arweave.createTransaction({ data: src }, wallet); + const srcTx = await this.arweave.createTransaction({data: src}, wallet); const contractType: ContractType = src instanceof Buffer ? 'wasm' : 'js'; @@ -42,7 +43,7 @@ export class DefaultCreateContract implements CreateContract { const module = await WebAssembly.instantiate(src, dummyImports()); // @ts-ignore if (!module.instance.exports.type) { - throw new Error(`No info about source type in wasm binary. Did you forget to export global "type" value?`); + throw new Error(`No info about source type in wasm binary. Did you forget to export "type" function?`); } // @ts-ignore const type = module.instance.exports.type(); @@ -78,9 +79,9 @@ export class DefaultCreateContract implements CreateContract { async deployFromSourceTx(contractData: FromSrcTxContractData): Promise { this.logger.debug('Creating new contract from src tx'); - const { wallet, srcTxId, initState, tags, transfer } = contractData; + const {wallet, srcTxId, initState, tags, transfer} = contractData; - let contractTX = await this.arweave.createTransaction({ data: initState }, wallet); + let contractTX = await this.arweave.createTransaction({data: initState}, wallet); if (+transfer?.winstonQty > 0 && transfer.target.length) { this.logger.debug('Creating additional transaction with AR transfer', transfer); @@ -121,10 +122,17 @@ export class DefaultCreateContract implements CreateContract { } function dummyImports() { - return imports( - { - useGas: function () {} - } as any, - null - ); + const dummySwGlobal = { + useGas: function () { + } + } as any; + + const dummyModuleInstance = { + exports: {} + } + + return { + ...rustWasmImports(dummySwGlobal, dummyModuleInstance).imports, + ...asWasmImports(dummySwGlobal, dummyModuleInstance) + } } diff --git a/src/core/modules/impl/DefaultStateEvaluator.ts b/src/core/modules/impl/DefaultStateEvaluator.ts index 4c56987..77741d3 100644 --- a/src/core/modules/impl/DefaultStateEvaluator.ts +++ b/src/core/modules/impl/DefaultStateEvaluator.ts @@ -35,7 +35,8 @@ export abstract class DefaultStateEvaluator implements StateEvaluator { protected constructor( protected readonly arweave: Arweave, private readonly executionContextModifiers: ExecutionContextModifier[] = [] - ) {} + ) { + } async eval( executionContext: ExecutionContext>, @@ -56,8 +57,8 @@ export abstract class DefaultStateEvaluator implements StateEvaluator { currentTx: CurrentTx[] ): Promise> { const stateEvaluationBenchmark = Benchmark.measure(); - const { ignoreExceptions, stackTrace, internalWrites } = executionContext.evaluationOptions; - const { contract, contractDefinition, sortedInteractions } = executionContext; + const {ignoreExceptions, stackTrace, internalWrites} = executionContext.evaluationOptions; + const {contract, contractDefinition, sortedInteractions} = executionContext; let currentState = baseState.state; const validity = baseState.validity; @@ -72,6 +73,8 @@ export abstract class DefaultStateEvaluator implements StateEvaluator { let lastConfirmedTxState: { tx: GQLNodeInterface; state: EvalStateResult } = null; const missingInteractionsLength = missingInteractions.length; + executionContext.handler.initState(currentState); + for (let i = 0; i < missingInteractionsLength; i++) { const missingInteraction = missingInteractions[i]; const singleInteractionBenchmark = Benchmark.measure(); @@ -94,7 +97,7 @@ export abstract class DefaultStateEvaluator implements StateEvaluator { const interactionCall: InteractionCall = contract .getCallStack() - .addInteractionData({ interaction: null, interactionTx, currentTx }); + .addInteractionData({interaction: null, interactionTx, currentTx}); // creating a Contract instance for the "writing" contract const writingContract = executionContext.smartweave.contract( @@ -155,7 +158,7 @@ export abstract class DefaultStateEvaluator implements StateEvaluator { gasUsed: 0 // TODO... }); - this.logger.debug('New state after internal write', { contractTxId: contractDefinition.txId, newState }); + this.logger.debug('New state after internal write', {contractTxId: contractDefinition.txId, newState}); } else { // "direct" interaction with this contract - "standard" processing const inputTag = this.tagsParser.getInputTag(missingInteraction, executionContext.contractDefinition.txId); @@ -224,7 +227,7 @@ export abstract class DefaultStateEvaluator implements StateEvaluator { // I'm really NOT a fan of this "modify" feature, but I don't have idea how to better // implement the "evolve" feature - for (const { modify } of this.executionContextModifiers) { + for (const {modify} of this.executionContextModifiers) { executionContext = await modify(currentState, executionContext); } } diff --git a/src/core/modules/impl/HandlerExecutorFactory.ts b/src/core/modules/impl/HandlerExecutorFactory.ts index bf52551..3adcd64 100644 --- a/src/core/modules/impl/HandlerExecutorFactory.ts +++ b/src/core/modules/impl/HandlerExecutorFactory.ts @@ -11,9 +11,10 @@ import { } from '@smartweave'; import { ContractHandlerApi } from './ContractHandlerApi'; import loader from '@assemblyscript/loader'; -import { imports } from './wasmImports'; import { WasmContractHandlerApi } from './WasmContractHandlerApi'; import metering from 'redstone-wasm-metering'; +import { asWasmImports } from './wasm/as-wasm-imports'; +import { rustWasmImports } from './wasm/rust-wasm-imports'; /** * A factory that produces handlers that are compatible with the "current" style of @@ -30,29 +31,56 @@ export class HandlerExecutorFactory implements ExecutorFactory implements HandlerApi { this.contractLogger = LoggerFactory.INST.create(swGlobal.contract.id); } - initState(state: State): void { - const statePtr = this.wasmExports.__newString(stringify(state)); - this.wasmExports.initState(statePtr); - } - async handle( executionContext: ExecutionContext, currentResult: EvalStateResult, @@ -43,7 +38,7 @@ export class WasmContractHandlerApi implements HandlerApi { this.swGlobal.gasLimit = executionContext.evaluationOptions.gasLimit; this.swGlobal.gasUsed = 0; - const handlerResult = this.doHandle(interaction); + const handlerResult = await this.doHandle(interaction); return { type: 'ok', @@ -83,17 +78,70 @@ export class WasmContractHandlerApi implements HandlerApi { } } - private doHandle(action: any): any { - this.logger.debug('Action', action.input); - const actionPtr = this.wasmExports.__newString(stringify(action.input)); - const resultPtr = this.wasmExports.handle(actionPtr); - const result = this.wasmExports.__getString(resultPtr); + initState(state: State): void { + switch (this.contractDefinition.srcWasmLang) { + case "assemblyscript": { + const statePtr = this.wasmExports.__newString(stringify(state)); + this.wasmExports.initState(statePtr); + break; + } + case "rust": { + this.logger.debug('Before init state', this.wasmExports); + this.wasmExports.initState(state); + this.logger.debug('After init state'); + break; + } + default: { + throw new Error(`Support for ${this.contractDefinition.srcWasmLang} not implemented yet.`); + } + } + } - return JSON.parse(result); + private async doHandle(action: any): Promise { + switch (this.contractDefinition.srcWasmLang) { + case "assemblyscript": { + this.logger.debug('Action', action.input); + const actionPtr = this.wasmExports.__newString(stringify(action.input)); + const resultPtr = this.wasmExports.handle(actionPtr); + const result = this.wasmExports.__getString(resultPtr); + + return JSON.parse(result); + } + case "rust": { + this.logger.debug("exports", this.wasmExports); + let handleResult = await this.wasmExports.handle(action.input); + this.logger.debug("handleResult", handleResult); + if (!handleResult) { + return; + } + this.logger.debug("handleResult.ok", handleResult.Ok); + if (Object.prototype.hasOwnProperty.call(handleResult, 'Ok')) { + return handleResult.Ok; + } else { + throw new Error(handleResult.Err) + } + } + default: { + throw new Error(`Support for ${this.contractDefinition.srcWasmLang} not implemented yet.`); + } + } } private doGetCurrentState(): State { - const currentStatePtr = this.wasmExports.currentState(); - return JSON.parse(this.wasmExports.__getString(currentStatePtr)); + switch (this.contractDefinition.srcWasmLang) { + case "assemblyscript": { + const currentStatePtr = this.wasmExports.currentState(); + return JSON.parse(this.wasmExports.__getString(currentStatePtr)); + } + case "rust": { + return this.wasmExports.currentState(); + } + default: { + throw new Error(`Support for ${this.contractDefinition.srcWasmLang} not implemented yet.`); + } + + } + + } } diff --git a/src/core/modules/impl/wasmImports.ts b/src/core/modules/impl/wasm/as-wasm-imports.ts similarity index 60% rename from src/core/modules/impl/wasmImports.ts rename to src/core/modules/impl/wasm/as-wasm-imports.ts index 7d832b5..2ddb236 100644 --- a/src/core/modules/impl/wasmImports.ts +++ b/src/core/modules/impl/wasm/as-wasm-imports.ts @@ -1,6 +1,6 @@ import { LoggerFactory, SmartWeaveGlobal } from '@smartweave'; -export const imports = (swGlobal: SmartWeaveGlobal, wasmModule: any): any => { +export const asWasmImports = (swGlobal: SmartWeaveGlobal, wasmInstance: any): any => { const wasmLogger = LoggerFactory.INST.create('WASM'); return { @@ -9,12 +9,12 @@ export const imports = (swGlobal: SmartWeaveGlobal, wasmModule: any): any => { }, console: { 'console.log': function (msgPtr) { - wasmLogger.debug(`${swGlobal.contract.id}: ${wasmModule.exports.__getString(msgPtr)}`); + wasmLogger.debug(`${swGlobal.contract.id}: ${wasmInstance.exports.__getString(msgPtr)}`); }, 'console.logO': function (msgPtr, objPtr) { wasmLogger.debug( - `${swGlobal.contract.id}: ${wasmModule.exports.__getString(msgPtr)}`, - JSON.parse(wasmModule.exports.__getString(objPtr)) + `${swGlobal.contract.id}: ${wasmInstance.exports.__getString(msgPtr)}`, + JSON.parse(wasmInstance.exports.__getString(objPtr)) ); } }, @@ -23,7 +23,7 @@ export const imports = (swGlobal: SmartWeaveGlobal, wasmModule: any): any => { return swGlobal.block.height; }, 'Block.indep_hash': function () { - return wasmModule.exports.__newString(swGlobal.block.indep_hash); + return wasmInstance.exports.__newString(swGlobal.block.indep_hash); }, 'Block.timestamp': function () { return swGlobal.block.timestamp; @@ -31,32 +31,32 @@ export const imports = (swGlobal: SmartWeaveGlobal, wasmModule: any): any => { }, transaction: { 'Transaction.id': function () { - return wasmModule.exports.__newString(swGlobal.transaction.id); + return wasmInstance.exports.__newString(swGlobal.transaction.id); }, 'Transaction.owner': function () { - return wasmModule.exports.__newString(swGlobal.transaction.owner); + return wasmInstance.exports.__newString(swGlobal.transaction.owner); }, 'Transaction.target': function () { - return wasmModule.exports.__newString(swGlobal.transaction.target); + return wasmInstance.exports.__newString(swGlobal.transaction.target); } }, contract: { 'Contract.id': function () { - return wasmModule.exports.__newString(swGlobal.contract.id); + return wasmInstance.exports.__newString(swGlobal.contract.id); }, 'Contract.owner': function () { - return wasmModule.exports.__newString(swGlobal.contract.owner); + return wasmInstance.exports.__newString(swGlobal.contract.owner); } }, api: { _readContractState: (fnIndex, contractTxIdPtr) => { - const contractTxId = wasmModule.exports.__getString(contractTxIdPtr); + const contractTxId = wasmInstance.exports.__getString(contractTxIdPtr); const callbackFn = getFn(fnIndex); console.log('Simulating read state of', contractTxId); return setTimeout(() => { console.log('calling callback'); callbackFn( - wasmModule.exports.__newString( + wasmInstance.exports.__newString( JSON.stringify({ contractTxId }) @@ -69,8 +69,8 @@ export const imports = (swGlobal: SmartWeaveGlobal, wasmModule: any): any => { env: { abort(messagePtr, fileNamePtr, line, column) { console.error('--------------------- Error message from AssemblyScript ----------------------'); - console.error(' ' + wasmModule.exports.__getString(messagePtr)); - console.error(' In file "' + wasmModule.exports.__getString(fileNamePtr) + '"'); + console.error(' ' + wasmInstance.exports.__getString(messagePtr)); + console.error(' In file "' + wasmInstance.exports.__getString(fileNamePtr) + '"'); console.error(` on line ${line}, column ${column}.`); console.error('------------------------------------------------------------------------------\n'); } @@ -78,6 +78,6 @@ export const imports = (swGlobal: SmartWeaveGlobal, wasmModule: any): any => { }; function getFn(idx) { - return wasmModule.exports.table.get(idx); + return wasmInstance.exports.table.get(idx); } }; diff --git a/src/core/modules/impl/wasm/rust-wasm-imports.ts b/src/core/modules/impl/wasm/rust-wasm-imports.ts new file mode 100644 index 0000000..e514e28 --- /dev/null +++ b/src/core/modules/impl/wasm/rust-wasm-imports.ts @@ -0,0 +1,523 @@ +/* tslint:disable */ +/* eslint-disable */ +/* a kind of magic */ +import {LoggerFactory, timeout} from "@smartweave"; + +export const rustWasmImports = (swGlobal, wasmInstance: any): any => { + const wasmLogger = LoggerFactory.INST.create('WASM'); + + //const wasm = wasmInstance.exports; + + const rawImports = { + metering: { + usegas: swGlobal.useGas + }, + "console": { + log: function (value) { + wasmLogger.debug(`${swGlobal.contract.id}: ${value}`); + } + }, + "Block": { + height: function () { + return swGlobal.block.height; + }, + indep_hash: function () { + return swGlobal.block.indep_hash; + }, + timestamp: function () { + return swGlobal.block.timestamp; + } + }, + "Transaction": { + id: function () { + return swGlobal.transaction.id; + }, + owner: function () { + return swGlobal.transaction.owner; + }, + target: function () { + return swGlobal.transaction.target; + }, + }, + "Contract": { + id: function () { + return swGlobal.contract.id; + }, + owner: function () { + return swGlobal.contract.owner; + } + }, + "SmartWeave": { + readContractState: async function (contractTxId) { + console.log('js: readContractState before timeout'); + await timeout(1000); + console.log('js: readContractState after timeout'); + return { + value: contractTxId + } + } + } + } + + let exports: any = {}; + let imports: any = {}; + + imports['__wbindgen_placeholder__'] = exports; + + const {TextDecoder, TextEncoder} = require(`util`); + + let cachedTextDecoder = new TextDecoder('utf-8', {ignoreBOM: true, fatal: true}); + + cachedTextDecoder.decode(); + + let cachegetUint8Memory0 = null; + + function getUint8Memory0() { + if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasmInstance.exports.memory.buffer) { + cachegetUint8Memory0 = new Uint8Array(wasmInstance.exports.memory.buffer); + } + return cachegetUint8Memory0; + } + + function getStringFromWasm0(ptr, len) { + return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); + } + + const heap = new Array(32).fill(undefined); + + heap.push(undefined, null, true, false); + + let heap_next = heap.length; + + function addHeapObject(obj) { + if (heap_next === heap.length) heap.push(heap.length + 1); + const idx = heap_next; + heap_next = heap[idx]; + + heap[idx] = obj; + return idx; + } + + function getObject(idx) { + return heap[idx]; + } + + let WASM_VECTOR_LEN = 0; + + let cachedTextEncoder = new TextEncoder('utf-8'); + + const encodeString = (typeof cachedTextEncoder.encodeInto === 'function' + ? function (arg, view) { + return cachedTextEncoder.encodeInto(arg, view); + } + : function (arg, view) { + const buf = cachedTextEncoder.encode(arg); + view.set(buf); + return { + read: arg.length, + written: buf.length + }; + }); + + function passStringToWasm0(arg, malloc, realloc) { + + if (realloc === undefined) { + const buf = cachedTextEncoder.encode(arg); + const ptr = malloc(buf.length); + getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf); + WASM_VECTOR_LEN = buf.length; + return ptr; + } + + let len = arg.length; + let ptr = malloc(len); + + const mem = getUint8Memory0(); + + let offset = 0; + + for (; offset < len; offset++) { + const code = arg.charCodeAt(offset); + if (code > 0x7F) break; + mem[ptr + offset] = code; + } + + if (offset !== len) { + if (offset !== 0) { + arg = arg.slice(offset); + } + ptr = realloc(ptr, len, len = offset + arg.length * 3); + const view = getUint8Memory0().subarray(ptr + offset, ptr + len); + const ret = encodeString(arg, view); + + offset += ret.written; + } + + WASM_VECTOR_LEN = offset; + return ptr; + } + + let cachegetInt32Memory0 = null; + + function getInt32Memory0() { + if (cachegetInt32Memory0 === null || cachegetInt32Memory0.buffer !== wasmInstance.exports.memory.buffer) { + cachegetInt32Memory0 = new Int32Array(wasmInstance.exports.memory.buffer); + } + return cachegetInt32Memory0; + } + + function dropObject(idx) { + if (idx < 36) return; + heap[idx] = heap_next; + heap_next = idx; + } + + function takeObject(idx) { + const ret = getObject(idx); + dropObject(idx); + return ret; + } + + function debugString(val) { + // primitive types + const type = typeof val; + if (type == 'number' || type == 'boolean' || val == null) { + return `${val}`; + } + if (type == 'string') { + return `"${val}"`; + } + if (type == 'symbol') { + const description = val.description; + if (description == null) { + return 'Symbol'; + } else { + return `Symbol(${description})`; + } + } + if (type == 'function') { + const name = val.name; + if (typeof name == 'string' && name.length > 0) { + return `Function(${name})`; + } else { + return 'Function'; + } + } + // objects + if (Array.isArray(val)) { + const length = val.length; + let debug = '['; + if (length > 0) { + debug += debugString(val[0]); + } + for (let i = 1; i < length; i++) { + debug += ', ' + debugString(val[i]); + } + debug += ']'; + return debug; + } + // Test for built-in + const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val)); + let className; + if (builtInMatches.length > 1) { + className = builtInMatches[1]; + } else { + // Failed to match the standard '[object ClassName]' + return toString.call(val); + } + if (className == 'Object') { + // we're a user defined class or Object + // JSON.stringify avoids problems with cycles, and is generally much + // easier than looping through ownProperties of `val`. + try { + return 'Object(' + JSON.stringify(val) + ')'; + } catch (_) { + return 'Object'; + } + } + // errors + if (val instanceof Error) { + return `${val.name}: ${val.message}\n${val.stack}`; + } + // TODO we could test for more things here, like `Set`s and `Map`s. + return className; + } + + function makeMutClosure(arg0, arg1, dtor, f) { + const state = {a: arg0, b: arg1, cnt: 1, dtor}; + const real = (...args) => { + // First up with a closure we increment the internal reference + // count. This ensures that the Rust closure environment won't + // be deallocated while we're invoking it. + state.cnt++; + const a = state.a; + state.a = 0; + try { + return f(a, state.b, ...args); + } finally { + if (--state.cnt === 0) { + wasmInstance.exports.__wbindgen_export_2.get(state.dtor)(a, state.b); + + } else { + state.a = a; + } + } + }; + real.original = state; + + return real; + } + + function __wbg_adapter_14(arg0, arg1, arg2) { + wasmInstance.exports._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h0af8cf16c8647f23(arg0, arg1, addHeapObject(arg2)); + } + + /** + * @param {any} interaction + * @returns {Promise} + */ + exports.handle = function (interaction) { + console.log("handleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", interaction); + console.log("handleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", wasmInstance.exports.handle); + var ret = wasmInstance.exports.handle(addHeapObject(interaction)); + return takeObject(ret); + }; + + let stack_pointer = 32; + + function addBorrowedObject(obj) { + if (stack_pointer == 1) throw new Error('out of js stack'); + heap[--stack_pointer] = obj; + return stack_pointer; + } + + /** + * @param {any} state + */ + exports.initState = function (state) { + console.log("INIT STATE11111111"); + try { + console.log(state); + wasmInstance.exports.initState(addBorrowedObject(state)); + } finally { + heap[stack_pointer++] = undefined; + } + }; + + /** + * @returns {any} + */ + exports.currentState = function () { + var ret = wasmInstance.exports.currentState(); + return takeObject(ret); + }; + + /** + * @returns {string} + */ + exports.lang = function () { + try { + const retptr = wasmInstance.exports.__wbindgen_add_to_stack_pointer(-16); + wasmInstance.exports.lang(retptr); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + return getStringFromWasm0(r0, r1); + } finally { + wasmInstance.exports.__wbindgen_add_to_stack_pointer(16); + wasmInstance.exports.__wbindgen_free(r0, r1); + } + }; + + /** + * @returns {number} + */ + exports.type = function () { + var ret = wasmInstance.exports.type(); + return ret; + }; + + function handleError(f, args) { + try { + return f.apply(this, args); + } catch (e) { + wasmInstance.exports.__wbindgen_exn_store(addHeapObject(e)); + } + } + + function __wbg_adapter_42(arg0, arg1, arg2, arg3) { + wasmInstance.exports.wasm_bindgen__convert__closures__invoke2_mut__h1aa5ebac0642c58b(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3)); + } + + /** + */ + class StateWrapper { + + __destroy_into_raw() { + // @ts-ignore + const ptr = this.ptr; + // @ts-ignore + this.ptr = 0; + + return ptr; + } + + free() { + const ptr = this.__destroy_into_raw(); + wasmInstance.exports.__wbg_statewrapper_free(ptr); + } + } + + exports.StateWrapper = StateWrapper; + + exports.__wbg_indephash_5169b74d7073ec06 = function (arg0) { + console.log("block indep hash"); + var ret = rawImports.Block.indep_hash(); + var ptr0 = passStringToWasm0(ret, wasmInstance.exports.__wbindgen_malloc, wasmInstance.exports.__wbindgen_realloc); + var len0 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len0; + getInt32Memory0()[arg0 / 4 + 0] = ptr0; + }; + + exports.__wbg_height_7e2d5ab154a32c53 = function () { + var ret = rawImports.Block.height(); + return ret; + }; + + exports.__wbg_timestamp_b2ae03e8830bf361 = function () { + var ret = rawImports.Block.timestamp(); + return ret; + }; + + exports.__wbg_id_96159534c1352b1f = function () { + var ret = rawImports.Contract.id(); + return ret; + }; + + exports.__wbg_owner_584edbeb2fc79632 = function (arg0) { + var ret = rawImports.Contract.owner(); + var ptr0 = passStringToWasm0(ret, wasmInstance.exports.__wbindgen_malloc, wasmInstance.exports.__wbindgen_realloc); + var len0 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len0; + getInt32Memory0()[arg0 / 4 + 0] = ptr0; + }; + + exports.__wbg_id_004f7156a1dccfe0 = function () { + var ret = rawImports.Transaction.id(); + return ret; + }; + + exports.__wbg_owner_3b98731ef4bca542 = function (arg0) { + var ret = rawImports.Transaction.owner(); + var ptr0 = passStringToWasm0(ret, wasmInstance.exports.__wbindgen_malloc, wasmInstance.exports.__wbindgen_realloc); + var len0 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len0; + getInt32Memory0()[arg0 / 4 + 0] = ptr0; + }; + + exports.__wbg_target_900d26a5419b4869 = function (arg0) { + var ret = rawImports.Transaction.target(); + var ptr0 = passStringToWasm0(ret, wasmInstance.exports.__wbindgen_malloc, wasmInstance.exports.__wbindgen_realloc); + var len0 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len0; + getInt32Memory0()[arg0 / 4 + 0] = ptr0; + }; + + exports.__wbg_log_5f1f23db3aa2a6c6 = function (arg0, arg1) { + rawImports.console.log(getStringFromWasm0(arg0, arg1)); + }; + + exports.__wbindgen_json_parse = function (arg0, arg1) { + var ret = JSON.parse(getStringFromWasm0(arg0, arg1)); + return addHeapObject(ret); + }; + + exports.__wbindgen_json_serialize = function (arg0, arg1) { + const obj = getObject(arg1); + var ret = JSON.stringify(obj === undefined ? null : obj); + var ptr0 = passStringToWasm0(ret, wasmInstance.exports.__wbindgen_malloc, wasmInstance.exports.__wbindgen_realloc); + var len0 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len0; + getInt32Memory0()[arg0 / 4 + 0] = ptr0; + }; + + exports.__wbindgen_object_drop_ref = function (arg0) { + takeObject(arg0); + }; + + exports.__wbindgen_cb_drop = function (arg0) { + const obj = takeObject(arg0).original; + if (obj.cnt-- == 1) { + obj.a = 0; + return true; + } + var ret = false; + return ret; + }; + + exports.__wbg_readContractState_251600c2ccc5a557 = function (arg0, arg1) { + var ret = rawImports.SmartWeave.readContractState(getStringFromWasm0(arg0, arg1)); + return addHeapObject(ret); + }; + + exports.__wbg_call_94697a95cb7e239c = function () { + return handleError(function (arg0, arg1, arg2) { + var ret = getObject(arg0).call(getObject(arg1), getObject(arg2)); + return addHeapObject(ret); + }, arguments) + }; + + exports.__wbg_new_4beacc9c71572250 = function (arg0, arg1) { + try { + var state0 = {a: arg0, b: arg1}; + var cb0 = (arg0, arg1) => { + const a = state0.a; + state0.a = 0; + try { + return __wbg_adapter_42(a, state0.b, arg0, arg1); + } finally { + state0.a = a; + } + }; + var ret = new Promise(cb0); + return addHeapObject(ret); + } finally { + state0.a = state0.b = 0; + } + }; + + exports.__wbg_resolve_4f8f547f26b30b27 = function (arg0) { + var ret = Promise.resolve(getObject(arg0)); + return addHeapObject(ret); + }; + + exports.__wbg_then_a6860c82b90816ca = function (arg0, arg1) { + var ret = getObject(arg0).then(getObject(arg1)); + return addHeapObject(ret); + }; + + exports.__wbg_then_58a04e42527f52c6 = function (arg0, arg1, arg2) { + var ret = getObject(arg0).then(getObject(arg1), getObject(arg2)); + return addHeapObject(ret); + }; + + exports.__wbindgen_debug_string = function (arg0, arg1) { + var ret = debugString(getObject(arg1)); + var ptr0 = passStringToWasm0(ret, wasmInstance.exports.__wbindgen_malloc, wasmInstance.exports.__wbindgen_realloc); + var len0 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len0; + getInt32Memory0()[arg0 / 4 + 0] = ptr0; + }; + + exports.__wbindgen_throw = function (arg0, arg1) { + throw new Error(getStringFromWasm0(arg0, arg1)); + }; + + exports.__wbindgen_closure_wrapper218 = function (arg0, arg1, arg2) { + var ret = makeMutClosure(arg0, arg1, 75, __wbg_adapter_14); + return addHeapObject(ret); + }; + + imports.metering = rawImports.metering; + + return {imports, exports}; +} diff --git a/tools/report.json b/tools/report.json new file mode 100644 index 0000000..fc57634 --- /dev/null +++ b/tools/report.json @@ -0,0 +1,265 @@ +{ + "contractTxId": "sR3FG6Wvvq0uYeILMCkK-tG7i2N0fxIB2LpgqgS__TI", + "depth": 0, + "label": "", + "interactions": { + "dataType": "Map", + "value": [ + [ + "W1COLMVJN2nr1G-Qe03lozP6fOKFotXxyxRR5FSU6pc", + { + "interactionInput": { + "txId": "W1COLMVJN2nr1G-Qe03lozP6fOKFotXxyxRR5FSU6pc", + "blockHeight": 879965, + "blockTimestamp": 1645687971, + "caller": "LOLS0MQ6sKprHDYVgwfYaMm0ypRmVU0T6oYQxrx3Bks", + "functionArguments": [ + { + "function": "transfer", + "qty": "1000000000000000", + "target": "kyGgyXpsHGX8wT9Oe4rsIGNb7ilybknVvSjcrLKVt1Y" + }, + { + "function": "transfer", + "qty": "1000000000000000", + "target": "SFvtYkST38oYwQGG1NuVeA7EMaM2QLhzBXGwDXe1fjg" + }, + { + "function": "transfer", + "qty": "1000000000000000", + "target": "FDtVABwHgn1VL4bgLwkiP-UbWtvSBZ-XZ9TLuQDN1fQ" + }, + { + "function": "transfer", + "qty": "1000000000000000", + "target": "iqqGjbgTJIrXVo71pySg2uiwhqEb-QShNGj-APcxhoQ" + } + ], + "foreignContractCalls": { + "dataType": "Map", + "value": [] + } + }, + "interactionOutput": { + "cacheHit": false, + "intermediaryCacheHit": false, + "executionTime": 6, + "errorMessage": "No function supplied or function not recognised: \\" + undefined + \ + \ + "" + } + } + ], + [ + "p5tPewKCHD8P6w4p-Jtn0UIV0CwaZCSUZt6PV9vezRg", + { + "interactionInput": { + "txId": "p5tPewKCHD8P6w4p-Jtn0UIV0CwaZCSUZt6PV9vezRg", + "blockHeight": 879975, + "blockTimestamp": 1645688473, + "caller": "LOLS0MQ6sKprHDYVgwfYaMm0ypRmVU0T6oYQxrx3Bks", + "functionArguments": [ + { + "function": "transfer", + "qty": 1000000000000000, + "target": "kyGgyXpsHGX8wT9Oe4rsIGNb7ilybknVvSjcrLKVt1Y" + }, + { + "function": "transfer", + "qty": 1000000000000000, + "target": "SFvtYkST38oYwQGG1NuVeA7EMaM2QLhzBXGwDXe1fjg" + }, + { + "function": "transfer", + "qty": 1000000000000000, + "target": "FDtVABwHgn1VL4bgLwkiP-UbWtvSBZ-XZ9TLuQDN1fQ" + }, + { + "function": "transfer", + "qty": 1000000000000000, + "target": "iqqGjbgTJIrXVo71pySg2uiwhqEb-QShNGj-APcxhoQ" + } + ], + "foreignContractCalls": { + "dataType": "Map", + "value": [] + } + }, + "interactionOutput": { + "cacheHit": false, + "intermediaryCacheHit": false, + "executionTime": 2, + "errorMessage": "No function supplied or function not recognised: \\" + undefined + \ + \ + "" + } + } + ], + [ + "iJoZwH9dwHPWS8l0z4j6JRNOET_mXjHdi10eVOnGnhA", + { + "interactionInput": { + "txId": "iJoZwH9dwHPWS8l0z4j6JRNOET_mXjHdi10eVOnGnhA", + "blockHeight": 879981, + "blockTimestamp": 1645689677, + "caller": "LOLS0MQ6sKprHDYVgwfYaMm0ypRmVU0T6oYQxrx3Bks", + "functionArguments": [ + { + "function": "transfer", + "qty": 1000000000000000, + "target": "DEgJqP8Zd4RBld0JCuc2U-UKtUJyNtLcW6jt4k6L1pQ" + } + ], + "foreignContractCalls": { + "dataType": "Map", + "value": [] + } + }, + "interactionOutput": { + "cacheHit": false, + "intermediaryCacheHit": false, + "executionTime": 2, + "errorMessage": "No function supplied or function not recognised: \\" + undefined + \ + \ + "" + } + } + ], + [ + "WHiXm0P6BTne5_VxNk76U4H6Zl3D_SoQ8-KRaAMlgNM", + { + "interactionInput": { + "txId": "WHiXm0P6BTne5_VxNk76U4H6Zl3D_SoQ8-KRaAMlgNM", + "blockHeight": 879985, + "blockTimestamp": 1645690362, + "caller": "LOLS0MQ6sKprHDYVgwfYaMm0ypRmVU0T6oYQxrx3Bks", + "functionName": "transfer", + "functionArguments": { + "function": "transfer", + "qty": 1000000000000000, + "target": "DEgJqP8Zd4RBld0JCuc2U-UKtUJyNtLcW6jt4k6L1pQ" + }, + "foreignContractCalls": { + "dataType": "Map", + "value": [] + } + }, + "interactionOutput": { + "cacheHit": false, + "intermediaryCacheHit": false, + "executionTime": 1 + } + } + ], + [ + "6IOtBWPh-9loPiJ8V2zIo1NzGtYNn4kA_Xdt9P1IIFg", + { + "interactionInput": { + "txId": "6IOtBWPh-9loPiJ8V2zIo1NzGtYNn4kA_Xdt9P1IIFg", + "blockHeight": 880001, + "blockTimestamp": 1645692336, + "caller": "LOLS0MQ6sKprHDYVgwfYaMm0ypRmVU0T6oYQxrx3Bks", + "functionArguments": [ + { + "function": "transfer", + "qty": 1000000000000000, + "target": "kyGgyXpsHGX8wT9Oe4rsIGNb7ilybknVvSjcrLKVt1Y" + }, + { + "function": "transfer", + "qty": 1000000000000000, + "target": "SFvtYkST38oYwQGG1NuVeA7EMaM2QLhzBXGwDXe1fjg" + } + ], + "foreignContractCalls": { + "dataType": "Map", + "value": [] + } + }, + "interactionOutput": { + "cacheHit": false, + "intermediaryCacheHit": false, + "executionTime": 2, + "errorMessage": "No function supplied or function not recognised: \\" + undefined + \ + \ + "" + } + } + ], + [ + "ipmwMylSfoiXUPqm8e5_oLvzWAoel98jRt00ewJa7hk", + { + "interactionInput": { + "txId": "ipmwMylSfoiXUPqm8e5_oLvzWAoel98jRt00ewJa7hk", + "blockHeight": 880051, + "blockTimestamp": 1645698048, + "caller": "LOLS0MQ6sKprHDYVgwfYaMm0ypRmVU0T6oYQxrx3Bks", + "functionArguments": "[{\\" + function + \ + \ + ":\\" + transfer + \ + \ + ",\\" + qty + \ + \ + ":1000000000000000,\\" + target + \ + \ + ":\\" + kyGgyXpsHGX8wT9Oe4rsIGNb7ilybknVvSjcrLKVt1Y + \ + \ + "},{\\" + function + \ + \ + ":\\" + transfer + \ + \ + ",\\" + qty + \ + \ + ":1000000000000000,\\" + target + \ + \ + ":\\" + SFvtYkST38oYwQGG1NuVeA7EMaM2QLhzBXGwDXe1fjg + \ + \ + "}]", + "foreignContractCalls": { + "dataType": "Map", + "value": [] + } + }, + "interactionOutput": { + "cacheHit": false, + "intermediaryCacheHit": false, + "executionTime": 1, + "errorMessage": "No function supplied or function not recognised: \\" + undefined + \ + \ + "" + } + } + ] + ] + } +}