Fixed faulty trie and state db

pull/4529/head
ioedeveloper 9 months ago
parent 3fd72bfcf1
commit d236c64633
  1. 6
      apps/remix-ide/src/blockchain/execution-context.js
  2. 5
      apps/remix-ide/src/blockchain/providers/vm.ts
  3. 1
      libs/remix-lib/src/execution/logsManager.ts
  4. 5
      libs/remix-lib/src/execution/txRunnerVM.ts
  5. 5
      libs/remix-simulator/src/methods/transactions.ts
  6. 12
      libs/remix-simulator/src/provider.ts
  7. 57
      libs/remix-simulator/src/vm-context.ts

@ -208,19 +208,15 @@ export class ExecutionContext {
async getStateDetails() {
// TODO: this won't save the state for transactions executed outside of the UI (for instance from a script execution).
const root = await this.web3().remix.getStateTrieRoot()
const db = await this.web3().remix.getStateDb()
const blocksData = await this.web3().remix.getBlocksData()
const state = {
root,
db: Object.fromEntries(db._database),
blocks: blocksData.blocks,
latestBlockNumber: blocksData.latestBlockNumber
}
const stringifyed = JSON.stringify(state, (key, value) => {
if (key === 'root') {
return bufferToHex(value)
} else if (key === 'db') {
if (key === 'db') {
return value
} else if (key === 'blocks') {
return value.map(block => bufferToHex(block))

@ -79,10 +79,7 @@ export class VMProvider {
try {
const blockchainState = JSON.parse(stringifiedState)
const blockNumber = parseInt(blockchainState.latestBlockNumber, 16)
const stateDb = {
root: toBuffer(blockchainState.root),
db: new Map(Object.entries(blockchainState.db))
}
const stateDb = blockchainState.db
this.worker.postMessage({
cmd: 'init',

@ -21,6 +21,7 @@ export class LogsManager {
eachOf(block.transactions, (tx: any, i, next) => {
const txHash = '0x' + tx.hash().toString('hex')
web3.eth.getTransactionReceipt(txHash, (_error, receipt) => {
if (!receipt) return next()
for (const log of receipt.logs) {
this.oldLogs.push({ type: 'block', blockNumber, block, tx, log, txNumber: i, receipt })
const subscriptions = this.getSubscriptionsFor({ type: 'block', blockNumber, block, tx, log, receipt})

@ -51,9 +51,9 @@ export class TxRunnerVM {
const vm = this.getVMObject().vm
if (Array.isArray(blocks) && (blocks || []).length > 0) {
const block = Block.fromRLPSerializedBlock(blocks[blocks.length - 1], { common: this.commonContext })
const lastBlock = Block.fromRLPSerializedBlock(blocks[blocks.length - 1], { common: this.commonContext })
this.blockParentHash = block.hash()
this.blockParentHash = lastBlock.hash()
this.blocks = blocks
} else {
this.blockParentHash = vm.blockchain.genesisBlock.hash()
@ -113,7 +113,6 @@ export class TxRunnerVM {
const coinbases = ['0x0e9281e9c6a0808672eaba6bd1220e144c9bb07a', '0x8945a1288dc78a6d8952a92c77aee6730b414778', '0x94d76e24f818426ae84aa404140e8d5f60e10e7e']
const difficulties = [69762765929000, 70762765929000, 71762765929000]
const difficulty = this.commonContext.consensusType() === ConsensusType.ProofOfStake ? 0 : difficulties[this.blockNumber % difficulties.length]
const blocknumber = this.blocks.length
const block = Block.fromBlockData({
header: {

@ -75,7 +75,6 @@ export class Transactions {
eth_getHHLogsForTx: this.eth_getHHLogsForTx.bind(this),
eth_getHashFromTagBySimulator: this.eth_getHashFromTagBySimulator.bind(this),
eth_registerCallId: this.eth_registerCallId.bind(this),
eth_getStateTrieRoot: this.eth_getStateTrieRoot.bind(this),
eth_getStateDb: this.eth_getStateDb.bind(this),
eth_getBlocksData: this.eth_getBlocksData.bind(this)
}
@ -201,10 +200,6 @@ export class Transactions {
cb()
}
eth_getStateTrieRoot (_, cb) {
cb(null, this.vmContext.currentVm.stateManager.getTrie().root())
}
eth_getStateDb (_, cb) {
cb(null, this.vmContext.currentVm.stateManager.getDb())
}

@ -28,10 +28,7 @@ export interface JSONRPCResponsePayload {
export type JSONRPCResponseCallback = (err: Error, result?: JSONRPCResponsePayload) => void
export type State = {
db: Map<string, Buffer>,
root: Buffer
}
export type State = Record<string, string>
export type ProviderOptions = {
fork: string,
@ -184,13 +181,6 @@ class Web3TestPlugin extends Web3PluginBase {
})
}
public getStateTrieRoot() {
return this.requestManager.send({
method: 'eth_getStateTrieRoot',
params: []
})
}
public getStateDb() {
return this.requestManager.send({
method: 'eth_getStateDb',

@ -13,7 +13,7 @@ import { VmProxy } from './VmProxy'
import { VM } from '@ethereumjs/vm'
import type { BigIntLike } from '@ethereumjs/util'
import { Common, ConsensusType } from '@ethereumjs/common'
import { Trie, MapDB, DB } from '@ethereumjs/trie'
import { Trie, MapDB } from '@ethereumjs/trie'
import { DefaultStateManager, StateManager, EthersStateManager, EthersStateManagerOpts } from '@ethereumjs/statemanager'
import { StorageDump } from '@ethereumjs/statemanager/dist/interface'
import { EVM } from '@ethereumjs/evm'
@ -40,47 +40,19 @@ export interface DefaultStateManagerOpts {
prefixCodeHashes?: boolean
}
class RemixMapDb extends MapDB {
async get(key: Buffer): Promise<Buffer | null> {
// the remix db contains stringified values (in order to save space),
// that's why we need to convert the hex string to the native type that the Trie understands.
let value = await super.get(key)
if (typeof value === 'string') {
value = toBuffer(value)
}
return value
}
copy(): DB {
return new RemixMapDb(this._database)
}
}
/*
extend vm state manager and instantiate VM
*/
class StateManagerCommonStorageDump extends DefaultStateManager {
keyHashes: { [key: string]: string }
internalTree: Trie
db: MapDB
stateDb: State
constructor (opts: DefaultStateManagerOpts = {}, stateDb?: State) {
const db = new RemixMapDb(stateDb ? stateDb.db: null)
const trie = new Trie({ useKeyHashing: true, db, useRootPersistence: true})
opts = { trie, ...opts }
constructor (opts: DefaultStateManagerOpts = {}) {
super(opts)
this.stateDb = stateDb
this.internalTree = trie
this.db = db
this.keyHashes = {}
}
getTrie () {
return this.internalTree
}
getDb () {
return this.db
// @ts-ignore
return this._trie.database().db
}
putContractStorage (address, key, value) {
@ -91,7 +63,7 @@ class StateManagerCommonStorageDump extends DefaultStateManager {
copy(): StateManagerCommonStorageDump {
const copyState = new StateManagerCommonStorageDump({
trie: this._trie.copy(false),
}, this.stateDb)
})
copyState.keyHashes = this.keyHashes
return copyState
}
@ -133,9 +105,8 @@ export interface CustomEthersStateManagerOpts {
class CustomEthersStateManager extends StateManagerCommonStorageDump {
private provider: ethers.providers.StaticJsonRpcProvider | ethers.providers.JsonRpcProvider
private blockTag: string
constructor(opts: CustomEthersStateManagerOpts, stateDb?: State) {
super(opts, stateDb)
this.stateDb = stateDb
constructor(opts: CustomEthersStateManagerOpts) {
super(opts)
if (typeof opts.provider === 'string') {
this.provider = new ethers.providers.StaticJsonRpcProvider(opts.provider)
} else if (opts.provider instanceof ethers.providers.JsonRpcProvider) {
@ -187,7 +158,7 @@ class CustomEthersStateManager extends StateManagerCommonStorageDump {
provider: this.provider,
blockTag: this.blockTag,
trie: this._trie.copy(false),
}, this.stateDb)
})
return newState
}
@ -366,17 +337,21 @@ export class VMContext {
stateManager = new CustomEthersStateManager({
provider: this.nodeUrl,
blockTag: '0x' + block.toString(16)
}, this.stateDb)
})
this.blockNumber = block
} else {
stateManager = new CustomEthersStateManager({
provider: this.nodeUrl,
blockTag: '0x' + this.blockNumber.toString(16)
}, this.stateDb)
})
}
} else{
const db = this.stateDb ? new Map(Object.entries(this.stateDb).map(([k, v]) => [k, toBuffer(v)])) : new Map()
const mapDb = new MapDB(db)
const trie = await Trie.create({ useKeyHashing: true, db: mapDb, useRootPersistence: true })
} else
stateManager = new StateManagerCommonStorageDump(null, this.stateDb)
stateManager = new StateManagerCommonStorageDump({ trie })
}
const consensusType = hardfork === 'berlin' || hardfork === 'london' ? ConsensusType.ProofOfWork : ConsensusType.ProofOfStake
const difficulty = consensusType === ConsensusType.ProofOfStake ? 0 : 69762765929000

Loading…
Cancel
Save