feat: storing info about contract type and contract lang in tags

This commit is contained in:
ppedziwiatr
2022-02-21 16:24:44 +01:00
committed by Piotr Pędziwiatr
parent 0e4d896d8e
commit a679c04ebe
11 changed files with 101 additions and 44 deletions

View File

@@ -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';
@@ -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 () => {
@@ -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 () => {
@@ -139,6 +146,4 @@ describe('Testing the SmartWeave client for WASM contract', () => {
expect(callStack.getInteraction(txId)).toEqual({});
});*/
});

View File

@@ -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;

View File

@@ -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'
}

View File

@@ -29,6 +29,8 @@ export interface ContractData extends CommonContractData {
export interface FromSrcTxContractData extends CommonContractData {
srcTxId: string;
contractType: ContractType;
wasmLang: string | null;
}
export interface CreateContract {

View File

@@ -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');

View File

@@ -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');
@@ -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');
@@ -34,6 +64,8 @@ export class DefaultCreateContract implements CreateContract {
srcTxId: srcTx.id,
wallet,
initState,
contractType,
wasmLang,
tags,
transfer
});
@@ -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);
@@ -82,3 +118,12 @@ export class DefaultCreateContract implements CreateContract {
}
}
}
function dummyImports() {
return imports(
{
useGas: function () {}
} as any,
null
);
}

View File

@@ -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).
@@ -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);
@@ -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
};

View File

@@ -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');

View File

@@ -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');
@@ -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);

Binary file not shown.