From 354bc2e7dbaa93b71f80fafb702abf8b679fb658 Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Thu, 26 Aug 2021 15:37:00 +0200 Subject: [PATCH] fix: fix for a strange issue with state changing for contract YLVpmhSq5JmLltfg6R-5fL04rIRPrlSU22f6RQ6VyYE --- .eslintrc | 3 + .gitignore | 4 + _scripts/after.json | 78 ++++++++++++++++ _scripts/benchmark.ts | 60 ------------ _scripts/cache-issue.ts | 30 ++---- _scripts/output/new/____init.json | 92 +++++++++++++++++++ _scripts/single-state-comparator.ts | 54 +++++++++++ _scripts/state-comparator.ts | 26 +++--- ...{swc-sorted-stats.json => test-cases.json} | 0 src/contract/HandlerBasedContract.ts | 20 ++-- src/contract/SmartWeave.ts | 13 ++- src/core/impl/ContractDefinitionLoader.ts | 11 ++- src/core/impl/DefaultStateEvaluator.ts | 23 ++++- src/core/impl/HandlerExecutorFactory.ts | 7 +- src/logging/Benchmark.ts | 4 + src/logging/node/TsLogFactory.ts | 3 +- src/plugins/Evolve.ts | 2 +- 17 files changed, 316 insertions(+), 114 deletions(-) create mode 100644 _scripts/after.json delete mode 100644 _scripts/benchmark.ts create mode 100644 _scripts/output/new/____init.json create mode 100644 _scripts/single-state-comparator.ts rename _scripts/{swc-sorted-stats.json => test-cases.json} (100%) diff --git a/.eslintrc b/.eslintrc index 7ce1218..ae6aa38 100644 --- a/.eslintrc +++ b/.eslintrc @@ -13,6 +13,9 @@ ], "rules": { "no-console": 1, // warning + "multiline-ternary": "off", + "no-nested-ternary": "error", + "no-multiple-empty-lines": "off", "prettier/prettier": 2 // error } } diff --git a/.gitignore b/.gitignore index cddc575..ea78785 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,7 @@ lib/ .idea/ .DS_Store + +yarn-error.log +cache/ +_scripts/**/*.json diff --git a/_scripts/after.json b/_scripts/after.json new file mode 100644 index 0000000..46f0c61 --- /dev/null +++ b/_scripts/after.json @@ -0,0 +1,78 @@ +{ + "accounts": { + "regulator": { + "balance": 999.999, + "vaults": [] + }, + "Pq6OBljxlpypNuE0O1eL92Kr9U1Ok4USfcc0aJcUAzs": { + "balance": 69.0005, + "vaults": [ + { + "amount": 0.005, + "start": 649390, + "end": 650390 + } + ], + "stake": 69 + }, + "DfCXDjdxcTIg1-FQDZ5jDclk1shKIpMlshe0IXodApc": { + "balance": 69.0005, + "vaults": [], + "stake": 69 + } + }, + "executables": { + "Ms6RRl0eh96F_lcKYyiJhWRdRIiB6z0VaThCvBZDOAc": { + "_discriminator": "validated", + "bids": [ + { + "bidder": "Pq6OBljxlpypNuE0O1eL92Kr9U1Ok4USfcc0aJcUAzs", + "quantity": 0.01 + } + ], + "caller": "Pq6OBljxlpypNuE0O1eL92Kr9U1Ok4USfcc0aJcUAzs", + "executable": { + "birth_height": 649382, + "executable_address": "is9cDN3ZKPun0F2KmEHnhiRuUcYOO3Dzfef-B5ZAQeQ", + "executable_kind": "wasm" + }, + "accepted_bid": { + "bidder": "Pq6OBljxlpypNuE0O1eL92Kr9U1Ok4USfcc0aJcUAzs", + "quantity": 0.01 + }, + "validation_linked_list": { + "value": [ + { + "_discriminator": "release", + "validator": "Pq6OBljxlpypNuE0O1eL92Kr9U1Ok4USfcc0aJcUAzs", + "encrypted_hash": "af8e9c76fc012934cd3009c0cb7cac697da634350aa7dd6a063ccc3fdbc533f815799ed08d72d06a84961e468cd2af3fec5549350ce582c74eea7c29e020acf052c3e619cc69aa98e6e5b43bd10574dce88bb204289891c97a535d1da69f32e0e42dd906159b47acb3d435679b9c61dc", + "symm_key": "sokka" + }, + { + "_discriminator": "release", + "validator": "DfCXDjdxcTIg1-FQDZ5jDclk1shKIpMlshe0IXodApc", + "encrypted_hash": "af8e9c76fc012934cd3009c0cb7cac697da634350aa7dd6a063ccc3fdbc533f815799ed08d72d06a84961e468cd2af3fec5549350ce582c74eea7c29e020acf052c3e619cc69aa98e6e5b43bd10574dce88bb204289891c97a535d1da69f32e0e42dd906159b47acb3d435679b9c61dc", + "symm_key": "sokka" + } + ] + }, + "result": { + "address": "OTWNmd9aSARYg1X4ds8CwSVmx_dNYHb_ka-W2VAJ7NQ", + "giver": "Pq6OBljxlpypNuE0O1eL92Kr9U1Ok4USfcc0aJcUAzs", + "height": 649390 + }, + "is_correct": true + }, + "Xstw2Ss9TMCkV92ozHTsvIDPsPXnMDZVzfKPTPxgAq0": { + "_discriminator": "proposed", + "bids": [], + "caller": "Pq6OBljxlpypNuE0O1eL92Kr9U1Ok4USfcc0aJcUAzs", + "executable": { + "birth_height": 649387, + "executable_address": "is9cDN3ZKPun0F2KmEHnhiRuUcYOO3Dzfef-B5ZAQeQ", + "executable_kind": "wasm" + } + } + }, + "ticker": "FEA" +} diff --git a/_scripts/benchmark.ts b/_scripts/benchmark.ts deleted file mode 100644 index c5bb386..0000000 --- a/_scripts/benchmark.ts +++ /dev/null @@ -1,60 +0,0 @@ -/* eslint-disable */ -import { LoggerFactory, SmartWeaveNodeFactory } from '@smartweave'; -import Arweave from 'arweave'; -import fs from 'fs'; -import path from 'path'; - -async function main() { - const arweave = Arweave.init({ - host: 'dh48zl0solow5.cloudfront.net', // Hostname or IP address for a Arweave host - port: 443, // Port - protocol: 'https', // Network protocol http or https - timeout: 60000, // Network request timeouts in milliseconds - logging: false // Enable network request logging - }); - const logger = LoggerFactory.INST.create(__filename); - LoggerFactory.INST.logLevel('silly', 'benchmark'); - const swcClient = SmartWeaveNodeFactory.fileCacheClient(arweave); - - const contractTxId = 'OrO8n453N6bx921wtsEs-0OCImBLCItNU5oSbFKlFuU'; - // Kyve: - // C_1uo08qRuQAeDi9Y1I8fkaWYUC9IWkOrKDNe9EphJo - // OFD4GqQcqp-Y_Iqh8DN_0s3a_68oMvvnekeOEu_a45I - // 8cq1wbjWHNiPg7GwYpoDT2m9HX99LY7tklRQWfh1L6c - - const resultDiffs = []; - - try { - /* console.log('readContract'); - const result = await readContract(arweave, contractTxId); - const resultString = JSON.stringify(result); - console.log(resultString); -*/ - const result2 = await swcClient.readState(contractTxId); - const result2String = JSON.stringify(result2.state); - logger.silly(result2String); - - /* if (resultString.localeCompare(result2String) !== 0) { - console.error('\n\n ====== States differ ======\n\n'); - resultDiffs.push(contractTxId); - const targetPath = path.join(__dirname, 'tests', contractTxId); - if (!fs.existsSync(targetPath)) { - fs.mkdirSync(targetPath); - } - fs.writeFileSync(path.join(targetPath, 'new.json'), result2String); - fs.writeFileSync(path.join(targetPath, 'old.json'), resultString); - }*/ - - const targetPath = path.join(__dirname, '../', 'tests', contractTxId); - if (!fs.existsSync(targetPath)) { - fs.mkdirSync(targetPath); - } - fs.writeFileSync(path.join(targetPath, 'new.json'), result2String); - logger.silly('Contracts with diff state:', resultDiffs); - } catch (e) { - logger.error(e); - logger.log('skipping ', contractTxId); - } -} - -main(); diff --git a/_scripts/cache-issue.ts b/_scripts/cache-issue.ts index b32750e..25d1d8c 100644 --- a/_scripts/cache-issue.ts +++ b/_scripts/cache-issue.ts @@ -2,6 +2,7 @@ import Arweave from 'arweave'; import { SmartWeaveNodeFactory, LoggerFactory } from '@smartweave'; import fs from 'fs'; +import { readContract } from 'smartweave'; const contracts = [ 'gepLlre8wG8K3C15rNjpdKZZv_9pWsurRoEB6ir_EC4', @@ -24,30 +25,13 @@ async function main() { logging: false // Enable network request logging }); - LoggerFactory.INST.logLevel('debug'); - const smartWeave = SmartWeaveNodeFactory.memCached(arweave); - const contract1 = smartWeave.contract('W_njBtwDRyltjVU1RizJtZfF0S_4X3aSrrrA0HUEhUs'); - const contract2 = smartWeave.contract('TMkCZKYO3GwcTLEKGgWSJegIlYCHi_UArtG0unCi2xA'); - await contract1.readState(); - await contract2.readState(); - - const jwk = readJSON('../../redstone-node/.secrets/redstone-dev-jwk.json'); - contract1.connect(jwk); - - type Contract1Input = { - function: string; - }; - type Contract1View = { - foo: string; - bar: number; - }; - const { type, result } = await contract1.viewState({ - function: 'currentManifest' - }); - if (type === 'ok') { - console.log((result as Contract1View).foo); - } + const contract1 = smartWeave.contract('YLVpmhSq5JmLltfg6R-5fL04rIRPrlSU22f6RQ6VyYE'); + //const contract2 = smartWeave.contract('TMkCZKYO3GwcTLEKGgWSJegIlYCHi_UArtG0unCi2xA'); + const { state } = await contract1.readState(); + //await contract2.readState(); + const state2 = await readContract(arweave, 'YLVpmhSq5JmLltfg6R-5fL04rIRPrlSU22f6RQ6VyYE'); + console.log; } function readJSON(path) { diff --git a/_scripts/output/new/____init.json b/_scripts/output/new/____init.json new file mode 100644 index 0000000..b42aa3f --- /dev/null +++ b/_scripts/output/new/____init.json @@ -0,0 +1,92 @@ +{ + "accounts": { + "regulator": { + "balance": 1000, + "vaults": [ + { + "amount": 0.0005, + "end": 650390, + "start": 649390 + }, + { + "amount": 0.0005, + "end": 650390, + "start": 649390 + } + ] + }, + "Pq6OBljxlpypNuE0O1eL92Kr9U1Ok4USfcc0aJcUAzs": { + "balance": 69, + "vaults": [ + { + "amount": 0.01, + "start": 649388, + "end": 650388 + }, + { + "amount": 0.005, + "start": 649390, + "end": 650390 + } + ], + "stake": 69 + }, + "DfCXDjdxcTIg1-FQDZ5jDclk1shKIpMlshe0IXodApc": { + "balance": 69, + "vaults": [], + "stake": 69 + } + }, + "executables": { + "Ms6RRl0eh96F_lcKYyiJhWRdRIiB6z0VaThCvBZDOAc": { + "_discriminator": "result", + "bids": [ + { + "bidder": "Pq6OBljxlpypNuE0O1eL92Kr9U1Ok4USfcc0aJcUAzs", + "quantity": 0.01 + } + ], + "caller": "Pq6OBljxlpypNuE0O1eL92Kr9U1Ok4USfcc0aJcUAzs", + "executable": { + "birth_height": 649382, + "executable_address": "is9cDN3ZKPun0F2KmEHnhiRuUcYOO3Dzfef-B5ZAQeQ", + "executable_kind": "wasm" + }, + "accepted_bid": { + "bidder": "Pq6OBljxlpypNuE0O1eL92Kr9U1Ok4USfcc0aJcUAzs", + "quantity": 0.01 + }, + "validation_linked_list": { + "value": [ + { + "_discriminator": "release", + "validator": "Pq6OBljxlpypNuE0O1eL92Kr9U1Ok4USfcc0aJcUAzs", + "encrypted_hash": "af8e9c76fc012934cd3009c0cb7cac697da634350aa7dd6a063ccc3fdbc533f815799ed08d72d06a84961e468cd2af3fec5549350ce582c74eea7c29e020acf052c3e619cc69aa98e6e5b43bd10574dce88bb204289891c97a535d1da69f32e0e42dd906159b47acb3d435679b9c61dc", + "symm_key": "sokka" + }, + { + "_discriminator": "lock", + "validator": "DfCXDjdxcTIg1-FQDZ5jDclk1shKIpMlshe0IXodApc", + "encrypted_hash": "af8e9c76fc012934cd3009c0cb7cac697da634350aa7dd6a063ccc3fdbc533f815799ed08d72d06a84961e468cd2af3fec5549350ce582c74eea7c29e020acf052c3e619cc69aa98e6e5b43bd10574dce88bb204289891c97a535d1da69f32e0e42dd906159b47acb3d435679b9c61dc" + } + ] + }, + "result": { + "address": "OTWNmd9aSARYg1X4ds8CwSVmx_dNYHb_ka-W2VAJ7NQ", + "giver": "Pq6OBljxlpypNuE0O1eL92Kr9U1Ok4USfcc0aJcUAzs", + "height": 649390 + } + }, + "Xstw2Ss9TMCkV92ozHTsvIDPsPXnMDZVzfKPTPxgAq0": { + "_discriminator": "proposed", + "bids": [], + "caller": "Pq6OBljxlpypNuE0O1eL92Kr9U1Ok4USfcc0aJcUAzs", + "executable": { + "birth_height": 649387, + "executable_address": "is9cDN3ZKPun0F2KmEHnhiRuUcYOO3Dzfef-B5ZAQeQ", + "executable_kind": "wasm" + } + } + }, + "ticker": "FEA" +} diff --git a/_scripts/single-state-comparator.ts b/_scripts/single-state-comparator.ts new file mode 100644 index 0000000..2d391aa --- /dev/null +++ b/_scripts/single-state-comparator.ts @@ -0,0 +1,54 @@ +/* eslint-disable */ +import { LoggerFactory, SmartWeaveNodeFactory } from '@smartweave'; +import Arweave from 'arweave'; +import fs from 'fs'; +import path from 'path'; +import { readContract } from 'smartweave'; + +async function main() { + const arweave = Arweave.init({ + host: 'arweave.net', // Hostname or IP address for a Arweave host + port: 443, // Port + protocol: 'https', // Network protocol http or https + timeout: 60000, // Network request timeouts in milliseconds + logging: false // Enable network request logging + }); + const logger = LoggerFactory.INST.create(__filename); + const smartWeave = SmartWeaveNodeFactory.memCached(arweave); + + const contractTxId = 'YLVpmhSq5JmLltfg6R-5fL04rIRPrlSU22f6RQ6VyYE'; + // Kyve: + // C_1uo08qRuQAeDi9Y1I8fkaWYUC9IWkOrKDNe9EphJo + // OFD4GqQcqp-Y_Iqh8DN_0s3a_68oMvvnekeOEu_a45I + // 8cq1wbjWHNiPg7GwYpoDT2m9HX99LY7tklRQWfh1L6c + + const resultDiffs = []; + + try { + logger.info('readContract'); + const { state, validity } = await readContract(arweave, contractTxId, undefined, true); + logger.debug('readContract validity', validity); + const resultString = JSON.stringify(state); + + logger.info('readState'); + const result2 = await smartWeave.contract(contractTxId).readState(); + logger.debug('readState validity', result2.validity); + const result2String = JSON.stringify(result2.state); + + if (resultString.localeCompare(result2String) !== 0) { + console.error('\n\n ====== States differ ======\n\n'); + resultDiffs.push(contractTxId); + const targetPath = path.join(__dirname, 'diffs', contractTxId); + if (!fs.existsSync(targetPath)) { + fs.mkdirSync(targetPath); + } + fs.writeFileSync(path.join(targetPath, 'new.json'), result2String); + fs.writeFileSync(path.join(targetPath, 'old.json'), resultString); + } + } catch (e) { + logger.error(e); + logger.info('skipping ', contractTxId); + } +} + +main(); diff --git a/_scripts/state-comparator.ts b/_scripts/state-comparator.ts index 2e273c8..d9fe887 100644 --- a/_scripts/state-comparator.ts +++ b/_scripts/state-comparator.ts @@ -32,7 +32,8 @@ query Transactions($tags: [TagFilter!]!, $after: String) { }`; const logger = LoggerFactory.INST.create(__filename); -LoggerFactory.INST.logLevel('silly', 'state-comparator'); + +// LoggerFactory.INST.logLevel('debug'); async function main() { const arweave = Arweave.init({ @@ -45,13 +46,16 @@ async function main() { const txs = loadTxFromFile(); - logger.silly(`Checking ${txs.length} contracts`); + const resumeFromContractTxId = 'YLVpmhSq5JmLltfg6R-5fL04rIRPrlSU22f6RQ6VyYE'; + let resumeFrom = true; + + logger.info(`Checking ${txs.length} contracts`); const differentStatesContractTxIds = []; const errorContractTxIds = []; - const swcClient = SmartWeaveNodeFactory.fileCacheClient(arweave, 'cache'); + const smartWeave = SmartWeaveNodeFactory.memCached(arweave); const contractsBlacklist = [ 'jFInOjLc_FFt802OmUObIIOlY1xNKvomzUTkoUpyP9U', // readContract very long evaluation @@ -162,15 +166,13 @@ async function main() { let counter = 0; - const resumeFromContractTxId = 'jFInOjLc_FFt802OmUObIIOlY1xNKvomzUTkoUpyP9U'; - let resumeFrom = false; - for (const contractTxId of txs) { const tx: Transaction = await arweave.transactions.get(contractTxId); counter++; - logger.silly(`\n${contractTxId}: [${counter}/${txs.length}]`); + logger.info(`\n${contractTxId}: [${counter}/${txs.length}]`); if (resumeFrom && contractTxId.localeCompare(resumeFromContractTxId) !== 0) { + console.info('Skipping...'); continue; } else { resumeFrom = false; @@ -200,14 +202,14 @@ async function main() { // console.log(resultString); logger.info('readState'); - const result2 = await swcClient.readState(contractTxId, null, null, { - ignoreExceptions: true - }); + const result2 = await smartWeave.contract(contractTxId).readState(); const result2String = JSON.stringify(result2.state); // console.log(result2String); if (resultString.localeCompare(result2String) !== 0) { logger.error('States differ!'); + fs.writeFileSync(path.join(__dirname, 'diffs', `${contractTxId}_old.json`), resultString); + fs.writeFileSync(path.join(__dirname, 'diffs', `${contractTxId}_new.json`), result2String); differentStatesContractTxIds.push(contractTxId); } } catch (e) { @@ -215,7 +217,7 @@ async function main() { logger.info('skipping ', contractTxId); errorContractTxIds.push(contractTxId); } finally { - logger.trace('Contracts with different states:', differentStatesContractTxIds); + logger.debug('Contracts with different states:', differentStatesContractTxIds); logger.info('\n\n ==== END'); } } @@ -224,7 +226,7 @@ async function main() { main().catch(); function loadTxFromFile(): string[] { - const transactions = JSON.parse(fs.readFileSync(path.join(__dirname, 'swc-sorted-stats.json'), 'utf-8')); + const transactions = JSON.parse(fs.readFileSync(path.join(__dirname, 'test-cases.json'), 'utf-8')); return Object.keys(transactions); } diff --git a/_scripts/swc-sorted-stats.json b/_scripts/test-cases.json similarity index 100% rename from _scripts/swc-sorted-stats.json rename to _scripts/test-cases.json diff --git a/src/contract/HandlerBasedContract.ts b/src/contract/HandlerBasedContract.ts index 115ad58..b3f81a1 100644 --- a/src/contract/HandlerBasedContract.ts +++ b/src/contract/HandlerBasedContract.ts @@ -1,5 +1,6 @@ import { JWKInterface } from 'arweave/node/lib/wallet'; import { + Benchmark, Contract, ContractInteraction, DefaultEvaluationOptions, @@ -28,7 +29,9 @@ export class HandlerBasedContract implements Contract { constructor( private readonly contractTxId: string, private readonly smartweave: SmartWeave, - private readonly parentContract: Contract = null + // note: this will be probably used for creating contract's + // call hierarchy and generating some sort of "stack trace" + private readonly callingContract: Contract = null ) {} async readState( @@ -36,11 +39,11 @@ export class HandlerBasedContract implements Contract { currentTx?: { interactionTxId: string; contractTxId: string }[], evaluationOptions?: EvaluationOptions ): Promise> { - logger.info('Read state for %s', this.contractTxId); + logger.info('Read state for', this.contractTxId); const { stateEvaluator } = this.smartweave; const executionContext = await this.createExecutionContext(this.contractTxId, blockHeight, evaluationOptions); - const result = await stateEvaluator.eval(executionContext, currentTx || []); + const result = await stateEvaluator.eval(executionContext, currentTx || []); return result as EvalStateResult; } @@ -53,7 +56,7 @@ export class HandlerBasedContract implements Contract { throw new Error("Wallet not connected. Use 'connect' method first."); } - logger.info('View state for %s', this.contractTxId); + logger.info('View state for', this.contractTxId); const { arweave, stateEvaluator } = this.smartweave; let executionContext = await this.createExecutionContext(this.contractTxId, blockHeight, evaluationOptions); @@ -111,7 +114,7 @@ export class HandlerBasedContract implements Contract { transaction: InteractionTx, evaluationOptions?: EvaluationOptions ): Promise> { - logger.info('Vies state for %s %o', this.contractTxId, transaction); + logger.info(`Vies state for ${this.contractTxId}`, transaction); const { stateEvaluator } = this.smartweave; const executionContext = await this.createExecutionContextFromTx(this.contractTxId, transaction); @@ -139,6 +142,7 @@ export class HandlerBasedContract implements Contract { blockHeight?: number, evaluationOptions?: EvaluationOptions ): Promise> { + const benchmark = Benchmark.measure(); const { arweave, definitionLoader, interactionsLoader, interactionsSorter } = this.smartweave; let currentNetworkInfo; @@ -158,6 +162,8 @@ export class HandlerBasedContract implements Contract { const interactions = await interactionsLoader.load(contractTxId, blockHeight); const sortedInteractions = await interactionsSorter.sort(interactions); + logger.debug('Creating execution context:', benchmark.elapsed()); + return { contractDefinition, blockHeight, @@ -175,7 +181,8 @@ export class HandlerBasedContract implements Contract { transaction: InteractionTx, evaluationOptions?: EvaluationOptions ): Promise> { - const { definitionLoader, executorFactory, interactionsLoader, interactionsSorter } = this.smartweave; + const benchmark = Benchmark.measure(); + const { definitionLoader, interactionsLoader, interactionsSorter } = this.smartweave; const blockHeight = transaction.block.height; const caller = transaction.owner.address; const contractDefinition = await definitionLoader.load(contractTxId); @@ -185,6 +192,7 @@ export class HandlerBasedContract implements Contract { if (evaluationOptions == null) { evaluationOptions = new DefaultEvaluationOptions(); } + logger.debug('Creating execution context from tx:', benchmark.elapsed()); return { contractDefinition, diff --git a/src/contract/SmartWeave.ts b/src/contract/SmartWeave.ts index 7699ec8..ee49a77 100644 --- a/src/contract/SmartWeave.ts +++ b/src/contract/SmartWeave.ts @@ -10,7 +10,12 @@ import Arweave from 'arweave'; import { Contract, HandlerBasedContract, SmartWeaveBuilder } from '@smartweave/contract'; /** - * The "motherboard" ;-) + * The SmartWeave "motherboard" ;-). + * This is the base class that supplies the implementation of the SmartWeave SDK. + * Allows to plug-in different implementation of all parts defined in its constructors. + * + * After being fully configured, it allows to "connect" to + * contract and perform operations on them (see {@link Contract}) */ export class SmartWeave { constructor( @@ -18,7 +23,7 @@ export class SmartWeave { readonly definitionLoader: DefinitionLoader, readonly interactionsLoader: InteractionsLoader, readonly interactionsSorter: InteractionsSorter, - readonly executorFactory: ExecutorFactory>, + readonly executorFactory: ExecutorFactory>, // TODO: really struggling with TS generics here... readonly stateEvaluator: StateEvaluator ) {} @@ -26,7 +31,7 @@ export class SmartWeave { return new SmartWeaveBuilder(arweave); } - contract(contractTxId: string, parent?: Contract): Contract { - return new HandlerBasedContract(contractTxId, this, parent); + contract(contractTxId: string, callingContract?: Contract): Contract { + return new HandlerBasedContract(contractTxId, this, callingContract); } } diff --git a/src/core/impl/ContractDefinitionLoader.ts b/src/core/impl/ContractDefinitionLoader.ts index 41873b8..926ff4b 100644 --- a/src/core/impl/ContractDefinitionLoader.ts +++ b/src/core/impl/ContractDefinitionLoader.ts @@ -1,4 +1,12 @@ -import { ContractDefinition, DefinitionLoader, getTag, LoggerFactory, SmartWeaveTags, SwCache } from '@smartweave'; +import { + Benchmark, + ContractDefinition, + DefinitionLoader, + getTag, + LoggerFactory, + SmartWeaveTags, + SwCache +} from '@smartweave'; import Arweave from 'arweave'; import Transaction from 'arweave/web/lib/transaction'; @@ -32,7 +40,6 @@ export class ContractDefinitionLoader implements DefinitionLoader { const minFee = getTag(contractTx, SmartWeaveTags.MIN_FEE); const contractSrcTx = await this.arweave.transactions.get(contractSrcTxId); const src = contractSrcTx.get('data', { decode: true, string: true }); - const initState = JSON.parse(await this.evalInitialState(contractTx)); return { diff --git a/src/core/impl/DefaultStateEvaluator.ts b/src/core/impl/DefaultStateEvaluator.ts index d41dafb..d1160f6 100644 --- a/src/core/impl/DefaultStateEvaluator.ts +++ b/src/core/impl/DefaultStateEvaluator.ts @@ -15,6 +15,8 @@ import { StateEvaluator } from '@smartweave'; import Arweave from 'arweave'; +import fs from 'fs'; +import path from 'path'; const logger = LoggerFactory.INST.create(__filename); @@ -43,6 +45,7 @@ export class DefaultStateEvaluator implements StateEvaluator { executionContext: ExecutionContext, currentTx: { interactionTxId: string; contractTxId: string }[] ): Promise> { + const stateEvaluationBenchmark = Benchmark.measure(); const evaluationOptions = executionContext.evaluationOptions; let currentState = baseState.state; @@ -56,13 +59,22 @@ export class DefaultStateEvaluator implements StateEvaluator { executionContext.contractDefinition )) as HandlerApi; + logger.debug( + 'missingInteractions', + missingInteractions.map((int) => { + return int.node.id; + }) + ); + + logger.debug('Init state', JSON.stringify(baseState.state)); + for (const missingInteraction of missingInteractions) { logger.debug( `${missingInteraction.node.id}: ${missingInteractions.indexOf(missingInteraction) + 1}/${ missingInteractions.length } [of all:${executionContext.sortedInteractions.length}]` ); - const benchmark = Benchmark.measure(); + const singleInteractionBenchmark = Benchmark.measure(); const currentInteraction: GQLNodeInterface = missingInteraction.node; const inputTag = this.findInputTag(missingInteraction, executionContext); @@ -91,18 +103,23 @@ export class DefaultStateEvaluator implements StateEvaluator { } validity[currentInteraction.id] = result.type === 'ok'; + currentState = result.state; - logger.debug(`${missingInteraction.node.id} evaluation`, benchmark.elapsed()); // I'm really NOT a fan of this "modify" feature, but I don't have idea how to better // implement the "evolve" feature for (const { modify } of this.executionContextModifiers) { + // strangely - state is for some reason modified for some contracts (eg. YLVpmhSq5JmLltfg6R-5fL04rIRPrlSU22f6RQ6VyYE) + // when calling any async (even simple timeout) function here... + // that's a dumb workaround for this issue + const stateCopy = JSON.parse(JSON.stringify(currentState)); executionContext = await modify(currentState, executionContext); + currentState = stateCopy; } this.onStateUpdate(currentInteraction, executionContext, new EvalStateResult(currentState, validity)); } - + console.debug('State evaluation total:', stateEvaluationBenchmark.elapsed()); return new EvalStateResult(currentState, validity); } diff --git a/src/core/impl/HandlerExecutorFactory.ts b/src/core/impl/HandlerExecutorFactory.ts index ab14c76..5d1f42d 100644 --- a/src/core/impl/HandlerExecutorFactory.ts +++ b/src/core/impl/HandlerExecutorFactory.ts @@ -28,6 +28,8 @@ const logger = LoggerFactory.INST.create(__filename); /** * A factory that produces handlers that are compatible with the "current" style of * writing SW contracts (ie. using "handle" function). + * Note: this code is mostly ported from the previous version of the SDK and is somewhat messy... + * First candidate for the refactor! */ export class HandlerExecutorFactory implements ExecutorFactory> { constructor(private readonly arweave: Arweave) {} @@ -105,7 +107,7 @@ export class HandlerExecutorFactory implements ExecutorFactory