Skip to content

Commit

Permalink
feat: add contract test webui
Browse files Browse the repository at this point in the history
  • Loading branch information
eng-cc committed Aug 18, 2023
1 parent 2b54cdf commit d370b20
Show file tree
Hide file tree
Showing 19 changed files with 252 additions and 142 deletions.
1 change: 1 addition & 0 deletions packages/contract/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"scripts": {
"test": "tsc -p ./tsconfig.build.json && node ./dist/src/cli.js build ./examples/coin/index.ts && rm -rf ./dist",
"gen-proto": "protoc --ts_out ./src/proto_ts --proto_path ../skvm/proto ../skvm/proto/*.proto",
"dev-build": "tsc -w -p ./tsconfig.build.json",
"build": "tsc -p ./tsconfig.build.json"
},
"engines": {
Expand Down
2 changes: 2 additions & 0 deletions packages/contract/src/index.mts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { EvalResult } from './proto_ts/eval_result.js';
export { init } from '@trustack/vm';

export { EvalResult } from './proto_ts/eval_result.js';

export { evalClass, evalFunction, evalCode } from './vm.js';
export interface EvaluateParams {
codeString: string[];
cuLimit: bigint;
Expand Down
54 changes: 54 additions & 0 deletions packages/contract/src/vm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { bytes } from 'multiformats';
import { BUILDER_NAMES, evaluate, init } from './index.mjs';
import type { EvalResult } from './proto_ts/eval_result.js';

const defaultCuLimit = 1000000n;

export const evalFunction = async (codeStr: string): Promise<EvalResult> => {
await init();
const codeString = [
`
const evalFn = ${codeStr}`,
`
evalFn()
`,
];
return evaluate({
codeString,
cuLimit: defaultCuLimit,
storage: bytes.fromString(''),
});
};

export const evalClass = async (
codeStr: string,
method: string,
params: string[] = [],
): Promise<EvalResult> => {
await init();
const codeString = [
`
${codeStr}
`,
`
const __run__class__ = new ${BUILDER_NAMES.CONTRACT_CLASS_NAME}();
__run__class__.${BUILDER_NAMES.CONSTRUCTOR_METHOD}();
__run__class__.${method}(${params?.join(',')});
`,
];
return evaluate({
codeString,
cuLimit: defaultCuLimit,
storage: bytes.fromString(''),
});
};

export const evalCode = async (code: string): Promise<EvalResult> => {
await init();
return evaluate({
codeString: [code],
cuLimit: defaultCuLimit,
storage: bytes.fromString(''),
});
};
132 changes: 66 additions & 66 deletions packages/contract_builder/src/ast.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type {
CallExpression,
ClassProperty,
ExportDeclaration,
ExportDefaultDeclaration,
Expression,
ExpressionStatement,
Program,
Expand All @@ -29,82 +30,81 @@ export const walkTop = (ast: Program): Program => {
}
});

// remove export
// ast.body = ast.body.map((topNode, i) => {
// if (
// ['ExportDeclaration', 'ExportDefaultDeclaration'].includes(topNode.type)
// ) {
// // remove export
// return (topNode as ExportDeclaration).declaration;
// }
// return topNode;
// });

// 除super之外的constructor逻辑
const constructorExpressionStatements: ExpressionStatement[] = [];
ast.body = ast.body.map((topNode, i) => {
if (topNode.type === 'ClassDeclaration') {
topNode.identifier.value = BUILDER_NAMES.CONTRACT_CLASS_NAME;
topNode.body = topNode.body.map((classNode) => {
if (classNode.type === 'Constructor') {
// chnage constructor to __constructor
// 将super()与其他逻辑分离
while (
classNode.body?.stmts.length &&
classNode.body?.stmts.length > 1
) {
if (
classNode.body.stmts[classNode.body.stmts.length - 1].type ===
'ExpressionStatement'
ast.body = ast.body.map((topTopNode, i) => {

Check warning on line 35 in packages/contract_builder/src/ast.utils.ts

View workflow job for this annotation

GitHub Actions / check

'i' is defined but never used. Allowed unused args must match /^_/u
if (
['ExportDeclaration', 'ExportDefaultDeclaration'].includes(
topTopNode.type,
)
) {
const topNode =
(topTopNode as ExportDeclaration).declaration ||
(topTopNode as ExportDefaultDeclaration).decl;

if (topNode.type === 'ClassDeclaration') {
topNode.identifier.value = BUILDER_NAMES.CONTRACT_CLASS_NAME;
topNode.body = topNode.body.map((classNode) => {
if (classNode.type === 'Constructor') {
// chnage constructor to __constructor
// 将super()与其他逻辑分离
while (
classNode.body?.stmts.length &&
classNode.body?.stmts.length > 1
) {
if (!isSuperBlock(classNode.body)) {
const exp = classNode.body.stmts.pop();
if (exp) {
// must use unshift,保证代码顺序
constructorExpressionStatements.unshift(
exp as ExpressionStatement,
);
if (
classNode.body.stmts[classNode.body.stmts.length - 1].type ===
'ExpressionStatement'
) {
if (!isSuperBlock(classNode.body)) {
const exp = classNode.body.stmts.pop();
if (exp) {
// must use unshift,保证代码顺序
constructorExpressionStatements.unshift(
exp as ExpressionStatement,
);
}
}
}
}
}
}
return classNode;
});
const replacedConstructor: ClassProperty = {
type: 'ClassProperty',
key: {
type: 'Identifier',
span: emptySpan(),
value: BUILDER_NAMES.CONSTRUCTOR_METHOD,
optional: false,
},
value: {
type: 'ArrowFunctionExpression',
span: emptySpan(),
params: [],
body: {
type: 'BlockStatement',
return classNode;
});
const replacedConstructor: ClassProperty = {
type: 'ClassProperty',
key: {
type: 'Identifier',
span: emptySpan(),
stmts: constructorExpressionStatements,
value: BUILDER_NAMES.CONSTRUCTOR_METHOD,
optional: false,
},
async: false,
generator: false,
},
span: emptySpan(),
isStatic: false,
decorators: [],
accessibility: 'public',
isAbstract: false,
isOptional: false,
isOverride: false,
readonly: false,
declare: false,
definite: false,
};
topNode.body.push(replacedConstructor);
value: {
type: 'ArrowFunctionExpression',
span: emptySpan(),
params: [],
body: {
type: 'BlockStatement',
span: emptySpan(),
stmts: constructorExpressionStatements,
},
async: false,
generator: false,
},
span: emptySpan(),
isStatic: false,
decorators: [],
accessibility: 'public',
isAbstract: false,
isOptional: false,
isOverride: false,
readonly: false,
declare: false,
definite: false,
};
topNode.body.push(replacedConstructor);
}
}
return topNode;
return topTopNode;
});
return ast;
};
Expand Down
12 changes: 3 additions & 9 deletions packages/contract_builder/src/builder.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
import { walkTop } from './ast.utils.js';
import {
Output,
Program,
Options,
ParseOptions,
parseSync,
bundle,
} from '@swc/core';
import { Output, Program, Options, ParseOptions, parseSync } from '@swc/core';
import { rollup } from 'rollup';
import terser from '@rollup/plugin-terser';
import typescript from 'rollup-plugin-typescript2';
Expand Down Expand Up @@ -66,5 +59,6 @@ export const boundleContract = async (entry: string) => {
format: 'esm',
sourcemap: false,
});
return res.output[0].code;
const code = res.output[0].code.replace(/export{.+};/g, '');
return code;
};
1 change: 0 additions & 1 deletion packages/skchain/src/index.mts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export type { DidJson } from '@trustack/common';
export { evalFunction } from './lib/contract/vm.js';

export { SKChain } from './skChain.js';
export { Address } from './mate/address.js';
Expand Down
2 changes: 1 addition & 1 deletion packages/skchain/src/lib/contract/__tests__/vm.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { testAccounts, testContracts } from '@trustack/common';
import { evalClass, evalFunction } from '@trustack/contract';
import { Address } from '../../../mate/address.js';
import { generateBaseContractCode } from '../codeSnippet.js';
import { evalClass, evalFunction } from '../vm.js';

describe('vm', () => {
describe('test', () => {
Expand Down
43 changes: 0 additions & 43 deletions packages/skchain/src/lib/contract/vm.ts

This file was deleted.

1 change: 1 addition & 0 deletions packages/webui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"esbuild": "^0.17.19",
"lodash": "^4.17.21",
"mime-types": "^2.1.35",
"monaco-editor": "^0.41.0",
"multiformats": "^11.0.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
Expand Down
4 changes: 2 additions & 2 deletions packages/webui/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { useRoutes } from 'react-router-dom';
import './App.css';
import CiPage from './ci';
import { VisPage } from './vis';
import { VMPage } from './skvm';

function App() {
const element = useRoutes([
{ path: '/ci', element: <CiPage /> },
{ path: 'vis', element: <VisPage /> },
{ path: '/vm', element: <VMPage /> },
]);
return element;
}
Expand Down
9 changes: 0 additions & 9 deletions packages/webui/src/ci/contract/builder.ts

This file was deleted.

10 changes: 0 additions & 10 deletions packages/webui/src/ci/contract/test.ts

This file was deleted.

14 changes: 14 additions & 0 deletions packages/webui/src/ci/contract/testRunner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { bytes } from 'multiformats';
import { evalClass } from 'skchain';

export const runBuildContractTest = async (): Promise<boolean> => {
const codeByte = (await import('./test.contract.js')) as unknown as {
default: Uint8Array;
};
const codeString = bytes.toString(codeByte.default);

console.log(codeString);
evalClass(codeString, 'getValue');
// TODO: eval code to test
return true;
};
2 changes: 1 addition & 1 deletion packages/webui/src/ci/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Button } from 'antd';
import { useState } from 'react';
import { runBuildContractTest } from './contract/test';
import { runBuildContractTest } from './contract/testRunner';
import { runContractTest, runSkvmTest, runTest } from './run';

export default function CiPage() {
Expand Down
5 changes: 5 additions & 0 deletions packages/webui/src/components/monacoEditor/editor.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.monaco-editor {
width: 50vw;
height: 50vh;
border: 1px solid #ccc;
}
Loading

0 comments on commit d370b20

Please sign in to comment.