From 0550773cf23bf8aa896ee1d8b846316a0000763a Mon Sep 17 00:00:00 2001 From: Tadeuchi Date: Wed, 10 Jan 2024 14:19:24 +0100 Subject: [PATCH] caching contracts loading from arweave #483 --- .../basic/contract-loading.test.ts | 9 +- src/__tests__/integration/basic/vrf.test.ts | 2 +- ...weave-sequenced-interaction-loader.test.ts | 36 +---- src/core/Warp.ts | 4 +- src/core/WarpBuilder.ts | 40 +++--- src/core/WarpFactory.ts | 2 +- src/core/modules/DefinitionLoader.ts | 2 + ....ts => ArweaveContractDefinitionLoader.ts} | 30 +--- .../impl/CacheableContractDefinitionLoader.ts | 129 ++++++++++++++++++ .../WarpGatewayContractDefinitionLoader.ts | 103 ++------------ src/index.ts | 2 +- tools/contract-testnet.js | 4 +- 12 files changed, 172 insertions(+), 191 deletions(-) rename src/core/modules/impl/{ContractDefinitionLoader.ts => ArweaveContractDefinitionLoader.ts} (85%) create mode 100644 src/core/modules/impl/CacheableContractDefinitionLoader.ts diff --git a/src/__tests__/integration/basic/contract-loading.test.ts b/src/__tests__/integration/basic/contract-loading.test.ts index b52d431a..da36707f 100644 --- a/src/__tests__/integration/basic/contract-loading.test.ts +++ b/src/__tests__/integration/basic/contract-loading.test.ts @@ -12,8 +12,8 @@ import { LoggerFactory } from '../../../logging/LoggerFactory'; import { WarpGatewayContractDefinitionLoader } from '../../../core/modules/impl/WarpGatewayContractDefinitionLoader'; import { DefaultEvaluationOptions } from '../../../core/modules/StateEvaluator'; import { LexicographicalInteractionsSorter } from '../../../core/modules/impl/LexicographicalInteractionsSorter'; -import { LevelDbCache } from '../../../cache/impl/LevelDbCache'; import { DeployPlugin } from 'warp-contracts-plugin-deploy'; +import { CacheableContractDefinitionLoader } from "../../../core/modules/impl/CacheableContractDefinitionLoader"; interface ExampleContractState { counter: number; @@ -22,7 +22,7 @@ interface ExampleContractState { describe('Testing WarpGatewayContractDefinitionLoader', () => { let contractSrc: string; let wallet: JWKInterface; - let loader: WarpGatewayContractDefinitionLoader; + let loader: CacheableContractDefinitionLoader; const evalOptions = new DefaultEvaluationOptions(); let sorter: LexicographicalInteractionsSorter; @@ -44,10 +44,7 @@ describe('Testing WarpGatewayContractDefinitionLoader', () => { const { arweave } = warp; - const contractCache = new LevelDbCache({ ...defaultCacheOptions, inMemory: true }); - const srcCache = new LevelDbCache({ ...defaultCacheOptions, inMemory: true }); - - loader = new WarpGatewayContractDefinitionLoader(arweave, contractCache, srcCache, 'local'); + loader = new CacheableContractDefinitionLoader(new WarpGatewayContractDefinitionLoader(arweave, 'local'), 'local', { ...defaultCacheOptions, inMemory: true }); loader.warp = warp; sorter = new LexicographicalInteractionsSorter(arweave); diff --git a/src/__tests__/integration/basic/vrf.test.ts b/src/__tests__/integration/basic/vrf.test.ts index 83218d1c..88ba6710 100644 --- a/src/__tests__/integration/basic/vrf.test.ts +++ b/src/__tests__/integration/basic/vrf.test.ts @@ -63,7 +63,7 @@ describe('Testing the Profit Sharing Token', () => { }, 'local' ) - .useArweaveGateway() + .useArweaveGateway(defaultCacheOptions) .setInteractionsLoader(loader) .build() .use(new DeployPlugin()) diff --git a/src/__tests__/regression/arweave-sequenced-interaction-loader.test.ts b/src/__tests__/regression/arweave-sequenced-interaction-loader.test.ts index 23f25316..80167e1d 100644 --- a/src/__tests__/regression/arweave-sequenced-interaction-loader.test.ts +++ b/src/__tests__/regression/arweave-sequenced-interaction-loader.test.ts @@ -2,13 +2,12 @@ import { ArweaveGatewayBundledContractDefinitionLoader } from '../../core/module import { ArweaveGatewayBundledInteractionLoader } from '../../core/modules/impl/ArweaveGatewayBundledInteractionLoader'; import { SourceType, WarpGatewayInteractionsLoader } from '../../core/modules/impl/WarpGatewayInteractionsLoader'; import { EvaluationOptions } from '../../core/modules/StateEvaluator'; -import { WarpFactory } from '../../core/WarpFactory'; +import { defaultCacheOptions, WarpFactory } from "../../core/WarpFactory"; import { LoggerFactory } from '../../logging/LoggerFactory'; import { WarpGatewayContractDefinitionLoader } from '../../core/modules/impl/WarpGatewayContractDefinitionLoader'; -import { LevelDbCache } from '../../cache/impl/LevelDbCache'; -import { ContractCache, SrcCache } from '../../core/ContractDefinition'; import stringify from 'safe-stable-stringify'; import Arweave from 'arweave/node/common'; +import { CacheableContractDefinitionLoader } from "../../core/modules/impl/CacheableContractDefinitionLoader"; const EXAMPLE_CONTRACT_TX_ID = 'T8Fakv0Sol6ALQ4Mt6FTxEJVDJWT-HDUmcI3qIA49U4'; const EXAMPLE_CONTRACT_SRC_TX_ID = 'QEIweYIpdMSer_E33VreYzmuTIx33FQ4Sq32XJqlLQw'; @@ -33,23 +32,7 @@ describe('Arweave Gateway interaction loader', () => { it('should load contract definition', async () => { const warp = WarpFactory.forMainnet(); - const contractsCache = new LevelDbCache>({ - inMemory: true, - dbLocation: '' - }); - - // Separate cache for sources to minimize duplicates - const sourceCache = new LevelDbCache({ - inMemory: true, - dbLocation: '' - }); - - const wrLoader = new WarpGatewayContractDefinitionLoader( - warp.arweave, - contractsCache, - sourceCache, - warp.environment - ); + const wrLoader = new CacheableContractDefinitionLoader(new WarpGatewayContractDefinitionLoader(warp.arweave, 'local'), 'local', { ...defaultCacheOptions, inMemory: true }) wrLoader.warp = warp; const arLoader = new ArweaveGatewayBundledContractDefinitionLoader(warp.environment); @@ -100,21 +83,10 @@ describe('Arweave Gateway interaction loader', () => { }); it('warp interaction loader and arweave interaction loader evaluates to same state', async () => { - const contractsCache = new LevelDbCache>({ - inMemory: true, - dbLocation: '' - }); - - // Separate cache for sources to minimize duplicates - const sourceCache = new LevelDbCache({ - inMemory: true, - dbLocation: '' - }); - const arweave = Arweave.init({ host: 'arweave.net', port: 443, protocol: 'https' }); const arLoader = new ArweaveGatewayBundledInteractionLoader(arweave, 'mainnet'); - const wrLoader = new WarpGatewayContractDefinitionLoader(arweave, contractsCache, sourceCache, 'mainnet'); + const wrLoader = new CacheableContractDefinitionLoader(new WarpGatewayContractDefinitionLoader(arweave, 'local'), 'local', { ...defaultCacheOptions, inMemory: true }); const withArLoader = WarpFactory.custom(arweave, { inMemory: true, dbLocation: '' }, 'mainnet') .setInteractionsLoader(arLoader) .setDefinitionLoader(wrLoader) diff --git a/src/core/Warp.ts b/src/core/Warp.ts index 441568bd..93bb8f46 100644 --- a/src/core/Warp.ts +++ b/src/core/Warp.ts @@ -12,7 +12,7 @@ import { HandlerBasedContract } from '../contract/HandlerBasedContract'; import { PstContract } from '../contract/PstContract'; import { PstContractImpl } from '../contract/PstContractImpl'; import { Testing, Wallet } from '../contract/testing/Testing'; -import { DefinitionLoader } from './modules/DefinitionLoader'; +import { CacheableDefinitionLoader } from './modules/DefinitionLoader'; import { ExecutorFactory } from './modules/ExecutorFactory'; import { HandlerApi } from './modules/impl/HandlerExecutorFactory'; import { InteractionsLoader } from './modules/InteractionsLoader'; @@ -72,7 +72,7 @@ export class Warp { constructor( readonly arweave: Arweave, - readonly definitionLoader: DefinitionLoader, + readonly definitionLoader: CacheableDefinitionLoader, readonly interactionsLoader: InteractionsLoader, readonly executorFactory: ExecutorFactory>, readonly stateEvaluator: StateEvaluator, diff --git a/src/core/WarpBuilder.ts b/src/core/WarpBuilder.ts index 821412c2..a7973d39 100644 --- a/src/core/WarpBuilder.ts +++ b/src/core/WarpBuilder.ts @@ -1,10 +1,10 @@ import Arweave from 'arweave'; import { DebuggableExecutorFactory } from '../plugins/DebuggableExecutorFactor'; -import { DefinitionLoader } from './modules/DefinitionLoader'; +import { CacheableDefinitionLoader } from './modules/DefinitionLoader'; import { ExecutorFactory } from './modules/ExecutorFactory'; import { ArweaveGatewayInteractionsLoader } from './modules/impl/ArweaveGatewayInteractionsLoader'; import { CacheableInteractionsLoader } from './modules/impl/CacheableInteractionsLoader'; -import { ContractDefinitionLoader } from './modules/impl/ContractDefinitionLoader'; +import { ArweaveContractDefinitionLoader } from './modules/impl/ArweaveContractDefinitionLoader'; import { HandlerApi } from './modules/impl/HandlerExecutorFactory'; import { WarpGatewayContractDefinitionLoader } from './modules/impl/WarpGatewayContractDefinitionLoader'; import { WarpGatewayInteractionsLoader } from './modules/impl/WarpGatewayInteractionsLoader'; @@ -12,12 +12,11 @@ import { InteractionsLoader } from './modules/InteractionsLoader'; import { StateEvaluator, EvalStateResult } from './modules/StateEvaluator'; import { WarpEnvironment, Warp } from './Warp'; import { CacheOptions, GatewayOptions } from './WarpFactory'; -import { LevelDbCache } from '../cache/impl/LevelDbCache'; -import { ContractCache, SrcCache } from './ContractDefinition'; import { BasicSortKeyCache } from '../cache/BasicSortKeyCache'; +import { CacheableContractDefinitionLoader } from './modules/impl/CacheableContractDefinitionLoader'; export class WarpBuilder { - private _definitionLoader?: DefinitionLoader; + private _definitionLoader?: CacheableDefinitionLoader; private _interactionsLoader?: InteractionsLoader; private _executorFactory?: ExecutorFactory>; private _stateEvaluator?: StateEvaluator; @@ -28,7 +27,7 @@ export class WarpBuilder { private readonly _environment: WarpEnvironment = 'custom' ) {} - public setDefinitionLoader(value: DefinitionLoader): WarpBuilder { + public setDefinitionLoader(value: CacheableDefinitionLoader): WarpBuilder { this._definitionLoader = value; return this; } @@ -61,31 +60,24 @@ export class WarpBuilder { new WarpGatewayInteractionsLoader(gatewayOptions.confirmationStatus, gatewayOptions.source) ); - const contractsCache = new LevelDbCache>({ - ...cacheOptions, - dbLocation: `${cacheOptions.dbLocation}/contracts` - }); - - // Separate cache for sources to minimize duplicates - const sourceCache = new LevelDbCache({ - ...cacheOptions, - dbLocation: `${cacheOptions.dbLocation}/source` - }); - - this._definitionLoader = new WarpGatewayContractDefinitionLoader( - this._arweave, - contractsCache, - sourceCache, - this._environment + this._definitionLoader = new CacheableContractDefinitionLoader( + new WarpGatewayContractDefinitionLoader(this._arweave, this._environment), + this._environment, + cacheOptions ); return this; } - public useArweaveGateway(): WarpBuilder { - this._definitionLoader = new ContractDefinitionLoader(this._arweave, this._environment); + public useArweaveGateway(cacheOptions: CacheOptions): WarpBuilder { this._interactionsLoader = new CacheableInteractionsLoader( new ArweaveGatewayInteractionsLoader(this._arweave, this._environment) ); + + this._definitionLoader = new CacheableContractDefinitionLoader( + new ArweaveContractDefinitionLoader(this._arweave, this._environment), + this._environment, + cacheOptions + ); return this; } diff --git a/src/core/WarpFactory.ts b/src/core/WarpFactory.ts index 3dd63434..320138bf 100644 --- a/src/core/WarpFactory.ts +++ b/src/core/WarpFactory.ts @@ -134,7 +134,7 @@ export class WarpFactory { cacheOptions: CacheOptions = defaultCacheOptions, environment: WarpEnvironment ): Warp { - return this.custom(arweave, cacheOptions, environment).useArweaveGateway().build(); + return this.custom(arweave, cacheOptions, environment).useArweaveGateway(cacheOptions).build(); } private static customWarpGw( diff --git a/src/core/modules/DefinitionLoader.ts b/src/core/modules/DefinitionLoader.ts index 86b2bcce..59ed4904 100644 --- a/src/core/modules/DefinitionLoader.ts +++ b/src/core/modules/DefinitionLoader.ts @@ -12,7 +12,9 @@ export interface DefinitionLoader extends GwTypeAware, WarpAware { load(contractTxId: string, evolvedSrcTxId?: string): Promise>; loadContractSource(srcTxId: string): Promise; +} +export interface CacheableDefinitionLoader extends DefinitionLoader { setCache(cache: BasicSortKeyCache>): void; // Cache for storing common source code or binaries diff --git a/src/core/modules/impl/ContractDefinitionLoader.ts b/src/core/modules/impl/ArweaveContractDefinitionLoader.ts similarity index 85% rename from src/core/modules/impl/ContractDefinitionLoader.ts rename to src/core/modules/impl/ArweaveContractDefinitionLoader.ts index ea78e8dc..7aecdb7c 100644 --- a/src/core/modules/impl/ContractDefinitionLoader.ts +++ b/src/core/modules/impl/ArweaveContractDefinitionLoader.ts @@ -1,12 +1,6 @@ import Arweave from 'arweave'; import { ContractType } from '../../../contract/deploy/CreateContract'; -import { - ContractDefinition, - ContractSource, - ContractCache, - SrcCache, - SUPPORTED_SRC_CONTENT_TYPES -} from '../../../core/ContractDefinition'; +import { ContractDefinition, ContractSource, SUPPORTED_SRC_CONTENT_TYPES } from '../../../core/ContractDefinition'; import { SMART_WEAVE_TAGS, WARP_TAGS } from '../../KnownTags'; import { Benchmark } from '../../../logging/Benchmark'; import { LoggerFactory } from '../../../logging/LoggerFactory'; @@ -17,11 +11,9 @@ import { TagsParser } from './TagsParser'; import { WasmSrc } from './wasm/WasmSrc'; import { Warp, WarpEnvironment } from '../../Warp'; import { Transaction } from '../../../utils/types/arweave-types'; -import { BasicSortKeyCache } from '../../../cache/BasicSortKeyCache'; -export class ContractDefinitionLoader implements DefinitionLoader { +export class ArweaveContractDefinitionLoader implements DefinitionLoader { private readonly logger = LoggerFactory.INST.create('ContractDefinitionLoader'); - protected arweaveWrapper: ArweaveWrapper; private readonly tagsParser: TagsParser; @@ -146,24 +138,6 @@ export class ContractDefinitionLoader implements DefinitionLoader { return 'arweave'; } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - setCache(cache: BasicSortKeyCache>): void { - throw new Error('No cache implemented for this loader'); - } - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - setSrcCache(cache: BasicSortKeyCache): void { - throw new Error('No cache implemented for this loader'); - } - - getCache(): BasicSortKeyCache> { - throw new Error('No cache implemented for this loader'); - } - - getSrcCache(): BasicSortKeyCache { - throw new Error('No cache implemented for this loader'); - } - set warp(warp: Warp) { this.arweaveWrapper = new ArweaveWrapper(warp); } diff --git a/src/core/modules/impl/CacheableContractDefinitionLoader.ts b/src/core/modules/impl/CacheableContractDefinitionLoader.ts new file mode 100644 index 00000000..4c42133d --- /dev/null +++ b/src/core/modules/impl/CacheableContractDefinitionLoader.ts @@ -0,0 +1,129 @@ +import { Buffer } from 'warp-isomorphic'; +import { GW_TYPE } from '../InteractionsLoader'; +import { ContractCache, ContractDefinition, ContractSource, SrcCache } from '../../ContractDefinition'; +import { Benchmark } from '../../../logging/Benchmark'; +import { LoggerFactory } from '../../../logging/LoggerFactory'; +import { CacheableDefinitionLoader, DefinitionLoader } from '../DefinitionLoader'; +import { Warp, WarpEnvironment } from '../../Warp'; +import { CacheKey, SortKeyCacheResult } from '../../../cache/SortKeyCache'; +import { BasicSortKeyCache } from '../../../cache/BasicSortKeyCache'; +import { LevelDbCache } from '../../../cache/impl/LevelDbCache'; +import { CacheOptions } from '../../WarpFactory'; + +/** + * An implementation of {@link CacheableDefinitionLoader} that delegates loading contracts and caches the result. + */ +export class CacheableContractDefinitionLoader implements CacheableDefinitionLoader { + private readonly rLogger = LoggerFactory.INST.create('CacheableContractDefinitionLoader'); + private definitionCache: BasicSortKeyCache>; + private srcCache: BasicSortKeyCache; + + constructor( + private readonly contractDefinitionLoader: DefinitionLoader, + private readonly env: WarpEnvironment, + cacheOptions: CacheOptions + ) { + this.definitionCache = new LevelDbCache>({ + ...cacheOptions, + dbLocation: `${cacheOptions.dbLocation}/contracts` + }); + + // Separate cache for sources to minimize duplicates + this.srcCache = new LevelDbCache({ + ...cacheOptions, + dbLocation: `${cacheOptions.dbLocation}/source` + }); + } + + async load(contractTxId: string, evolvedSrcTxId?: string): Promise> { + const result = await this.getFromCache(contractTxId, evolvedSrcTxId); + if (result) { + this.rLogger.debug('Hit from cache!', contractTxId, evolvedSrcTxId); + // LevelDB serializes Buffer to an object with 'type' and 'data' fields + // eslint-disable-next-line @typescript-eslint/no-explicit-any + if (result.contractType == 'wasm' && (result.srcBinary as any).data) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + result.srcBinary = Buffer.from((result.srcBinary as any).data); + } + this.verifyEnv(result); + return result; + } + const benchmark = Benchmark.measure(); + const contract = await this.contractDefinitionLoader.load(contractTxId, evolvedSrcTxId); + + this.rLogger.info(`Contract definition loaded in: ${benchmark.elapsed()}`); + this.verifyEnv(contract); + + await this.putToCache(contractTxId, contract, evolvedSrcTxId); + + return contract; + } + + async loadContractSource(contractSrcTxId: string): Promise { + return await this.contractDefinitionLoader.loadContractSource(contractSrcTxId); + } + + type(): GW_TYPE { + return this.contractDefinitionLoader.type(); + } + + setCache(cache: BasicSortKeyCache>): void { + this.definitionCache = cache; + } + + setSrcCache(cacheSrc: BasicSortKeyCache): void { + this.srcCache = cacheSrc; + } + + getCache(): BasicSortKeyCache> { + return this.definitionCache; + } + + getSrcCache(): BasicSortKeyCache { + return this.srcCache; + } + + private verifyEnv(def: ContractDefinition): void { + if (def.testnet && this.env !== 'testnet') { + throw new Error('Trying to use testnet contract in a non-testnet env. Use the "forTestnet" factory method.'); + } + if (!def.testnet && this.env === 'testnet') { + throw new Error('Trying to use non-testnet contract in a testnet env.'); + } + } + + // Gets ContractDefinition and ContractSource from two caches and returns a combined structure + private async getFromCache(contractTxId: string, srcTxId?: string): Promise | null> { + const contract = (await this.definitionCache.get(new CacheKey(contractTxId, 'cd'))) as SortKeyCacheResult< + ContractCache + >; + + if (!contract) { + return null; + } + const effectiveSrcTxId = srcTxId || contract.cachedValue.srcTxId; + + const src = await this.srcCache.get(new CacheKey(effectiveSrcTxId, 'src')); + if (!src) { + return null; + } + return { ...contract.cachedValue, ...src.cachedValue, srcTxId: effectiveSrcTxId }; + } + + // Divides ContractDefinition into entries in two caches to avoid duplicates + private async putToCache( + contractTxId: string, + value: ContractDefinition, + srcTxId?: string + ): Promise { + const src = new SrcCache(value); + const contract = new ContractCache(value); + + await this.definitionCache.put({ key: contractTxId, sortKey: 'cd' }, contract); + await this.srcCache.put({ key: srcTxId || contract.srcTxId, sortKey: 'src' }, src); + } + + set warp(warp: Warp) { + this.contractDefinitionLoader.warp = warp; + } +} diff --git a/src/core/modules/impl/WarpGatewayContractDefinitionLoader.ts b/src/core/modules/impl/WarpGatewayContractDefinitionLoader.ts index 40c5dc13..62c1b4af 100644 --- a/src/core/modules/impl/WarpGatewayContractDefinitionLoader.ts +++ b/src/core/modules/impl/WarpGatewayContractDefinitionLoader.ts @@ -1,74 +1,42 @@ import Arweave from 'arweave'; -import { ContractDefinitionLoader } from './ContractDefinitionLoader'; +import { ArweaveContractDefinitionLoader } from './ArweaveContractDefinitionLoader'; import { Buffer } from 'warp-isomorphic'; import { GW_TYPE } from '../InteractionsLoader'; -import { ContractCache, ContractDefinition, ContractSource, SrcCache } from '../../../core/ContractDefinition'; +import { ContractDefinition, ContractSource } from '../../../core/ContractDefinition'; import { WARP_TAGS } from '../../KnownTags'; -import { Benchmark } from '../../../logging/Benchmark'; import { LoggerFactory } from '../../../logging/LoggerFactory'; import { ArweaveWrapper } from '../../../utils/ArweaveWrapper'; import { DefinitionLoader } from '../DefinitionLoader'; import { WasmSrc } from './wasm/WasmSrc'; import { Warp, WarpEnvironment } from '../../Warp'; import { TagsParser } from './TagsParser'; -import { CacheKey, SortKeyCacheResult } from '../../../cache/SortKeyCache'; import { Transaction } from '../../../utils/types/arweave-types'; import { getJsonResponse, stripTrailingSlash } from '../../../utils/utils'; -import { BasicSortKeyCache } from '../../../cache/BasicSortKeyCache'; /** - * An extension to {@link ContractDefinitionLoader} that makes use of - * Warp Gateway ({@link https://github.com/redstone-finance/redstone-sw-gateway}) + * Makes use of Warp Gateway ({@link https://github.com/redstone-finance/redstone-sw-gateway}) * to load Contract Data. * * If the contract data is not available on Warp Gateway - it fallbacks to default implementation - * in {@link ContractDefinitionLoader} - i.e. loads the definition from Arweave gateway. + * in {@link ArweaveContractDefinitionLoader} - i.e. loads the definition from Arweave gateway. */ export class WarpGatewayContractDefinitionLoader implements DefinitionLoader { private readonly rLogger = LoggerFactory.INST.create('WarpGatewayContractDefinitionLoader'); - private contractDefinitionLoader: ContractDefinitionLoader; + private contractDefinitionLoader: ArweaveContractDefinitionLoader; private arweaveWrapper: ArweaveWrapper; private readonly tagsParser: TagsParser; private _warp: Warp; - constructor( - arweave: Arweave, - private definitionCache: BasicSortKeyCache>, - private srcCache: BasicSortKeyCache, - private readonly env: WarpEnvironment - ) { - this.contractDefinitionLoader = new ContractDefinitionLoader(arweave, env); + constructor(arweave: Arweave, env: WarpEnvironment) { + this.contractDefinitionLoader = new ArweaveContractDefinitionLoader(arweave, env); this.tagsParser = new TagsParser(); } async load(contractTxId: string, evolvedSrcTxId?: string): Promise> { - const result = await this.getFromCache(contractTxId, evolvedSrcTxId); - if (result) { - this.rLogger.debug('WarpGatewayContractDefinitionLoader: Hit from cache!'); - // LevelDB serializes Buffer to an object with 'type' and 'data' fields - // eslint-disable-next-line @typescript-eslint/no-explicit-any - if (result.contractType == 'wasm' && (result.srcBinary as any).data) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - result.srcBinary = Buffer.from((result.srcBinary as any).data); - } - this.verifyEnv(result); - return result; - } - const benchmark = Benchmark.measure(); - const contract = await this.doLoad(contractTxId, evolvedSrcTxId); - this.rLogger.info(`Contract definition loaded in: ${benchmark.elapsed()}`); - this.verifyEnv(contract); - - await this.putToCache(contractTxId, contract, evolvedSrcTxId); - - return contract; - } - - async doLoad(contractTxId: string, forcedSrcTxId?: string): Promise> { try { const baseUrl = stripTrailingSlash(this._warp.gwUrl()); const result: ContractDefinition = await getJsonResponse( - fetch(`${baseUrl}/gateway/contract?txId=${contractTxId}${forcedSrcTxId ? `&srcTxId=${forcedSrcTxId}` : ''}`) + fetch(`${baseUrl}/gateway/contract?txId=${contractTxId}${evolvedSrcTxId ? `&srcTxId=${evolvedSrcTxId}` : ''}`) ); if (result.srcBinary != null && !(result.srcBinary instanceof Buffer)) { @@ -91,7 +59,7 @@ export class WarpGatewayContractDefinitionLoader implements DefinitionLoader { return result; } catch (e) { this.rLogger.warn('Falling back to default contracts loader', e); - return await this.contractDefinitionLoader.doLoad(contractTxId, forcedSrcTxId); + return await this.contractDefinitionLoader.doLoad(contractTxId, evolvedSrcTxId); } } @@ -103,59 +71,6 @@ export class WarpGatewayContractDefinitionLoader implements DefinitionLoader { return 'warp'; } - setCache(cache: BasicSortKeyCache>): void { - this.definitionCache = cache; - } - - setSrcCache(cacheSrc: BasicSortKeyCache): void { - this.srcCache = cacheSrc; - } - - getCache(): BasicSortKeyCache> { - return this.definitionCache; - } - - getSrcCache(): BasicSortKeyCache { - return this.srcCache; - } - - private verifyEnv(def: ContractDefinition): void { - if (def.testnet && this.env !== 'testnet') { - throw new Error('Trying to use testnet contract in a non-testnet env. Use the "forTestnet" factory method.'); - } - if (!def.testnet && this.env === 'testnet') { - throw new Error('Trying to use non-testnet contract in a testnet env.'); - } - } - - // Gets ContractDefinition and ContractSource from two caches and returns a combined structure - private async getFromCache(contractTxId: string, srcTxId?: string): Promise | null> { - const contract = (await this.definitionCache.get(new CacheKey(contractTxId, 'cd'))) as SortKeyCacheResult< - ContractCache - >; - if (!contract) { - return null; - } - - const src = await this.srcCache.get(new CacheKey(srcTxId || contract.cachedValue.srcTxId, 'src')); - if (!src) { - return null; - } - return { ...contract.cachedValue, ...src.cachedValue }; - } - - // Divides ContractDefinition into entries in two caches to avoid duplicates - private async putToCache( - contractTxId: string, - value: ContractDefinition, - srcTxId?: string - ): Promise { - const src = new SrcCache(value); - const contract = new ContractCache(value); - await this.definitionCache.put({ key: contractTxId, sortKey: 'cd' }, contract); - await this.srcCache.put({ key: srcTxId || contract.srcTxId, sortKey: 'src' }, src); - } - set warp(warp: Warp) { this._warp = warp; this.arweaveWrapper = new ArweaveWrapper(warp); diff --git a/src/index.ts b/src/index.ts index d1fe5b21..522a81cd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,7 +17,7 @@ export * from './core/modules/InteractionsLoader'; export * from './core/modules/InteractionsSorter'; export * from './core/modules/StateEvaluator'; -export * from './core/modules/impl/ContractDefinitionLoader'; +export * from './core/modules/impl/ArweaveContractDefinitionLoader'; export * from './core/modules/impl/WarpGatewayContractDefinitionLoader'; export * from './core/modules/impl/ArweaveGatewayInteractionsLoader'; export * from './core/modules/impl/WarpGatewayInteractionsLoader'; diff --git a/tools/contract-testnet.js b/tools/contract-testnet.js index be825f73..7062b1bf 100644 --- a/tools/contract-testnet.js +++ b/tools/contract-testnet.js @@ -7,7 +7,7 @@ const fs = require('fs'); const path =require('path'); const {readContract} = require("smartweave"); const {WarpNodeFactory} = require("../lib/cjs/core/node/WarpNodeFactory"); -const {ContractDefinitionLoader} = require("../src"); +const {ArweaveContractDefinitionLoader} = require("../src"); const logger = LoggerFactory.INST.create('Contract'); @@ -21,7 +21,7 @@ async function main() { protocol: 'https', port: 443, }); - const loader = new ContractDefinitionLoader(arweave); + const loader = new ArweaveContractDefinitionLoader(arweave); const definition = await loader.load("contract_tx_id"); console.log(definition.srcTxId);