Skip to content

Commit

Permalink
common: add spec test for 2935 contract code and update history stora…
Browse files Browse the repository at this point in the history
…ge address (#3373)

* vm: add spec test for 2935 contract code

* update the history address

* reset the hitory address for kaustinen6

* make sure kaustinen6 still uses old history save address

* apply dry feedback
  • Loading branch information
g11tech committed May 3, 2024
1 parent eef06a5 commit d94dc5f
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 2 deletions.
10 changes: 9 additions & 1 deletion packages/common/src/eips.ts
Expand Up @@ -222,7 +222,7 @@ export const EIPs: EIPsDict = {
requiredEIPs: [],
vm: {
historyStorageAddress: {
v: BigInt('0xfffffffffffffffffffffffffffffffffffffffe'),
v: BigInt('0x25a219378dad9b3503c8268c9ca836a52427a4fb'),
d: 'The address where the historical blockhashes are stored',
},
historyServeWindow: {
Expand Down Expand Up @@ -535,6 +535,14 @@ export const EIPs: EIPsDict = {
d: 'Gas cost of the first read of storage from a given location (per transaction)',
},
},
vm: {
// kaustinen 6 current uses this address, however this will be updated to correct address
// in next iteration
historyStorageAddress: {
v: BigInt('0xfffffffffffffffffffffffffffffffffffffffe'),
d: 'The address where the historical blockhashes are stored',
},
},
},
7002: {
comment: 'Execution layer triggerable withdrawals (experimental)',
Expand Down
2 changes: 1 addition & 1 deletion packages/common/src/hardforks.ts
Expand Up @@ -849,6 +849,6 @@ export const hardforks: HardforksDict = {
'Next feature hardfork after prague, internally used for verkle testing/implementation (incomplete/experimental)',
url: 'https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/osaka.md',
status: Status.Draft,
eips: [6800, 2935],
eips: [2935, 6800],
},
}
58 changes: 58 additions & 0 deletions packages/vm/test/api/EIPs/eip-2935-historical-block-hashes.spec.ts
@@ -1,12 +1,18 @@
import { Block } from '@ethereumjs/block'
import { Blockchain } from '@ethereumjs/blockchain'
import { Common, Hardfork } from '@ethereumjs/common'
import { LegacyTransaction } from '@ethereumjs/tx'
import {
Account,
Address,
BIGINT_1,
bigIntToBytes,
bigIntToHex,
bytesToHex,
equalsBytes,
privateToAddress,
setLengthLeft,
unprefixedHexToBytes,
zeros,
} from '@ethereumjs/util'
import { hexToBytes } from 'ethereum-cryptography/utils'
Expand Down Expand Up @@ -76,6 +82,32 @@ commonGenesis.setHardforkBy({
const historyAddress = Address.fromString(
bigIntToHex(commonGenesis.param('vm', 'historyStorageAddress'))
)
const contract2935Code = unprefixedHexToBytes(
'60203611603157600143035f35116029575f356120000143116029576120005f3506545f5260205ff35b5f5f5260205ff35b5f5ffd00'
)

const callerPrivateKey = hexToBytes(`0x${'44'.repeat(32)}`)
const callerAddress = new Address(privateToAddress(callerPrivateKey))
const PREBALANCE = BigInt(10000000)

async function testBlockhashContract(vm: VM, block: Block, i: bigint): Promise<Uint8Array> {
const tx = LegacyTransaction.fromTxData({
to: historyAddress,
gasLimit: 1000000,
gasPrice: 10,
data: bytesToHex(setLengthLeft(bigIntToBytes(i), 32)),
}).sign(callerPrivateKey)

await vm.stateManager.putAccount(callerAddress, new Account())
const account = await vm.stateManager.getAccount(callerAddress)
account!.balance = PREBALANCE
await vm.stateManager.putAccount(callerAddress, account!)
await vm.stateManager.putContractCode(historyAddress, contract2935Code)

const result = await vm.runTx({ tx, block, skipHardForkValidation: true })
const blockHashi = result.execResult.returnValue
return blockHashi
}

describe('EIP 2935: historical block hashes', () => {
it('should save genesis block hash to the history block hash contract', async () => {
Expand All @@ -86,6 +118,7 @@ describe('EIP 2935: historical block hashes', () => {
validateConsensus: false,
})
const vm = await VM.create({ common: commonGenesis, blockchain })

commonGenesis.setHardforkBy({
timestamp: 1,
})
Expand Down Expand Up @@ -166,5 +199,30 @@ describe('EIP 2935: historical block hashes', () => {
assert.ok(equalsBytes(ret.execResult.returnValue, zeros(64)))
}
}

// validate the contract code cases
// const result = await vm.runTx({ tx, block, skipHardForkValidation: true })
const block = Block.fromBlockData(
{
header: {
baseFeePerGas: BigInt(7),
number: blocksToBuild,
},
},
{ common }
)

// should be able to resolve blockhash via contract code
for (const i of [0, 1, blocksActivation, blocksToBuild - 1]) {
const blockHashi = await testBlockhashContract(vm, block, BigInt(i))
const blocki = await vm.blockchain.getBlock(i)
assert.ok(equalsBytes(blockHashi, blocki.hash()))
}

// should be able to return 0 if input >= current block
for (const i of [blocksToBuild, blocksToBuild + 100]) {
const blockHashi = await testBlockhashContract(vm, block, BigInt(i))
assert.ok(equalsBytes(blockHashi, setLengthLeft(bigIntToBytes(BigInt(0)), 32)))
}
})
})

0 comments on commit d94dc5f

Please sign in to comment.