Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Common/Block/EVM: Deprecation Cleanup Work #2706

Merged
merged 6 commits into from
May 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 1 addition & 22 deletions packages/blockchain/src/blockchain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ export class Blockchain implements BlockchainInterface {
/**
* Returns the specified iterator head.
*
* This function replaces the old {@link Blockchain.getHead} method. Note that
* This function replaces the old Blockchain.getHead() method. Note that
* the function deviates from the old behavior and returns the
* genesis hash instead of the current head block if an iterator
* has not been run. This matches the behavior of {@link Blockchain.iterator}.
Expand All @@ -295,27 +295,6 @@ export class Blockchain implements BlockchainInterface {
})
}

/**
* Returns the specified iterator head.
*
* @param name - Optional name of the iterator head (default: 'vm')
*
* @deprecated use {@link Blockchain.getIteratorHead} instead.
* Note that {@link Blockchain.getIteratorHead} doesn't return
* the `headHeader` but the genesis hash as an initial iterator
* head value (now matching the behavior of {@link Blockchain.iterator}
* on a first run)
*/
async getHead(name = 'vm'): Promise<Block> {
return this.runWithLock<Block>(async () => {
// if the head is not found return the headHeader
const hash = this._heads[name] ?? this._headBlockHash
if (hash === undefined) throw new Error('No head found.')
const block = await this.getBlock(hash)
return block
})
}

/**
* Returns the latest header in the canonical chain.
*/
Expand Down
66 changes: 0 additions & 66 deletions packages/common/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -714,20 +714,6 @@ export class Common extends EventEmitter {
return BigInt(ttd)
}

/**
* True if block number provided is the hardfork (given or set) change block
* @param blockNumber Number of the block to check
* @param hardfork Hardfork name, optional if HF set
* @returns True if blockNumber is HF block
* @deprecated
*/
isHardforkBlock(blockNumber: BigIntLike, hardfork?: string | Hardfork): boolean {
blockNumber = toType(blockNumber, TypeOutput.BigInt)
hardfork = hardfork ?? this._hardfork
const block = this.hardforkBlock(hardfork)
return typeof block === 'bigint' && block !== BigInt(0) ? block === blockNumber : false
}

/**
* Returns the change block for the next hardfork after the hardfork provided or set
* @param hardfork Hardfork name, optional if HF set
Expand Down Expand Up @@ -777,58 +763,6 @@ export class Common extends EventEmitter {
return BigInt(nextHfBlock)
}

/**
* Returns the change block for the next hardfork after the hardfork provided or set
* @param hardfork Hardfork name, optional if HF set
* @returns Block number or null if not available
* @deprecated
*/
nextHardforkBlock(hardfork?: string | Hardfork): bigint | null {
hardfork = hardfork ?? this._hardfork
let hfBlock = this.hardforkBlock(hardfork)
// If this is a merge hardfork with block not set, then we fallback to previous hardfork
// to find the nextHardforkBlock
if (hfBlock === null && hardfork === Hardfork.Paris) {
const hfs = this.hardforks()
const mergeIndex = hfs.findIndex((hf) => hf.ttd !== null && hf.ttd !== undefined)
if (mergeIndex < 0) {
throw Error(`Paris (Merge) hardfork should have been found`)
}
hfBlock = this.hardforkBlock(hfs[mergeIndex - 1].name)
}
if (hfBlock === null) {
return null
}
// Next fork block number or null if none available
// Logic: if accumulator is still null and on the first occurrence of
// a block greater than the current hfBlock set the accumulator,
// pass on the accumulator as the final result from this time on
const nextHfBlock = this.hardforks().reduce((acc: bigint | null, hf: HardforkConfig) => {
// We need to ignore the merge block in our next hardfork calc
const block = BigInt(
hf.block === null || (hf.ttd !== undefined && hf.ttd !== null) ? 0 : hf.block
)
// Typescript can't seem to follow that the hfBlock is not null at this point
return block > hfBlock! && acc === null ? block : acc
}, null)
return nextHfBlock
}

/**
* True if block number provided is the hardfork change block following the hardfork given or set
* @param blockNumber Number of the block to check
* @param hardfork Hardfork name, optional if HF set
* @returns True if blockNumber is HF block
* @deprecated
*/
isNextHardforkBlock(blockNumber: BigIntLike, hardfork?: string | Hardfork): boolean {
blockNumber = toType(blockNumber, TypeOutput.BigInt)
hardfork = hardfork ?? this._hardfork
const nextHardforkBlock = this.nextHardforkBlock(hardfork)

return nextHardforkBlock === null ? false : nextHardforkBlock === blockNumber
}

/**
* Internal helper function to calculate a fork hash
* @param hardfork Hardfork name
Expand Down
7 changes: 6 additions & 1 deletion packages/common/src/eips/4399.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
"minimumHardfork": "london",
"requiredEIPs": [],
"gasConfig": {},
"gasPrices": {},
"gasPrices": {
"prevrandao": {
"v": 2,
"d": "Base fee of the PREVRANDAO opcode (previously DIFFICULTY)"
}
},
"vm": {},
"pow": {}
}
4 changes: 2 additions & 2 deletions packages/common/src/hardforks/chainstart.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@
"v": 10,
"d": "Times ceil(log256(exponent)) for the EXP instruction"
},
"sha3": {
"keccak256": {
"v": 30,
"d": "Base fee of the SHA3 opcode"
},
"sha3Word": {
"keccak256Word": {
"v": 6,
"d": "Once per word of the SHA3 operation's data"
},
Expand Down
40 changes: 0 additions & 40 deletions packages/common/test/hardforks.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,24 +124,6 @@ tape('[Common]: Hardfork logic', function (t: tape.Test) {
st.end()
})

t.test('isHardforkBlock()', function (st: tape.Test) {
let c = new Common({ chain: Chain.Ropsten })
let msg = 'should return true for HF change block for byzantium (provided)'
st.equal(c.isHardforkBlock(1700000, Hardfork.Byzantium), true, msg)

msg = 'should return false for another block for byzantium (provided)'
st.equal(c.isHardforkBlock(1700001, Hardfork.Byzantium), false, msg)

c = new Common({ chain: Chain.Ropsten, hardfork: Hardfork.Byzantium })
msg = 'should return true for HF change block for byzantium (set)'
st.equal(c.isHardforkBlock(1700000), true, msg)

msg = 'should return false for another block for byzantium (set)'
st.equal(c.isHardforkBlock(1700001), false, msg)

st.end()
})

t.test('nextHardforkBlockOrTimestamp()', function (st: tape.Test) {
let c = new Common({ chain: Chain.Rinkeby, hardfork: Hardfork.Chainstart })
let msg =
Expand All @@ -166,28 +148,6 @@ tape('[Common]: Hardfork logic', function (t: tape.Test) {
st.end()
})

t.test('isNextHardforkBlock()', function (st: tape.Test) {
const c = new Common({ chain: Chain.Rinkeby, hardfork: Hardfork.Chainstart })
let msg =
'should work with HF set / return true for correct next HF block for chainstart (rinkeby: chainstart -> homestead)'
st.equal(c.isNextHardforkBlock(1), true, msg)

msg =
'should correctly skip a HF where block is set to null (rinkeby: homestead -> (dao) -> tangerineWhistle)'
st.equal(c.isNextHardforkBlock(2, 'homestead'), true, msg)

msg = 'should return true for correct next HF (rinkeby: byzantium -> constantinople)'
st.equal(c.isNextHardforkBlock(3660663, Hardfork.Byzantium), true, msg)

msg = 'should return false for a block number too low (rinkeby: byzantium -> constantinople)'
st.equal(c.isNextHardforkBlock(124, Hardfork.Byzantium), false, msg)

msg = 'should return false for a block number too high (rinkeby: byzantium -> constantinople)'
st.equal(c.isNextHardforkBlock(605948938, Hardfork.Byzantium), false, msg)

st.end()
})

t.test('hardforkIsActiveOnBlock() / activeOnBlock()', function (st: tape.Test) {
let c = new Common({ chain: Chain.Ropsten })
let msg = 'Ropsten, byzantium (provided), 1700000 -> true'
Expand Down
34 changes: 20 additions & 14 deletions packages/evm/src/opcodes/codes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const opcodes: OpcodeEntry = {
0x1a: { name: 'BYTE', isAsync: false, dynamicGas: false },

// 0x20 range - crypto
0x20: { name: 'SHA3', isAsync: false, dynamicGas: true },
0x20: { name: 'KECCAK256', isAsync: false, dynamicGas: true },

// 0x30 range - closure state
0x30: { name: 'ADDRESS', isAsync: true, dynamicGas: false },
Expand Down Expand Up @@ -212,7 +212,7 @@ const hardforkOpcodes: { hardfork: Hardfork; opcodes: OpcodeEntry }[] = [
{
hardfork: Hardfork.Homestead,
opcodes: {
0xf4: { name: 'DELEGATECALL', isAsync: true, dynamicGas: true }, // EIP 7
0xf4: { name: 'DELEGATECALL', isAsync: true, dynamicGas: true }, // EIP-7
},
},
{
Expand All @@ -223,35 +223,41 @@ const hardforkOpcodes: { hardfork: Hardfork; opcodes: OpcodeEntry }[] = [
0xf2: { name: 'CALLCODE', isAsync: true, dynamicGas: true },
0x3b: { name: 'EXTCODESIZE', isAsync: true, dynamicGas: true },
0x3c: { name: 'EXTCODECOPY', isAsync: true, dynamicGas: true },
0xf4: { name: 'DELEGATECALL', isAsync: true, dynamicGas: true }, // EIP 7
0xf4: { name: 'DELEGATECALL', isAsync: true, dynamicGas: true }, // EIP-7
0xff: { name: 'SELFDESTRUCT', isAsync: true, dynamicGas: true },
0x31: { name: 'BALANCE', isAsync: true, dynamicGas: true },
},
},
{
hardfork: Hardfork.Byzantium,
opcodes: {
0xfd: { name: 'REVERT', isAsync: false, dynamicGas: true }, // EIP 140
0xfa: { name: 'STATICCALL', isAsync: true, dynamicGas: true }, // EIP 214
0x3d: { name: 'RETURNDATASIZE', isAsync: true, dynamicGas: false }, // EIP 211
0x3e: { name: 'RETURNDATACOPY', isAsync: true, dynamicGas: true }, // EIP 211
0xfd: { name: 'REVERT', isAsync: false, dynamicGas: true }, // EIP-140
0xfa: { name: 'STATICCALL', isAsync: true, dynamicGas: true }, // EIP-214
0x3d: { name: 'RETURNDATASIZE', isAsync: true, dynamicGas: false }, // EIP-211
0x3e: { name: 'RETURNDATACOPY', isAsync: true, dynamicGas: true }, // EIP-211
},
},
{
hardfork: Hardfork.Constantinople,
opcodes: {
0x1b: { name: 'SHL', isAsync: false, dynamicGas: false }, // EIP 145
0x1c: { name: 'SHR', isAsync: false, dynamicGas: false }, // EIP 145
0x1d: { name: 'SAR', isAsync: false, dynamicGas: false }, // EIP 145
0x3f: { name: 'EXTCODEHASH', isAsync: true, dynamicGas: true }, // EIP 1052
0xf5: { name: 'CREATE2', isAsync: true, dynamicGas: true }, // EIP 1014
0x1b: { name: 'SHL', isAsync: false, dynamicGas: false }, // EIP-145
0x1c: { name: 'SHR', isAsync: false, dynamicGas: false }, // EIP-145
0x1d: { name: 'SAR', isAsync: false, dynamicGas: false }, // EIP-145
0x3f: { name: 'EXTCODEHASH', isAsync: true, dynamicGas: true }, // EIP-1052
0xf5: { name: 'CREATE2', isAsync: true, dynamicGas: true }, // EIP-1014
},
},
{
hardfork: Hardfork.Istanbul,
opcodes: {
0x46: { name: 'CHAINID', isAsync: false, dynamicGas: false }, // EIP 1344
0x47: { name: 'SELFBALANCE', isAsync: false, dynamicGas: false }, // EIP 1884
0x46: { name: 'CHAINID', isAsync: false, dynamicGas: false }, // EIP-1344
0x47: { name: 'SELFBALANCE', isAsync: false, dynamicGas: false }, // EIP-1884
},
},
{
hardfork: Hardfork.Paris,
opcodes: {
0x44: { name: 'PREVRANDAO', isAsync: true, dynamicGas: false }, // EIP-4399
},
},
]
Expand Down
2 changes: 1 addition & 1 deletion packages/evm/src/opcodes/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ export const handlers: Map<number, OpHandler> = new Map([
},
],
// 0x20 range - crypto
// 0x20: SHA3
// 0x20: KECCAK256
[
0x20,
function (runState) {
Expand Down
6 changes: 3 additions & 3 deletions packages/evm/src/opcodes/gas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ export const dynamicGasHandlers: Map<number, AsyncDynamicGasHandler | SyncDynami
},
],
[
/* SHA3 */
/* KECCAK256 */
0x20,
async function (runState, gas, common): Promise<bigint> {
const [offset, length] = runState.stack.peek(2)
gas += subMemUsage(runState, offset, length, common)
gas += common.param('gasPrices', 'sha3Word') * divCeil(length, BigInt(32))
gas += common.param('gasPrices', 'keccak256Word') * divCeil(length, BigInt(32))
return gas
},
],
Expand Down Expand Up @@ -473,7 +473,7 @@ export const dynamicGasHandlers: Map<number, AsyncDynamicGasHandler | SyncDynami
((length + BigInt(31)) / BigInt(32)) * common.param('gasPrices', 'initCodeWordCost')
}

gas += common.param('gasPrices', 'sha3Word') * divCeil(length, BigInt(32))
gas += common.param('gasPrices', 'keccak256Word') * divCeil(length, BigInt(32))
let gasLimit = runState.interpreter.getGasLeft() - gas
gasLimit = maxCallGas(gasLimit, gasLimit, runState, common) // CREATE2 is only available after TangerineWhistle (Constantinople introduced this opcode)
runState.messageGasLimit = gasLimit
Expand Down
27 changes: 27 additions & 0 deletions packages/evm/test/opcodes.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as tape from 'tape'
import { EVM } from '../src'

tape('EVM -> getActiveOpcodes()', (t) => {
const DIFFICULTY_PREVRANDAO = 0x44
const CHAINID = 0x46 //istanbul opcode
const BEGINSUB = 0x5c // EIP-2315 opcode

Expand Down Expand Up @@ -48,6 +49,32 @@ tape('EVM -> getActiveOpcodes()', (t) => {
st.end()
})

t.test('should switch DIFFICULTY opcode name to PREVRANDAO when >= Merge HF', async (st) => {
let common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Istanbul })
let evm = await EVM.create({
common,
stateManager: new DefaultStateManager(),
})
st.equal(
evm.getActiveOpcodes().get(DIFFICULTY_PREVRANDAO)!.name,
'DIFFICULTY',
'Opcode x44 named DIFFICULTY pre-Merge'
)

common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Paris })
evm = await EVM.create({
common,
stateManager: new DefaultStateManager(),
})
st.equal(
evm.getActiveOpcodes().get(DIFFICULTY_PREVRANDAO)!.name,
'PREVRANDAO',
'Opcode x44 named PREVRANDAO post-Merge'
)

st.end()
})

t.test('should expose opcodes when EIP is active', async (st) => {
let common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Istanbul, eips: [2315] })
let evm = await EVM.create({
Expand Down
2 changes: 1 addition & 1 deletion packages/vm/test/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export function dumpState(state: any, cb: Function) {
results.push(result)
}
for (let i = 0; i < results.length; i++) {
console.log("SHA3'd address: " + bytesToHex(results[i].address))
console.log('Hashed address: ' + bytesToHex(results[i].address))
console.log('\tstorage root: ' + bytesToHex(results[i].storageRoot))
console.log('\tstorage: ')
for (const storageKey in results[i].storage) {
Expand Down