Skip to content

Commit a7d2b5c

Browse files
author
Michał Mrożek
authored
Merge pull request #646 from input-output-hk/etcm-18-reduce-alt-bn128-precompile-gas-cost
[ETCM-18] EIP-1108: Reduce alt_bn128 precompile gas costs
2 parents c153333 + 0b45947 commit a7d2b5c

File tree

3 files changed

+67
-21
lines changed

3 files changed

+67
-21
lines changed

src/main/scala/io/iohk/ethereum/vm/BlockchainConfigForEvm.scala

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package io.iohk.ethereum.vm
22

33
import io.iohk.ethereum.domain.UInt256
44
import io.iohk.ethereum.utils.BlockchainConfig
5+
import io.iohk.ethereum.vm.BlockchainConfigForEvm.EtcForks.{Agharta, Atlantis, BeforeAtlantis, EtcFork, Phoenix}
6+
import io.iohk.ethereum.vm.BlockchainConfigForEvm.EthForks.{BeforeByzantium, Byzantium, Constantinople, Petersburg}
57

68
/**
79
* A subset of [[io.iohk.ethereum.utils.BlockchainConfig]] that is required for instantiating an [[EvmConfig]]
@@ -23,9 +25,36 @@ case class BlockchainConfigForEvm(
2325
petersburgBlockNumber: BigInt,
2426
phoenixBlockNumber: BigInt,
2527
chainId: Byte
26-
)
28+
){
29+
def etcForkForBlockNumber(blockNumber: BigInt): EtcFork = blockNumber match {
30+
case _ if blockNumber < atlantisBlockNumber => BeforeAtlantis
31+
case _ if blockNumber < aghartaBlockNumber => Atlantis
32+
case _ if blockNumber < phoenixBlockNumber => Agharta
33+
case _ if blockNumber >= phoenixBlockNumber => Phoenix
34+
}
35+
36+
def ethForkForBlockNumber(blockNumber: BigInt): BlockchainConfigForEvm.EthForks.Value = blockNumber match {
37+
case _ if blockNumber < byzantiumBlockNumber => BeforeByzantium
38+
case _ if blockNumber < constantinopleBlockNumber => Byzantium
39+
case _ if blockNumber < petersburgBlockNumber => Constantinople
40+
case _ if blockNumber >= petersburgBlockNumber => Petersburg
41+
// TODO add Istanbul
42+
}
43+
}
2744

2845
object BlockchainConfigForEvm {
46+
47+
object EtcForks extends Enumeration {
48+
type EtcFork = Value
49+
val BeforeAtlantis, Atlantis, Agharta, Phoenix = Value
50+
}
51+
52+
object EthForks extends Enumeration {
53+
type EthFork = Value
54+
val BeforeByzantium, Byzantium, Constantinople, Petersburg, Istanbul = Value
55+
}
56+
57+
2958
def apply(blockchainConfig: BlockchainConfig): BlockchainConfigForEvm = {
3059
import blockchainConfig._
3160
BlockchainConfigForEvm(

src/main/scala/io/iohk/ethereum/vm/OpCode.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import akka.util.ByteString
44
import io.iohk.ethereum.crypto.kec256
55
import io.iohk.ethereum.domain.{Account, Address, TxLogEntry, UInt256}
66
import io.iohk.ethereum.domain.UInt256._
7+
import io.iohk.ethereum.vm.BlockchainConfigForEvm.EthForks
78

89
// scalastyle:off magic.number
910
// scalastyle:off number.of.types
@@ -664,7 +665,7 @@ case object SSTORE extends OpCode(0x55, 2, 0, _.G_zero) {
664665

665666
private def isEip1283Enabled[W <: WorldStateProxy[W, S], S <: Storage[S]](state: ProgramState[W, S]): Boolean = {
666667
val blockNumber = state.env.blockHeader.number
667-
blockNumber >= state.config.blockchainConfig.constantinopleBlockNumber && blockNumber < state.config.blockchainConfig.petersburgBlockNumber
668+
state.config.blockchainConfig.ethForkForBlockNumber(blockNumber) == EthForks.Constantinople
668669
}
669670
}
670671

src/main/scala/io/iohk/ethereum/vm/PrecompiledContracts.scala

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ import io.iohk.ethereum.crypto.zksnark.{BN128Fp, PairingCheck}
77
import io.iohk.ethereum.crypto.zksnark.PairingCheck.G1G2Pair
88
import io.iohk.ethereum.domain.Address
99
import io.iohk.ethereum.utils.ByteUtils
10-
10+
import io.iohk.ethereum.vm.BlockchainConfigForEvm.EtcForks.EtcFork
11+
import io.iohk.ethereum.vm.BlockchainConfigForEvm.EthForks.EthFork
12+
import io.iohk.ethereum.vm.BlockchainConfigForEvm.{EtcForks, EthForks}
1113
import scala.util.Try
1214

1315
// scalastyle:off magic.number
@@ -29,7 +31,7 @@ object PrecompiledContracts {
2931
IdAddr -> Identity
3032
)
3133

32-
val byzantiumContracts = contracts ++ Map(
34+
val byzantiumAtlantisContracts = contracts ++ Map(
3335
ModExpAddr -> ModExp,
3436
Bn128AddAddr -> Bn128Add,
3537
Bn128MulAddr -> Bn128Mul,
@@ -51,21 +53,25 @@ object PrecompiledContracts {
5153

5254
private def getContract(context: ProgramContext[_, _]): Option[PrecompiledContract] = {
5355
context.recipientAddr.flatMap{ addr =>
54-
if (context.blockHeader.number >= context.evmConfig.blockchainConfig.byzantiumBlockNumber ||
55-
context.blockHeader.number >= context.evmConfig.blockchainConfig.atlantisBlockNumber) {
56+
if (context.evmConfig.blockchainConfig.ethForkForBlockNumber(context.blockHeader.number) >= EthForks.Byzantium ||
57+
context.evmConfig.blockchainConfig.etcForkForBlockNumber(context.blockHeader.number) >= EtcForks.Atlantis) {
5658
// byzantium and atlantis hard fork introduce the same set of precompiled contracts
57-
byzantiumContracts.get(addr)
59+
byzantiumAtlantisContracts.get(addr)
5860
} else
5961
contracts.get(addr)
6062
}
6163
}
6264

6365
sealed trait PrecompiledContract {
6466
protected def exec(inputData: ByteString): Option[ByteString]
65-
protected def gas(inputData: ByteString): BigInt
67+
protected def gas(inputData: ByteString, etcFork: EtcFork, ethFork: EthFork): BigInt
6668

6769
def run[W <: WorldStateProxy[W, S], S <: Storage[S]](context: ProgramContext[W, S]): ProgramResult[W, S] = {
68-
val g = gas(context.inputData)
70+
71+
val ethFork = context.evmConfig.blockchainConfig.ethForkForBlockNumber(context.blockHeader.number)
72+
val etcFork = context.evmConfig.blockchainConfig.etcForkForBlockNumber(context.blockHeader.number)
73+
74+
val g = gas(context.inputData, etcFork, ethFork)
6975

7076
val (result, error, gasRemaining): (ByteString, Option[ProgramError], BigInt) =
7177
if (g <= context.startGas)
@@ -108,8 +114,7 @@ object PrecompiledContracts {
108114

109115
}
110116

111-
def gas(inputData: ByteString): BigInt =
112-
3000
117+
def gas(inputData: ByteString, etcFork: EtcFork, ethFork: EthFork): BigInt = 3000
113118

114119
private def hasOnlyLastByteSet(v: ByteString): Boolean =
115120
v.dropWhile(_ == 0).size == 1
@@ -119,23 +124,23 @@ object PrecompiledContracts {
119124
def exec(inputData: ByteString): Option[ByteString] =
120125
Some(sha256(inputData))
121126

122-
def gas(inputData: ByteString): BigInt =
127+
def gas(inputData: ByteString, etcFork: EtcFork, ethFork: EthFork): BigInt =
123128
60 + 12 * wordsForBytes(inputData.size)
124129
}
125130

126131
object Ripemp160 extends PrecompiledContract {
127132
def exec(inputData: ByteString): Option[ByteString] =
128133
Some(ByteUtils.padLeft(ripemd160(inputData), 32))
129134

130-
def gas(inputData: ByteString): BigInt =
135+
def gas(inputData: ByteString, etcFork: EtcFork, ethFork: EthFork): BigInt =
131136
600 + 120 * wordsForBytes(inputData.size)
132137
}
133138

134139
object Identity extends PrecompiledContract {
135140
def exec(inputData: ByteString): Option[ByteString] =
136141
Some(inputData)
137142

138-
def gas(inputData: ByteString): BigInt =
143+
def gas(inputData: ByteString, etcFork: EtcFork, ethFork: EthFork): BigInt =
139144
15 + 3 * wordsForBytes(inputData.size)
140145
}
141146

@@ -168,7 +173,7 @@ object PrecompiledContracts {
168173
Some(ByteString(ByteUtils.bigIntegerToBytes(result.bigInteger, modLength)))
169174
}
170175

171-
def gas(inputData: ByteString): BigInt = {
176+
def gas(inputData: ByteString, etcFork: EtcFork, ethFork: EthFork): BigInt = {
172177
val baseLength = getLength(inputData, 0)
173178
val expLength = getLength(inputData, 1)
174179
val modLength = getLength(inputData, 2)
@@ -256,8 +261,11 @@ object PrecompiledContracts {
256261
}
257262

258263

259-
def gas(inputData: ByteString): BigInt =
260-
BigInt(500)
264+
def gas(inputData: ByteString, etcFork: EtcFork, ethFork: EthFork): BigInt =
265+
if(etcFork >= EtcForks.Phoenix || ethFork >= EthForks.Istanbul)
266+
BigInt(150) // https://eips.ethereum.org/EIPS/eip-1108
267+
else
268+
BigInt(500)
261269

262270

263271
private def getCurvePointsBytes(input: ByteString): (ByteString, ByteString, ByteString, ByteString) = {
@@ -293,8 +301,11 @@ object PrecompiledContracts {
293301
}
294302
}
295303

296-
def gas(inputData: ByteString): BigInt =
297-
40000
304+
def gas(inputData: ByteString, etcFork: EtcFork, ethFork: EthFork): BigInt =
305+
if(etcFork >= EtcForks.Phoenix || ethFork >= EthForks.Istanbul)
306+
6000 // https://eips.ethereum.org/EIPS/eip-1108
307+
else
308+
40000
298309

299310
private def getCurvePointsBytes(input: ByteString): (ByteString, ByteString, ByteString) = {
300311
(input.slice(0, 32),
@@ -325,8 +336,13 @@ object PrecompiledContracts {
325336
}
326337
}
327338

328-
def gas(inputData: ByteString): BigInt = {
329-
80000 * (inputData.length / inputLength) + 100000
339+
def gas(inputData: ByteString, etcFork: EtcFork, ethFork: EthFork): BigInt = {
340+
val k = inputData.length / inputLength
341+
if(etcFork >= EtcForks.Phoenix || ethFork >= EthForks.Istanbul){ // https://eips.ethereum.org/EIPS/eip-1108
342+
34000 * k + 45000
343+
} else {
344+
80000 * k + 100000
345+
}
330346
}
331347

332348
// Method which stops reading another points if one of earlier ones failed (had invalid coordinates, or was not on

0 commit comments

Comments
 (0)