Skip to content

Commit

Permalink
feat: storing info about contract type and contract lang in tags
Browse files Browse the repository at this point in the history
  • Loading branch information
ppedziwiatr committed Feb 22, 2022
1 parent 0e4d896 commit a679c04
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 44 deletions.
Binary file modified src/__tests__/integration/data/wasm/counter.wasm
Binary file not shown.
15 changes: 10 additions & 5 deletions src/__tests__/integration/wasm-deploy-write-read.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import fs from 'fs';
import ArLocal from 'arlocal';
import Arweave from 'arweave';
import { JWKInterface } from 'arweave/node/lib/wallet';
import { Contract, LoggerFactory, SmartWeave, SmartWeaveNodeFactory } from '@smartweave';
import {Contract, getTag, LoggerFactory, SmartWeave, SmartWeaveNodeFactory, SmartWeaveTags} from '@smartweave';
import path from 'path';
import { addFunds, mineBlock } from './_helpers';

Expand Down Expand Up @@ -68,7 +68,14 @@ describe('Testing the SmartWeave client for WASM contract', () => {

it('should properly deploy contract', async () => {
const contractTx = await arweave.transactions.get(contractTxId);

expect(contractTx).not.toBeNull();
expect(getTag(contractTx, SmartWeaveTags.CONTRACT_TYPE)).toEqual('wasm');
expect(getTag(contractTx, SmartWeaveTags.WASM_LANG)).toEqual('assemblyscript');

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('assemblyscript');
});

it('should properly read initial state', async () => {
Expand Down Expand Up @@ -122,8 +129,8 @@ describe('Testing the SmartWeave client for WASM contract', () => {
function: 'infLoop'
});

expect(result.type).toEqual("exception");
expect(result.errorMessage.startsWith("[RE:OOG")).toBeTruthy();
expect(result.type).toEqual('exception');
expect(result.errorMessage.startsWith('[RE:OOG')).toBeTruthy();
});

/*it('should skip interaction during contract state read if gas limit exceeded', async () => {
Expand All @@ -139,6 +146,4 @@ describe('Testing the SmartWeave client for WASM contract', () => {
expect(callStack.getInteraction(txId)).toEqual({});
});*/


});
2 changes: 1 addition & 1 deletion src/core/ContractDefinition.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* This type contains all data and meta-data of the given contact.
*/
import {ContractType} from "./modules/CreateContract";
import { ContractType } from './modules/CreateContract';

export type ContractDefinition<State> = {
txId: string;
Expand Down
4 changes: 3 additions & 1 deletion src/core/SmartWeaveTags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@ export enum SmartWeaveTags {
MIN_FEE = 'Min-Fee',
INIT_STATE = 'Init-State',
INIT_STATE_TX = 'Init-State-TX',
INTERACT_WRITE = 'Interact-Write'
INTERACT_WRITE = 'Interact-Write',
WASM_LANG = 'Wasm-Lang',
CONTRACT_TYPE = 'Contract-Type'
}
2 changes: 2 additions & 0 deletions src/core/modules/CreateContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export interface ContractData extends CommonContractData {

export interface FromSrcTxContractData extends CommonContractData {
srcTxId: string;
contractType: ContractType;
wasmLang: string | null;
}

export interface CreateContract {
Expand Down
4 changes: 1 addition & 3 deletions src/core/modules/impl/ContractDefinitionLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ import {
import Arweave from 'arweave';
import Transaction from 'arweave/web/lib/transaction';

const supportedSrcContentTypes = [
'application/javascript', 'application/wasm'
];
const supportedSrcContentTypes = ['application/javascript', 'application/wasm'];

export class ContractDefinitionLoader implements DefinitionLoader {
private readonly logger = LoggerFactory.INST.create('ContractDefinitionLoader');
Expand Down
47 changes: 46 additions & 1 deletion src/core/modules/impl/DefaultCreateContract.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
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';

const wasmTypeMapping: Map<number, string> = new Map([
[1, 'assemblyscript'],
[2, 'rust'],
[3, 'go'],
[4, 'swift'],
[5, 'c']
]);

export class DefaultCreateContract implements CreateContract {
private readonly logger = LoggerFactory.INST.create('DefaultCreateContract');
Expand All @@ -24,6 +33,27 @@ export class DefaultCreateContract implements CreateContract {
srcTx.addTag(SmartWeaveTags.SDK, 'RedStone');
srcTx.addTag(SmartWeaveTags.CONTENT_TYPE, contractType == 'js' ? 'application/javascript' : 'application/wasm');

let wasmLang = null;

if (contractType == 'wasm') {
// note: instantiating wasm module for a while just to check
// the exported "type" value - which holds info about source lang.
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`);
}
// @ts-ignore
const type = module.instance.exports.type.value;
if (!wasmTypeMapping.has(type)) {
throw new Error(`Unknown wasm source type ${type}`);
}

wasmLang = wasmTypeMapping.get(type);

srcTx.addTag(SmartWeaveTags.WASM_LANG, wasmLang);
}

await this.arweave.transactions.sign(srcTx, wallet);

this.logger.debug('Posting transaction with source');
Expand All @@ -34,6 +64,8 @@ export class DefaultCreateContract implements CreateContract {
srcTxId: srcTx.id,
wallet,
initState,
contractType,
wasmLang,
tags,
transfer
});
Expand Down Expand Up @@ -71,6 +103,10 @@ export class DefaultCreateContract implements CreateContract {
contractTX.addTag(SmartWeaveTags.CONTRACT_SRC_TX_ID, srcTxId);
contractTX.addTag(SmartWeaveTags.SDK, 'RedStone');
contractTX.addTag(SmartWeaveTags.CONTENT_TYPE, 'application/json');
contractTX.addTag(SmartWeaveTags.CONTRACT_TYPE, contractData.contractType);
if (contractData.contractType == 'wasm') {
contractTX.addTag(SmartWeaveTags.WASM_LANG, contractData.wasmLang);
}

await this.arweave.transactions.sign(contractTX, wallet);

Expand All @@ -82,3 +118,12 @@ export class DefaultCreateContract implements CreateContract {
}
}
}

function dummyImports() {
return imports(
{
useGas: function () {}
} as any,
null
);
}
6 changes: 3 additions & 3 deletions src/core/modules/impl/HandlerExecutorFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import { ContractHandlerApi } from './ContractHandlerApi';
import loader from '@assemblyscript/loader';
import { imports } from './wasmImports';
import { WasmContractHandlerApi } from './WasmContractHandlerApi';
import metering from 'wasm-metering';

const metering = require('wasm-metering');
/**
* A factory that produces handlers that are compatible with the "current" style of
* writing SW contracts (ie. using "handle" function).
Expand All @@ -32,7 +32,7 @@ export class HandlerExecutorFactory implements ExecutorFactory<HandlerApi<unknow

if (contractDefinition.contractType == 'js') {
this.logger.info('Creating handler for js contract', contractDefinition.txId);
let normalizedSource =
const normalizedSource =
contractDefinition.src instanceof Buffer
? normalizeContractSource(this.arweave.utils.bufferToString(contractDefinition.src))
: normalizeContractSource(contractDefinition.src);
Expand All @@ -43,7 +43,7 @@ export class HandlerExecutorFactory implements ExecutorFactory<HandlerApi<unknow
} else {
this.logger.info('Creating handler for wasm contract', contractDefinition.txId);

let wasmModuleData = {
const wasmModuleData = {
exports: null
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class RedstoneGatewayContractDefinitionLoader extends ContractDefinitionL
}
throw new Error(`Unable to retrieve contract data. Redstone gateway responded with status ${error.status}.`);
});
result.contractType = "js"; // TODO: Add support in redstone gateway
result.contractType = 'js'; // TODO: Add support in redstone gateway
return result;
} catch (e) {
this.rLogger.warn('Falling back to default contracts loader');
Expand Down
63 changes: 34 additions & 29 deletions src/core/modules/impl/wasmImports.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {LoggerFactory, SmartWeaveGlobal} from "@smartweave";
import { LoggerFactory, SmartWeaveGlobal } from '@smartweave';

export const imports = (swGlobal: SmartWeaveGlobal, wasmModule: any): any => {
const wasmLogger = LoggerFactory.INST.create('WASM');
Expand All @@ -8,69 +8,74 @@ export const imports = (swGlobal: SmartWeaveGlobal, wasmModule: any): any => {
usegas: swGlobal.useGas
},
console: {
"console.log": function (msgPtr) {
'console.log': function (msgPtr) {
wasmLogger.debug(`${swGlobal.contract.id}: ${wasmModule.exports.__getString(msgPtr)}`);
},
"console.logO": function (msgPtr, objPtr) {
wasmLogger.debug(`${swGlobal.contract.id}: ${wasmModule.exports.__getString(msgPtr)}`, JSON.parse(wasmModule.exports.__getString(objPtr)));
},
'console.logO': function (msgPtr, objPtr) {
wasmLogger.debug(
`${swGlobal.contract.id}: ${wasmModule.exports.__getString(msgPtr)}`,
JSON.parse(wasmModule.exports.__getString(objPtr))
);
}
},
block: {
"Block.height": function () {
'Block.height': function () {
return swGlobal.block.height;
},
"Block.indep_hash": function () {
'Block.indep_hash': function () {
return wasmModule.exports.__newString(swGlobal.block.indep_hash);
},
"Block.timestamp": function () {
'Block.timestamp': function () {
return swGlobal.block.timestamp;
},
}
},
transaction: {
"Transaction.id": function () {
'Transaction.id': function () {
return wasmModule.exports.__newString(swGlobal.transaction.id);
},
"Transaction.owner": function () {
'Transaction.owner': function () {
return wasmModule.exports.__newString(swGlobal.transaction.owner);
},
"Transaction.target": function () {
'Transaction.target': function () {
return wasmModule.exports.__newString(swGlobal.transaction.target);
},
}
},
contract: {
"Contract.id": function () {
'Contract.id': function () {
return wasmModule.exports.__newString(swGlobal.contract.id);
},
"Contract.owner": function () {
'Contract.owner': function () {
return wasmModule.exports.__newString(swGlobal.contract.owner);
},
}
},
api: {
_readContractState: (fnIndex, contractTxIdPtr) => {
const contractTxId = wasmModule.exports.__getString(contractTxIdPtr);
const callbackFn = getFn(fnIndex);
console.log("Simulating read state of", contractTxId);
console.log('Simulating read state of', contractTxId);
return setTimeout(() => {
console.log('calling callback');
callbackFn(wasmModule.exports.__newString(JSON.stringify({
contractTxId
})));
callbackFn(
wasmModule.exports.__newString(
JSON.stringify({
contractTxId
})
)
);
}, 1000);
},
clearTimeout,
clearTimeout
},
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('--------------------- Error message from AssemblyScript ----------------------');
console.error(' ' + wasmModule.exports.__getString(messagePtr));
console.error(' In file "' + wasmModule.exports.__getString(fileNamePtr) + '"');
console.error(` on line ${line}, column ${column}.`);
console.error("------------------------------------------------------------------------------\n");
},
console.error('------------------------------------------------------------------------------\n');
}
}
}
};

function getFn(idx) {
return wasmModule.exports.table.get(idx);
Expand Down
Binary file modified tools/data/wasm/counter.wasm
Binary file not shown.

0 comments on commit a679c04

Please sign in to comment.