Skip to content

Commit

Permalink
feat: blockchain.recordStorage
Browse files Browse the repository at this point in the history
  • Loading branch information
krigga committed Sep 17, 2024
1 parent 7b2781c commit fe0fc3b
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 52 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
52 changes: 1 addition & 51 deletions src/blockchain/Blockchain.spec.ts
Original file line number Diff line number Diff line change
@@ -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()

Expand Down
11 changes: 11 additions & 0 deletions src/blockchain/Blockchain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ export type BlockchainTransaction = Transaction & {
parent?: BlockchainTransaction,
children: BlockchainTransaction[],
externals: ExternalOut[],
oldStorage?: Cell,
newStorage?: Cell,
}

/**
Expand Down Expand Up @@ -167,6 +169,7 @@ export class Blockchain {
protected lock = new AsyncLock()
protected contractFetches = new Map<string, Promise<SmartContract>>()
protected nextCreateWalletIndex = 0
protected shouldRecordStorage = false

readonly executor: IExecutor

Expand Down Expand Up @@ -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
*/
Expand Down
14 changes: 14 additions & 0 deletions src/blockchain/SmartContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ export type SmartContractTransaction = Transaction & {
blockchainLogs: string
vmLogs: string
debugLogs: string
oldStorage?: Cell
newStorage?: Cell
}
export type MessageParams = Partial<{
now: number,
Expand Down Expand Up @@ -292,6 +294,11 @@ export class SmartContract {
}

protected async runCommon(run: () => Promise<EmulationResult>): Promise<SmartContractTransaction> {
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) {
Expand Down Expand Up @@ -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,
}
}

Expand Down

0 comments on commit fe0fc3b

Please sign in to comment.