feat: enable evolve for all contracts
This commit is contained in:
@@ -112,7 +112,7 @@ describe('Testing the Profit Sharing Token', () => {
|
||||
|
||||
const newSource = fs.readFileSync(path.join(__dirname, '../data/token-evolve.js'), 'utf8');
|
||||
|
||||
const newSrcTxId = await pst.saveNewSource(newSource);
|
||||
const newSrcTxId = await pst.saveSource({ src: newSource });
|
||||
await mineBlock(arweave);
|
||||
|
||||
await pst.evolve(newSrcTxId);
|
||||
|
||||
@@ -131,7 +131,7 @@ describe('Testing the Profit Sharing Token', () => {
|
||||
|
||||
const newSource = fs.readFileSync(path.join(__dirname, '../data/token-evolve.js'), 'utf8');
|
||||
|
||||
const newSrcTxId = await pst.saveNewSource(newSource);
|
||||
const newSrcTxId = await pst.saveSource({ src: newSource });
|
||||
await mineBlock(arweave);
|
||||
|
||||
await pst.evolve(newSrcTxId);
|
||||
|
||||
@@ -6,7 +6,8 @@ import {
|
||||
EvaluationOptions,
|
||||
GQLNodeInterface,
|
||||
InteractionResult,
|
||||
Tags
|
||||
Tags,
|
||||
SaveSource
|
||||
} from '@smartweave';
|
||||
import { NetworkInfoInterface } from 'arweave/node/network';
|
||||
import Transaction from 'arweave/node/lib/transaction';
|
||||
@@ -16,11 +17,27 @@ export type BenchmarkStats = { gatewayCommunication: number; stateEvaluation: nu
|
||||
|
||||
export type SigningFunction = (tx: Transaction) => Promise<void>;
|
||||
|
||||
/**
|
||||
* Interface describing state for all Evolve-compatible contracts.
|
||||
*/
|
||||
export interface EvolveState {
|
||||
settings: any[] | unknown | null;
|
||||
/**
|
||||
* whether contract is allowed to evolve. seems to default to true..
|
||||
*/
|
||||
canEvolve: boolean;
|
||||
|
||||
/**
|
||||
* the transaction id of the Arweave transaction with the updated source code.
|
||||
*/
|
||||
evolve: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A base interface to be implemented by SmartWeave Contracts clients
|
||||
* - contains "low-level" methods that allow to interact with any contract
|
||||
*/
|
||||
export interface Contract<State = unknown> {
|
||||
export interface Contract<State = unknown> extends SaveSource {
|
||||
/**
|
||||
* Returns the Arweave transaction id of this contract.
|
||||
*/
|
||||
@@ -217,4 +234,14 @@ export interface Contract<State = unknown> {
|
||||
* @param nodeAddress - distributed execution network node address
|
||||
*/
|
||||
syncState(nodeAddress: string): Promise<Contract>;
|
||||
|
||||
/**
|
||||
* Evolve is a feature that allows to change contract's source
|
||||
* code, without having to deploy a new contract.
|
||||
* This method effectively evolves the contract to the source.
|
||||
* This requires the {@link saveSource} to be called first
|
||||
* and its transaction to be confirmed by the network.
|
||||
* @param newSrcTxId - result of the {@link saveSource} method call.
|
||||
*/
|
||||
evolve(newSrcTxId: string): Promise<string | null>;
|
||||
}
|
||||
|
||||
@@ -29,14 +29,15 @@ import {
|
||||
SmartWeave,
|
||||
SmartWeaveTags,
|
||||
SourceType,
|
||||
Tags
|
||||
Tags,
|
||||
SaveSourceImpl,
|
||||
SaveSourceData
|
||||
} from '@smartweave';
|
||||
import { TransactionStatusResponse } from 'arweave/node/transactions';
|
||||
import { NetworkInfoInterface } from 'arweave/node/network';
|
||||
import stringify from 'safe-stable-stringify';
|
||||
import * as crypto from 'crypto';
|
||||
import Transaction from 'arweave/node/lib/transaction';
|
||||
import { options } from 'tsconfig-paths/lib/options';
|
||||
|
||||
/**
|
||||
* An implementation of {@link Contract} that is backwards compatible with current style
|
||||
@@ -765,4 +766,20 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
async evolve(newSrcTxId: string): Promise<string | null> {
|
||||
return await this.writeInteraction<any>({ function: 'evolve', value: newSrcTxId });
|
||||
}
|
||||
|
||||
async saveSource(saveSourceData: SaveSourceData): Promise<any> {
|
||||
if (!this.signer) {
|
||||
throw new Error("Wallet not connected. Use 'connect' method first.");
|
||||
}
|
||||
const { arweave } = this.smartweave;
|
||||
const source = new SaveSourceImpl(arweave);
|
||||
|
||||
const srcTx = await source.saveSource(saveSourceData, this.signer);
|
||||
|
||||
return srcTx.id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Contract } from '@smartweave';
|
||||
import { EvolveState } from './Contract';
|
||||
|
||||
/**
|
||||
* The result from the "balance" view method on the PST Contract.
|
||||
@@ -9,44 +10,6 @@ export interface BalanceResult {
|
||||
balance: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for all contracts the implement the {@link Evolve} feature.
|
||||
* Evolve is a feature that allows to change contract's source
|
||||
* code, without having to deploy a new contract.
|
||||
* See ({@link Evolve})
|
||||
*/
|
||||
export interface EvolvingContract {
|
||||
/**
|
||||
* allows to post new contract source on Arweave
|
||||
* @param newContractSource - new contract source...
|
||||
*/
|
||||
saveNewSource(newContractSource: string): Promise<string | null>;
|
||||
|
||||
/**
|
||||
* effectively evolves the contract to the source.
|
||||
* This requires the {@link saveNewSource} to be called first
|
||||
* and its transaction to be confirmed by the network.
|
||||
* @param newSrcTxId - result of the {@link saveNewSource} method call.
|
||||
*/
|
||||
evolve(newSrcTxId: string): Promise<string | null>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface describing state for all Evolve-compatible contracts.
|
||||
*/
|
||||
export interface EvolveState {
|
||||
settings: any[] | unknown | null;
|
||||
/**
|
||||
* whether contract is allowed to evolve. seems to default to true..
|
||||
*/
|
||||
canEvolve: boolean;
|
||||
|
||||
/**
|
||||
* the transaction id of the Arweave transaction with the updated source code.
|
||||
*/
|
||||
evolve: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface describing base state for all PST contracts.
|
||||
*/
|
||||
@@ -70,7 +33,7 @@ export interface TransferInput {
|
||||
* A type of {@link Contract} designed specifically for the interaction with
|
||||
* Profit Sharing Token contract.
|
||||
*/
|
||||
export interface PstContract extends Contract<PstState>, EvolvingContract {
|
||||
export interface PstContract extends Contract<PstState> {
|
||||
/**
|
||||
* return the current balance for the given wallet
|
||||
* @param target - wallet address
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { SmartWeaveTags } from '@smartweave';
|
||||
import { BalanceResult, HandlerBasedContract, PstContract, PstState, TransferInput } from '@smartweave/contract';
|
||||
|
||||
interface BalanceInput {
|
||||
@@ -22,25 +21,4 @@ export class PstContractImpl extends HandlerBasedContract<PstState> implements P
|
||||
async transfer(transfer: TransferInput): Promise<string | null> {
|
||||
return await this.writeInteraction<any>({ function: 'transfer', ...transfer });
|
||||
}
|
||||
|
||||
async evolve(newSrcTxId: string): Promise<string | null> {
|
||||
return await this.writeInteraction<any>({ function: 'evolve', value: newSrcTxId });
|
||||
}
|
||||
|
||||
async saveNewSource(newContractSource: string): Promise<string | null> {
|
||||
if (!this.signer) {
|
||||
throw new Error("Wallet not connected. Use 'connect' method first.");
|
||||
}
|
||||
const { arweave } = this.smartweave;
|
||||
|
||||
const tx = await arweave.createTransaction({ data: newContractSource });
|
||||
tx.addTag(SmartWeaveTags.APP_NAME, 'SmartWeaveContractSource');
|
||||
tx.addTag(SmartWeaveTags.APP_VERSION, '0.3.0');
|
||||
tx.addTag('Content-Type', 'application/javascript');
|
||||
|
||||
await this.signer(tx);
|
||||
await arweave.transactions.post(tx);
|
||||
|
||||
return tx.id;
|
||||
}
|
||||
}
|
||||
|
||||
15
src/contract/SaveSource.ts
Normal file
15
src/contract/SaveSource.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { ArWallet } from '@smartweave/core';
|
||||
import { SigningFunction } from './Contract';
|
||||
import { SaveSourceData } from './SaveSourceImpl';
|
||||
|
||||
export interface SaveSource {
|
||||
/**
|
||||
* allows to post contract source on Arweave
|
||||
* @param newContractSource - new contract source...
|
||||
*/
|
||||
saveSource(
|
||||
contractSource: SaveSourceData,
|
||||
signer: ArWallet | SigningFunction,
|
||||
useBundler?: boolean
|
||||
): Promise<string | null>;
|
||||
}
|
||||
186
src/contract/SaveSourceImpl.ts
Normal file
186
src/contract/SaveSourceImpl.ts
Normal file
@@ -0,0 +1,186 @@
|
||||
import { ArWallet, ContractData, ContractType, SmartWeaveTags } from '@smartweave/core';
|
||||
import { LoggerFactory } from '@smartweave/logging';
|
||||
import { SaveSource, SigningFunction } from '@smartweave';
|
||||
import metering from 'redstone-wasm-metering';
|
||||
import Arweave from 'arweave';
|
||||
import { Go } from '../core/modules/impl/wasm/go-wasm-imports';
|
||||
import fs, { PathOrFileDescriptor } from 'fs';
|
||||
import { matchMutClosureDtor } from '../core/modules/impl/wasm/wasm-bindgen-tools';
|
||||
|
||||
const wasmTypeMapping: Map<number, string> = new Map([
|
||||
[1, 'assemblyscript'],
|
||||
[2, 'rust'],
|
||||
[3, 'go']
|
||||
/*[4, 'swift'],
|
||||
[5, 'c']*/
|
||||
]);
|
||||
|
||||
export interface SaveSourceData {
|
||||
src: string | Buffer;
|
||||
wasmSrcCodeDir?: string;
|
||||
wasmGlueCode?: string;
|
||||
}
|
||||
|
||||
export class SaveSourceImpl implements SaveSource {
|
||||
private readonly logger = LoggerFactory.INST.create('SaveSource');
|
||||
constructor(private readonly arweave: Arweave) {}
|
||||
|
||||
async saveSource(contractData: SaveSourceData, signer: ArWallet | SigningFunction, useBundler = false): Promise<any> {
|
||||
this.logger.debug('Creating new contract');
|
||||
|
||||
const { src, wasmSrcCodeDir, wasmGlueCode } = contractData;
|
||||
|
||||
const contractType: ContractType = src instanceof Buffer ? 'wasm' : 'js';
|
||||
let srcTx;
|
||||
let wasmLang = null;
|
||||
let wasmVersion = null;
|
||||
const metadata = {};
|
||||
|
||||
const data: Buffer[] = [];
|
||||
|
||||
if (contractType == 'wasm') {
|
||||
const meteredWasmBinary = metering.meterWASM(src, {
|
||||
meterType: 'i32'
|
||||
});
|
||||
data.push(meteredWasmBinary);
|
||||
|
||||
const wasmModule = await WebAssembly.compile(src as Buffer);
|
||||
const moduleImports = WebAssembly.Module.imports(wasmModule);
|
||||
let lang: number;
|
||||
|
||||
if (this.isGoModule(moduleImports)) {
|
||||
const go = new Go(null);
|
||||
const module = new WebAssembly.Instance(wasmModule, go.importObject);
|
||||
// DO NOT await here!
|
||||
go.run(module);
|
||||
lang = go.exports.lang();
|
||||
wasmVersion = go.exports.version();
|
||||
} else {
|
||||
const module: WebAssembly.Instance = await WebAssembly.instantiate(src, dummyImports(moduleImports));
|
||||
// @ts-ignore
|
||||
if (!module.instance.exports.lang) {
|
||||
throw new Error(`No info about source type in wasm binary. Did you forget to export "lang" function?`);
|
||||
}
|
||||
// @ts-ignore
|
||||
lang = module.instance.exports.lang();
|
||||
// @ts-ignore
|
||||
wasmVersion = module.instance.exports.version();
|
||||
if (!wasmTypeMapping.has(lang)) {
|
||||
throw new Error(`Unknown wasm source type ${lang}`);
|
||||
}
|
||||
}
|
||||
|
||||
wasmLang = wasmTypeMapping.get(lang);
|
||||
if (wasmSrcCodeDir == null) {
|
||||
throw new Error('No path to original wasm contract source code');
|
||||
}
|
||||
|
||||
const zippedSourceCode = await this.zipContents(wasmSrcCodeDir);
|
||||
data.push(zippedSourceCode);
|
||||
|
||||
if (wasmLang == 'rust') {
|
||||
if (!wasmGlueCode) {
|
||||
throw new Error('No path to generated wasm-bindgen js code');
|
||||
}
|
||||
const wasmBindgenSrc = fs.readFileSync(wasmGlueCode, 'utf-8');
|
||||
const dtor = matchMutClosureDtor(wasmBindgenSrc);
|
||||
metadata['dtor'] = parseInt(dtor);
|
||||
data.push(Buffer.from(wasmBindgenSrc));
|
||||
}
|
||||
}
|
||||
|
||||
const allData = contractType == 'wasm' ? this.joinBuffers(data) : src;
|
||||
|
||||
if (typeof signer == 'function') {
|
||||
srcTx = await this.arweave.createTransaction({ data: allData });
|
||||
} else {
|
||||
srcTx = await this.arweave.createTransaction({ data: allData }, signer);
|
||||
}
|
||||
|
||||
srcTx.addTag(SmartWeaveTags.APP_NAME, 'SmartWeaveContractSource');
|
||||
// TODO: version should be taken from the current package.json version.
|
||||
srcTx.addTag(SmartWeaveTags.APP_VERSION, '0.3.0');
|
||||
srcTx.addTag(SmartWeaveTags.SDK, 'RedStone');
|
||||
srcTx.addTag(SmartWeaveTags.CONTENT_TYPE, contractType == 'js' ? 'application/javascript' : 'application/wasm');
|
||||
|
||||
if (contractType == 'wasm') {
|
||||
srcTx.addTag(SmartWeaveTags.WASM_LANG, wasmLang);
|
||||
srcTx.addTag(SmartWeaveTags.WASM_LANG_VERSION, wasmVersion);
|
||||
srcTx.addTag(SmartWeaveTags.WASM_META, JSON.stringify(metadata));
|
||||
}
|
||||
|
||||
if (typeof signer == 'function') {
|
||||
await signer(srcTx);
|
||||
} else {
|
||||
await this.arweave.transactions.sign(srcTx, signer);
|
||||
}
|
||||
this.logger.debug('Posting transaction with source');
|
||||
|
||||
// note: in case of useBundler = true, we're posting both
|
||||
// src tx and contract tx in one request.
|
||||
let responseOk = true;
|
||||
if (!useBundler) {
|
||||
const response = await this.arweave.transactions.post(srcTx);
|
||||
responseOk = response.status === 200 || response.status === 208;
|
||||
}
|
||||
|
||||
if (responseOk) {
|
||||
return srcTx;
|
||||
} else {
|
||||
throw new Error(`Unable to write Contract Source`);
|
||||
}
|
||||
}
|
||||
|
||||
private isGoModule(moduleImports: WebAssembly.ModuleImportDescriptor[]) {
|
||||
return moduleImports.some((moduleImport) => {
|
||||
return moduleImport.module == 'env' && moduleImport.name.startsWith('syscall/js');
|
||||
});
|
||||
}
|
||||
|
||||
private joinBuffers(buffers: Buffer[]): Buffer {
|
||||
const length = buffers.length;
|
||||
const result = [];
|
||||
result.push(Buffer.from(length.toString()));
|
||||
result.push(Buffer.from('|'));
|
||||
buffers.forEach((b) => {
|
||||
result.push(Buffer.from(b.length.toString()));
|
||||
result.push(Buffer.from('|'));
|
||||
});
|
||||
result.push(...buffers);
|
||||
return result.reduce((prev, b) => Buffer.concat([prev, b]));
|
||||
}
|
||||
|
||||
private async zipContents(source: PathOrFileDescriptor): Promise<Buffer> {
|
||||
const archiver = require('archiver'),
|
||||
streamBuffers = require('stream-buffers');
|
||||
const outputStreamBuffer = new streamBuffers.WritableStreamBuffer({
|
||||
initialSize: 1000 * 1024, // start at 1000 kilobytes.
|
||||
incrementAmount: 1000 * 1024 // grow by 1000 kilobytes each time buffer overflows.
|
||||
});
|
||||
const archive = archiver('zip', {
|
||||
zlib: { level: 9 } // Sets the compression level.
|
||||
});
|
||||
archive.on('error', function (err: any) {
|
||||
throw err;
|
||||
});
|
||||
archive.pipe(outputStreamBuffer);
|
||||
archive.directory(source.toString(), source.toString());
|
||||
await archive.finalize();
|
||||
outputStreamBuffer.end();
|
||||
|
||||
return outputStreamBuffer.getContents();
|
||||
}
|
||||
}
|
||||
|
||||
function dummyImports(moduleImports: WebAssembly.ModuleImportDescriptor[]) {
|
||||
const imports = {};
|
||||
|
||||
moduleImports.forEach((moduleImport) => {
|
||||
if (!Object.prototype.hasOwnProperty.call(imports, moduleImport.module)) {
|
||||
imports[moduleImport.module] = {};
|
||||
}
|
||||
imports[moduleImport.module][moduleImport.name] = function () {};
|
||||
});
|
||||
|
||||
return imports;
|
||||
}
|
||||
@@ -3,3 +3,5 @@ export * from './HandlerBasedContract';
|
||||
export * from './PstContract';
|
||||
export * from './PstContractImpl';
|
||||
export * from './InnerWritesEvaluator';
|
||||
export * from './SaveSource';
|
||||
export * from './SaveSourceImpl';
|
||||
|
||||
@@ -2,21 +2,8 @@
|
||||
import { ContractData, ContractType, CreateContract, FromSrcTxContractData, SmartWeaveTags } from '@smartweave/core';
|
||||
import Arweave from 'arweave';
|
||||
import { LoggerFactory } from '@smartweave/logging';
|
||||
import { Go } from './wasm/go-wasm-imports';
|
||||
import metering from 'redstone-wasm-metering';
|
||||
import fs, { PathOrFileDescriptor } from 'fs';
|
||||
import { matchMutClosureDtor } from './wasm/wasm-bindgen-tools';
|
||||
import { parseInt } from 'lodash';
|
||||
import Transaction from 'arweave/node/lib/transaction';
|
||||
import stringify from 'safe-stable-stringify';
|
||||
|
||||
const wasmTypeMapping: Map<number, string> = new Map([
|
||||
[1, 'assemblyscript'],
|
||||
[2, 'rust'],
|
||||
[3, 'go']
|
||||
/*[4, 'swift'],
|
||||
[5, 'c']*/
|
||||
]);
|
||||
import { SaveSourceImpl } from '@smartweave/contract';
|
||||
|
||||
export class DefaultCreateContract implements CreateContract {
|
||||
private readonly logger = LoggerFactory.INST.create('DefaultCreateContract');
|
||||
@@ -26,109 +13,24 @@ export class DefaultCreateContract implements CreateContract {
|
||||
}
|
||||
|
||||
async deploy(contractData: ContractData, useBundler = false): Promise<string> {
|
||||
const { wallet, initState, tags, transfer } = contractData;
|
||||
|
||||
const source = new SaveSourceImpl(this.arweave);
|
||||
|
||||
const srcTx = await source.saveSource(contractData, wallet, useBundler);
|
||||
this.logger.debug('Creating new contract');
|
||||
|
||||
const { wallet, src, initState, tags, transfer, wasmSrcCodeDir, wasmGlueCode } = contractData;
|
||||
const contractType: ContractType = src instanceof Buffer ? 'wasm' : 'js';
|
||||
let srcTx;
|
||||
let wasmLang = null;
|
||||
let wasmVersion = null;
|
||||
const metadata = {};
|
||||
|
||||
const data: Buffer[] = [];
|
||||
|
||||
if (contractType == 'wasm') {
|
||||
const meteredWasmBinary = metering.meterWASM(src, {
|
||||
meterType: 'i32'
|
||||
});
|
||||
data.push(meteredWasmBinary);
|
||||
|
||||
const wasmModule = await WebAssembly.compile(src as Buffer);
|
||||
const moduleImports = WebAssembly.Module.imports(wasmModule);
|
||||
let lang;
|
||||
|
||||
if (this.isGoModule(moduleImports)) {
|
||||
const go = new Go(null);
|
||||
const module = new WebAssembly.Instance(wasmModule, go.importObject);
|
||||
// DO NOT await here!
|
||||
go.run(module);
|
||||
lang = go.exports.lang();
|
||||
wasmVersion = go.exports.version();
|
||||
} else {
|
||||
const module: WebAssembly.Instance = await WebAssembly.instantiate(src, dummyImports(moduleImports));
|
||||
// @ts-ignore
|
||||
if (!module.instance.exports.lang) {
|
||||
throw new Error(`No info about source type in wasm binary. Did you forget to export "lang" function?`);
|
||||
}
|
||||
// @ts-ignore
|
||||
lang = module.instance.exports.lang();
|
||||
// @ts-ignore
|
||||
wasmVersion = module.instance.exports.version();
|
||||
if (!wasmTypeMapping.has(lang)) {
|
||||
throw new Error(`Unknown wasm source type ${lang}`);
|
||||
}
|
||||
}
|
||||
|
||||
wasmLang = wasmTypeMapping.get(lang);
|
||||
if (wasmSrcCodeDir == null) {
|
||||
throw new Error('No path to original wasm contract source code');
|
||||
}
|
||||
|
||||
const zippedSourceCode = await this.zipContents(wasmSrcCodeDir);
|
||||
data.push(zippedSourceCode);
|
||||
|
||||
if (wasmLang == 'rust') {
|
||||
if (!wasmGlueCode) {
|
||||
throw new Error('No path to generated wasm-bindgen js code');
|
||||
}
|
||||
const wasmBindgenSrc = fs.readFileSync(wasmGlueCode, 'utf-8');
|
||||
const dtor = matchMutClosureDtor(wasmBindgenSrc);
|
||||
metadata['dtor'] = parseInt(dtor);
|
||||
data.push(Buffer.from(wasmBindgenSrc));
|
||||
}
|
||||
}
|
||||
|
||||
const allData = contractType == 'wasm' ? this.joinBuffers(data) : src;
|
||||
|
||||
srcTx = await this.arweave.createTransaction({ data: allData }, wallet);
|
||||
srcTx.addTag(SmartWeaveTags.APP_NAME, 'SmartWeaveContractSource');
|
||||
// TODO: version should be taken from the current package.json version.
|
||||
srcTx.addTag(SmartWeaveTags.APP_VERSION, '0.3.0');
|
||||
srcTx.addTag(SmartWeaveTags.SDK, 'RedStone');
|
||||
srcTx.addTag(SmartWeaveTags.CONTENT_TYPE, contractType == 'js' ? 'application/javascript' : 'application/wasm');
|
||||
|
||||
if (contractType == 'wasm') {
|
||||
srcTx.addTag(SmartWeaveTags.WASM_LANG, wasmLang);
|
||||
srcTx.addTag(SmartWeaveTags.WASM_LANG_VERSION, wasmVersion);
|
||||
srcTx.addTag(SmartWeaveTags.WASM_META, JSON.stringify(metadata));
|
||||
}
|
||||
|
||||
await this.arweave.transactions.sign(srcTx, wallet);
|
||||
this.logger.debug('Posting transaction with source');
|
||||
|
||||
// note: in case of useBundler = true, we're posting both
|
||||
// src tx and contract tx in one request.
|
||||
let responseOk = true;
|
||||
if (!useBundler) {
|
||||
const response = await this.arweave.transactions.post(srcTx);
|
||||
responseOk = response.status === 200 || response.status === 208;
|
||||
}
|
||||
|
||||
if (responseOk) {
|
||||
return await this.deployFromSourceTx(
|
||||
{
|
||||
srcTxId: srcTx.id,
|
||||
wallet,
|
||||
initState,
|
||||
tags,
|
||||
transfer
|
||||
},
|
||||
useBundler,
|
||||
srcTx
|
||||
);
|
||||
} else {
|
||||
throw new Error(`Unable to write Contract Source`);
|
||||
}
|
||||
return await this.deployFromSourceTx(
|
||||
{
|
||||
srcTxId: srcTx.id,
|
||||
wallet,
|
||||
initState,
|
||||
tags,
|
||||
transfer
|
||||
},
|
||||
useBundler,
|
||||
srcTx
|
||||
);
|
||||
}
|
||||
|
||||
async deployFromSourceTx(
|
||||
@@ -210,57 +112,4 @@ export class DefaultCreateContract implements CreateContract {
|
||||
throw new Error(`Error while posting contract ${response.statusText}`);
|
||||
}
|
||||
}
|
||||
|
||||
private isGoModule(moduleImports: WebAssembly.ModuleImportDescriptor[]) {
|
||||
return moduleImports.some((moduleImport) => {
|
||||
return moduleImport.module == 'env' && moduleImport.name.startsWith('syscall/js');
|
||||
});
|
||||
}
|
||||
|
||||
private joinBuffers(buffers: Buffer[]): Buffer {
|
||||
const length = buffers.length;
|
||||
const result = [];
|
||||
result.push(Buffer.from(length.toString()));
|
||||
result.push(Buffer.from('|'));
|
||||
buffers.forEach((b) => {
|
||||
result.push(Buffer.from(b.length.toString()));
|
||||
result.push(Buffer.from('|'));
|
||||
});
|
||||
result.push(...buffers);
|
||||
return result.reduce((prev, b) => Buffer.concat([prev, b]));
|
||||
}
|
||||
|
||||
private async zipContents(source: PathOrFileDescriptor): Promise<Buffer> {
|
||||
const archiver = require('archiver'),
|
||||
streamBuffers = require('stream-buffers');
|
||||
const outputStreamBuffer = new streamBuffers.WritableStreamBuffer({
|
||||
initialSize: 1000 * 1024, // start at 1000 kilobytes.
|
||||
incrementAmount: 1000 * 1024 // grow by 1000 kilobytes each time buffer overflows.
|
||||
});
|
||||
const archive = archiver('zip', {
|
||||
zlib: { level: 9 } // Sets the compression level.
|
||||
});
|
||||
archive.on('error', function (err) {
|
||||
throw err;
|
||||
});
|
||||
archive.pipe(outputStreamBuffer);
|
||||
archive.directory(source.toString(), source.toString());
|
||||
await archive.finalize();
|
||||
outputStreamBuffer.end();
|
||||
|
||||
return outputStreamBuffer.getContents();
|
||||
}
|
||||
}
|
||||
|
||||
function dummyImports(moduleImports: WebAssembly.ModuleImportDescriptor[]) {
|
||||
const imports = {};
|
||||
|
||||
moduleImports.forEach((moduleImport) => {
|
||||
if (!Object.prototype.hasOwnProperty.call(imports, moduleImport.module)) {
|
||||
imports[moduleImport.module] = {};
|
||||
}
|
||||
imports[moduleImport.module][moduleImport.name] = function () {};
|
||||
});
|
||||
|
||||
return imports;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user