Skip to content

Berlinterop devnet 2 #3400

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

Closed
wants to merge 31 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
a5c5362
add the block validation check
advaita-saha Jun 10, 2025
08816a3
restrict block production to 10MB
advaita-saha Jun 11, 2025
bdf2591
temp fix
advaita-saha Jun 11, 2025
e171145
secp256r1 impl
advaita-saha Jun 12, 2025
0cae682
remove unwanted stuff
advaita-saha Jun 12, 2025
ab95690
fix double hashing
advaita-saha Jun 12, 2025
d481c60
remove commented code
advaita-saha Jun 12, 2025
b88979f
add complete test suite
advaita-saha Jun 12, 2025
bb1bfad
improve performance
advaita-saha Jun 12, 2025
cf05a0d
Merge branch 'master' into eip-7951
advaita-saha Jun 12, 2025
e4fd912
fix gas calculation
advaita-saha Jun 12, 2025
8a3970b
fix unwanted ECC Points
advaita-saha Jun 13, 2025
9eedcca
initial impl of CLZ
advaita-saha Jun 13, 2025
abee849
few more fixes
advaita-saha Jun 13, 2025
0a0f86f
enum error fix
chirag-parmar Jun 13, 2025
da600b1
update copyright year
chirag-parmar Jun 13, 2025
70e0955
fix weird EIP, no error but consume gas
advaita-saha Jun 13, 2025
dbc54f7
fix
chirag-parmar Jun 13, 2025
06d8cfc
Merge branch 'CLZ' into berlinterop-devnet-1
chirag-parmar Jun 13, 2025
8b3623c
Merge remote-tracking branch 'origin/eip-7951' into berlinterop-devnet-1
chirag-parmar Jun 13, 2025
6905019
initial impl of CLZ
advaita-saha Jun 13, 2025
d95bfb1
enum error fix
chirag-parmar Jun 13, 2025
41bbc80
update copyright year
chirag-parmar Jun 13, 2025
d4306e1
fix
chirag-parmar Jun 13, 2025
7b5efbe
add gas and Prague
advaita-saha Jun 13, 2025
2df3d67
execution_chain
advaita-saha Jun 13, 2025
2017994
Merge branch 'eip-7934' into CLZ
advaita-saha Jun 13, 2025
ca15b24
Revert "Merge branch 'eip-7934' into CLZ"
advaita-saha Jun 13, 2025
4a3b239
resolve
advaita-saha Jun 13, 2025
475600c
add eip-7883 changes
advaita-saha Jun 13, 2025
749c2c1
Merge branch 'modexp-new' into berlinterop-devnet-1
advaita-saha Jun 13, 2025
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
7 changes: 2 additions & 5 deletions Dockerfile.debug
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,10 @@ COPY ./ /nimbus-eth1

WORKDIR /nimbus-eth1

RUN mv vendor vendor.orig

RUN --mount=type=cache,target=/nimbus-eth1/build --mount=type=cache,target=/nimbus-eth1/vendor \
mv vendor.orig vendor && \
RUN --mount=type=cache,target=/nimbus-eth1/build \
make -j${NPROC} NIMFLAGS="${NIMFLAGS_COMMON} --parallelBuild:${NPROC}" V=1 update

RUN --mount=type=cache,target=/nimbus-eth1/build --mount=type=cache,target=/nimbus-eth1/vendor \
RUN --mount=type=cache,target=/nimbus-eth1/build \
make -j${NPROC} NIMFLAGS="${NIMFLAGS_COMMON} --parallelBuild:${NPROC}" nimbus_execution_client && \
mv build/nimbus_execution_client /usr/local/bin/nimbus_execution_client

Expand Down
5 changes: 3 additions & 2 deletions PrecompileTests.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ PrecompileTests
===
## PrecompileTests
```diff
+ P256Verify.json OK
+ blake2F.json OK
+ blsG1Add.json OK
+ blsG1MultiExp.json OK
Expand All @@ -24,7 +25,7 @@ PrecompileTests
+ ripemd160.json OK
+ sha256.json OK
```
OK: 21/21 Fail: 0/21 Skip: 0/21
OK: 22/22 Fail: 0/22 Skip: 0/22
## eest
```diff
+ add_G1_bls.json OK
Expand All @@ -49,4 +50,4 @@ OK: 21/21 Fail: 0/21 Skip: 0/21
OK: 18/18 Fail: 0/18 Skip: 0/18

---TOTAL---
OK: 39/39 Fail: 0/39 Skip: 0/39
OK: 40/40 Fail: 0/40 Skip: 0/40
2 changes: 2 additions & 0 deletions execution_chain/evm/interpreter/gas_costs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,7 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) =
Shl: fixed GasVeryLow,
Shr: fixed GasVeryLow,
Sar: fixed GasVeryLow,
Clz: fixed GasVeryLow,

# 20s: SHA3
Sha3: memExpansion `prefix gasSha3`,
Expand Down Expand Up @@ -858,3 +859,4 @@ const
Bls12381PairingPerPairGas* = GasInt 32600
Bls12381MapG1Gas* = GasInt 5500
Bls12381MapG2Gas* = GasInt 23800
GasP256VerifyGas* = GasInt 3450
5 changes: 3 additions & 2 deletions execution_chain/evm/interpreter/op_codes.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Nimbus
# Copyright (c) 2018-2024 Status Research & Development GmbH
# Copyright (c) 2018-2025 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0)
Expand Down Expand Up @@ -58,8 +58,9 @@ type
Shl = 0x1B, ## Shift left
Shr = 0x1C, ## Logical shift right
Sar = 0x1D, ## Arithmetic shift right
Clz = 0x1E, ## Count leading zeros

Nop0x1E, Nop0x1F, ## ..
Nop0x1F, ## ..

# 20s: SHA3
Sha3 = 0x20, ## Compute Keccak-256 hash.
Expand Down
30 changes: 28 additions & 2 deletions execution_chain/evm/interpreter/op_handlers/oph_arithmetic.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Nimbus
# Copyright (c) 2018-2024 Status Research & Development GmbH
# Copyright (c) 2018-2025 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0)
Expand Down Expand Up @@ -277,6 +277,26 @@ proc sarOp(cpt: VmCpt): EvmResultVoid =

cpt.stack.binaryWithTop(sar256)

proc clzOp(cpt: VmCpt): EvmResultVoid =
## 0x1e, Count Leading Zeros
template clz256(top, value, toStackElem) =
if value.isZero:
toStackElem(256.u256, top)
else:
var count = 0
for i in 0 ..< 32:
let b = (value shr ((31 - i) * 8)).truncate(byte)
if b != 0:
var mask = 0x80'u8
while (b and mask) == 0:
inc count
mask = mask shr 1
break
inc count, 8
toStackElem(count.u256, top)

cpt.stack.unaryWithTop(clz256)

# ------------------------------------------------------------------------------
# Public, op exec table entries
# ------------------------------------------------------------------------------
Expand Down Expand Up @@ -460,7 +480,13 @@ const
forks: VmOpConstantinopleAndLater,
name: "sarOp",
info: "Arithmetic shift right",
exec: sarOp)]
exec: sarOp),

(opCode: Clz, ## CLZ (Count Leading Zeros)
forks: VmOpOsakaAndLater, ## Or a newer fork gate, if appropriate
name: "clzOp",
info: "Count leading zero bits in a 256-bit word",
exec: clzOp)]

# ------------------------------------------------------------------------------
# End
Expand Down
6 changes: 6 additions & 0 deletions execution_chain/evm/interpreter/op_handlers/oph_defs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ const
VmOpCancunAndLater* =
VmOpShanghaiAndLater - {FkShanghai}

VmOpPragueAndLater* =
VmOpCancunAndLater - {FkCancun}

VmOpOsakaAndLater* =
VmOpPragueAndLater - {FkPrague}

# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------
183 changes: 137 additions & 46 deletions execution_chain/evm/precompiles.nim
Original file line number Diff line number Diff line change
Expand Up @@ -17,56 +17,115 @@ import
chronicles,
nimcrypto/[ripemd, sha2, utils],
bncurve/[fields, groups],
stew/assign2,
stew/[assign2, endians2, byteutils],
libp2p/crypto/ecnist,
../common/evmforks,
../core/eip4844,
./modexp,
./evm_errors,
./computation,
./secp256r1verify,
eth/common/[base, addresses]

type
PrecompileAddresses* = enum
Precompiles* = enum
# Frontier to Spurious Dragron
paEcRecover = 0x01
paSha256 = 0x02
paRipeMd160 = 0x03
paIdentity = 0x04
paEcRecover
paSha256
paRipeMd160
paIdentity
# Byzantium and Constantinople
paModExp = 0x05
paEcAdd = 0x06
paEcMul = 0x07
paPairing = 0x08
paModExp
paEcAdd
paEcMul
paPairing
# Istanbul
paBlake2bf = 0x09
paBlake2bf
# Cancun
paPointEvaluation = 0x0a
paPointEvaluation
# Prague (EIP-2537)
paBlsG1Add = 0x0b
paBlsG1MultiExp = 0x0c
paBlsG2Add = 0x0d
paBlsG2MultiExp = 0x0e
paBlsPairing = 0x0f
paBlsMapG1 = 0x10
paBlsMapG2 = 0x11
paBlsG1Add
paBlsG1MultiExp
paBlsG2Add
paBlsG2MultiExp
paBlsPairing
paBlsMapG1
paBlsMapG2
# Osaka
paP256Verify

SigRes = object
msgHash: array[32, byte]
sig: Signature

const
# Frontier to Spurious Dragron
paEcRecoverAddress = Address.fromHex("0x0000000000000000000000000000000000000001")
paSha256Address = Address.fromHex("0x0000000000000000000000000000000000000002")
paRipeMd160Address = Address.fromHex("0x0000000000000000000000000000000000000003")
paIdentityAddress = Address.fromHex("0x0000000000000000000000000000000000000004")
# Byzantium and Constantinople
paModExpAddress = Address.fromHex("0x0000000000000000000000000000000000000005")
paEcAddAddress = Address.fromHex("0x0000000000000000000000000000000000000006")
paEcMulAddress = Address.fromHex("0x0000000000000000000000000000000000000007")
paPairingAddress = Address.fromHex("0x0000000000000000000000000000000000000008")
# Istanbul
paBlake2bfAddress = Address.fromHex("0x0000000000000000000000000000000000000009")
# Cancun
paPointEvaluationAddress = Address.fromHex("0x000000000000000000000000000000000000000a")
# Prague (EIP-2537)
paBlsG1AddAddress = Address.fromHex("0x000000000000000000000000000000000000000b")
paBlsG1MultiExpAddress = Address.fromHex("0x000000000000000000000000000000000000000c")
paBlsG2AddAddress = Address.fromHex("0x000000000000000000000000000000000000000d")
paBlsG2MultiExpAddress = Address.fromHex("0x000000000000000000000000000000000000000e")
paBlsPairingAddress = Address.fromHex("0x000000000000000000000000000000000000000f")
paBlsMapG1Address = Address.fromHex("0x0000000000000000000000000000000000000010")
paBlsMapG2Address = Address.fromHex("0x0000000000000000000000000000000000000011")
# Osaka
paP256VerifyAddress = Address.fromHex("0x0000000000000000000000000000000000000100")

precompileAddrs*: array[Precompiles, Address] = [
# Frontier to Spurious Dragon
paEcRecoverAddress, # paEcRecover
paSha256Address, # paSha256
paRipeMd160Address, # paRipeMd160
paIdentityAddress, # paIdentity

# Byzantium and Constantinople
paModExpAddress, # paModExp
paEcAddAddress, # paEcAdd
paEcMulAddress, # paEcMul
paPairingAddress, # paPairing

# Istanbul
paBlake2bfAddress, # paBlake2bf

# Cancun
paPointEvaluationAddress, # paPointEvaluation

# Prague (EIP-2537)
paBlsG1AddAddress, # paBlsG1Add
paBlsG1MultiExpAddress, # paBlsG1MultiExp
paBlsG2AddAddress, # paBlsG2Add
paBlsG2MultiExpAddress, # paBlsG2MultiExp
paBlsPairingAddress, # paBlsPairing
paBlsMapG1Address, # paBlsMapG1
paBlsMapG2Address, # paBlsMapG2
paP256VerifyAddress # paP256Verify
]


# ------------------------------------------------------------------------------
# Private functions
# ------------------------------------------------------------------------------

func getMaxPrecompileAddr(fork: EVMFork): PrecompileAddresses =
func getMaxPrecompile(fork: EVMFork): Precompiles =
if fork < FkByzantium: paIdentity
elif fork < FkIstanbul: paPairing
elif fork < FkCancun: paBlake2bf
elif fork < FkPrague: paPointEvaluation
else: PrecompileAddresses.high

func validPrecompileAddr(addrByte, maxPrecompileAddr: byte): bool =
(addrByte in PrecompileAddresses.low.byte .. maxPrecompileAddr)
elif fork < FkOsaka: paBlsMapG2
else: Precompiles.high

func getSignature(c: Computation): EvmResult[SigRes] =
# input is Hash, V, R, S
Expand Down Expand Up @@ -205,11 +264,11 @@ func modExpFee(c: Computation,
result = result * result

func mulComplexityEIP7883(maxLen: UInt256): UInt256 =
# gas = ceil(x div 8) ^ 2
result = maxLen + 7
result = result div 8
result = result * result
result = 16'u256
if maxLen > 32.u256:
result = maxLen + 7
result = result div 8
result = result * result
result = result * 2

let adjExpLen = block:
Expand Down Expand Up @@ -694,36 +753,67 @@ proc pointEvaluation(c: Computation): EvmResultVoid =
c.output = @PointEvaluationResult
ok()

proc p256verify(c: Computation): EvmResultVoid =

template failed() =
c.output.setLen(0)
return ok()

? c.gasMeter.consumeGas(GasP256VerifyGas, reason="P256VERIFY Precompile")

if c.msg.data.len != 160:
failed()

var inputPubKey: array[65, byte]

# Validations
if isInfinityByte(c.msg.data.toOpenArray(96, 159)):
failed()

# Check scalar and field bounds (r, s ∈ (0, n), qx, qy ∈ [0, p))
var sig: EcSignature
if not sig.initRaw(c.msg.data.toOpenArray(32, 95)):
failed()

var pubkey: EcPublicKey
inputPubKey[0] = 4.byte
assign(inputPubKey.toOpenArray(1, 64), c.msg.data.toOpenArray(96, 159))

if not pubkey.initRaw(inputPubKey):
failed()

let isValid = sig.verifyRaw(c.msg.data.toOpenArray(0, 31), pubkey)

if isValid:
c.output.setLen(32)
c.output[^1] = 1.byte # return 0x...01
else:
c.output.setLen(0)

ok()

# ------------------------------------------------------------------------------
# Public functions
# ------------------------------------------------------------------------------

iterator activePrecompiles*(fork: EVMFork): Address =
var res: Address
let maxPrecompileAddr = getMaxPrecompileAddr(fork)
for c in PrecompileAddresses.low..maxPrecompileAddr:
if validPrecompileAddr(c.byte, maxPrecompileAddr.byte):
res.data[^1] = c.byte
yield res
let maxPrecompile = getMaxPrecompile(fork)
for c in Precompiles.low..maxPrecompile:
yield precompileAddrs[c]

func activePrecompilesList*(fork: EVMFork): seq[Address] =
for address in activePrecompiles(fork):
result.add address

proc getPrecompile*(fork: EVMFork, b: byte): Opt[PrecompileAddresses] =
let maxPrecompileAddr = getMaxPrecompileAddr(fork)
if validPrecompileAddr(b, maxPrecompileAddr.byte):
Opt.some(PrecompileAddresses(b))
else:
Opt.none(PrecompileAddresses)
proc getPrecompile*(fork: EVMFork, codeAddress: Address): Opt[Precompiles] =
let maxPrecompile = getMaxPrecompile(fork)
for c in Precompiles.low..maxPrecompile:
if precompileAddrs[c] == codeAddress:
return Opt.some(c)

proc getPrecompile*(fork: EVMFork, codeAddress: Address): Opt[PrecompileAddresses] =
for i in 0..18:
if codeAddress.data[i] != 0:
return Opt.none(PrecompileAddresses)
getPrecompile(fork, codeAddress.data[19])
Opt.none(Precompiles)

proc execPrecompile*(c: Computation, precompile: PrecompileAddresses) =
proc execPrecompile*(c: Computation, precompile: Precompiles) =
let fork = c.fork
let res = case precompile
of paEcRecover: ecRecover(c)
Expand All @@ -743,6 +833,7 @@ proc execPrecompile*(c: Computation, precompile: PrecompileAddresses) =
of paBlsPairing: blsPairing(c)
of paBlsMapG1: blsMapG1(c)
of paBlsMapG2: blsMapG2(c)
of paP256Verify: p256verify(c)

if res.isErr:
if res.error.code == EvmErrorCode.OutOfGas:
Expand Down
Loading
Loading