From fe0fc3b09adc0921d047543e5a7a3b1436d1c819 Mon Sep 17 00:00:00 2001 From: krigga <25533192+krigga@users.noreply.github.com> Date: Tue, 17 Sep 2024 18:23:23 +0300 Subject: [PATCH] feat: blockchain.recordStorage --- CHANGELOG.md | 6 ++++ package.json | 2 +- src/blockchain/Blockchain.spec.ts | 52 +------------------------------ src/blockchain/Blockchain.ts | 11 +++++++ src/blockchain/SmartContract.ts | 14 +++++++++ 5 files changed, 33 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 368c432..95d2315 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.22.0] - 2024-09-17 + +### Added + +- Added `blockchain.recordStorage` flag. If set to `true`, `BlockchainTransaction` will have `oldStorage` and `newStorage` fields. Note that enabling this flag will disable a certain optimization, which will slow down contract emulation + ## [0.21.0] - 2024-09-16 ### Added diff --git a/package.json b/package.json index 52ef4a7..8df1a4c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ton/sandbox", - "version": "0.21.0", + "version": "0.22.0", "description": "TON transaction emulator", "main": "dist/index.js", "license": "MIT", diff --git a/src/blockchain/Blockchain.spec.ts b/src/blockchain/Blockchain.spec.ts index 8a322a9..bcf822d 100644 --- a/src/blockchain/Blockchain.spec.ts +++ b/src/blockchain/Blockchain.spec.ts @@ -1,62 +1,12 @@ import {Blockchain, BlockchainTransaction} from "./Blockchain"; -import {Address, beginCell, Cell, Contract, contractAddress, ContractProvider, Message, Sender, storeTransaction, toNano} from "@ton/core"; +import {Address, beginCell, Cell, Contract, contractAddress, ContractProvider, Sender, storeTransaction, toNano} from "@ton/core"; import {compareTransaction, flattenTransaction, randomAddress} from "@ton/test-utils"; -import {TonClient4} from "@ton/ton"; -import {RemoteBlockchainStorage, wrapTonClient4ForRemote} from "./BlockchainStorage"; -import {prettyLogTransactions} from "../utils/prettyLogTransaction"; -import {printTransactionFees} from "../utils/printTransactionFees"; import { createShardAccount, GetMethodError, TimeError } from "./SmartContract"; import { internal } from "../utils/message"; import { SandboxContractProvider } from "./BlockchainContractProvider"; import { TickOrTock } from "../executor/Executor"; describe('Blockchain', () => { - jest.setTimeout(30000) - - it('should work with remote storage', async () => { - let client = new TonClient4({ - endpoint: 'https://mainnet-v4.tonhubapi.com' - }) - - let blockchain = await Blockchain.create({ - storage: new RemoteBlockchainStorage(wrapTonClient4ForRemote(client), 34892000) - }) - - let buyer = randomAddress() - - let saleContractAddress = Address.parse('EQARG1yo4fg29oCxOFM3Ua2rizUErlRw9gu0RWvIfKFtxsF0') - - let message: Message = { - info: { - type: 'internal', - dest: saleContractAddress, - src: buyer, - value: { coins: toNano(400) }, - bounce: true, - ihrDisabled: true, - bounced: false, - ihrFee: 0n, - forwardFee: 0n, - createdAt: 0, - createdLt: 0n - }, - body: beginCell().endCell() - } - - let res = await blockchain.sendMessage(message) - - prettyLogTransactions(res.transactions) - - printTransactionFees(res.transactions) - - let nft = await blockchain.getContract(Address.parse('EQDTbyyOixs9JsO8bmHjk9WJYN8deL-qJeNZvWx147pM8qeO')) - let data = await nft.get('get_nft_data') - - let [, , , owner] = [data.stackReader.pop(), data.stackReader.pop(), data.stackReader.pop(), data.stackReader.readAddress()] - - expect(buyer.equals(owner)).toBe(true) - }) - it('should print debug logs', async () => { const blockchain = await Blockchain.create() diff --git a/src/blockchain/Blockchain.ts b/src/blockchain/Blockchain.ts index 8d33f4e..b3161c9 100644 --- a/src/blockchain/Blockchain.ts +++ b/src/blockchain/Blockchain.ts @@ -57,6 +57,8 @@ export type BlockchainTransaction = Transaction & { parent?: BlockchainTransaction, children: BlockchainTransaction[], externals: ExternalOut[], + oldStorage?: Cell, + newStorage?: Cell, } /** @@ -167,6 +169,7 @@ export class Blockchain { protected lock = new AsyncLock() protected contractFetches = new Map>() protected nextCreateWalletIndex = 0 + protected shouldRecordStorage = false readonly executor: IExecutor @@ -211,6 +214,14 @@ export class Blockchain { this.nextCreateWalletIndex = snapshot.nextCreateWalletIndex } + get recordStorage() { + return this.shouldRecordStorage + } + + set recordStorage(v: boolean) { + this.shouldRecordStorage = v + } + /** * @returns Current time in blockchain */ diff --git a/src/blockchain/SmartContract.ts b/src/blockchain/SmartContract.ts index 5a94844..68c7f92 100644 --- a/src/blockchain/SmartContract.ts +++ b/src/blockchain/SmartContract.ts @@ -94,6 +94,8 @@ export type SmartContractTransaction = Transaction & { blockchainLogs: string vmLogs: string debugLogs: string + oldStorage?: Cell + newStorage?: Cell } export type MessageParams = Partial<{ now: number, @@ -292,6 +294,11 @@ export class SmartContract { } protected async runCommon(run: () => Promise): Promise { + let oldStorage: Cell | undefined = undefined + if (this.blockchain.recordStorage && this.account.account?.storage.state.type === 'active') { + oldStorage = this.account.account?.storage.state.state.data ?? undefined + } + const res = await run() if (this.verbosity.print && this.verbosity.blockchainLogs && res.logs.length > 0) { @@ -322,11 +329,18 @@ export class SmartContract { this.#parsedAccount = undefined this.#lastTxTime = tx.now + let newStorage: Cell | undefined = undefined + if (this.blockchain.recordStorage && this.account.account?.storage.state.type === 'active') { + newStorage = this.account.account?.storage.state.state.data ?? undefined + } + return { ...tx, blockchainLogs: res.logs, vmLogs: res.result.vmLog, debugLogs: res.debugLogs, + oldStorage, + newStorage, } }