Skip to content

Commit 03daea8

Browse files
strauss-mAurélien Richez
andauthored
[ETCM-1166] Pass ETS GeneralStateTests for Berlin (#1120)
* Adds accessed address even in case of failure * Adds accessed address and storage in call result * Fix refund calculation * avoid adding access list after an error * update ets tests to 8.0.5 (latest for Berlin) * add created contract to accessedAddress list * activate Berlin tests * [ETCM-1166] Fix AccessedStorageKeys for CREATE/CREATE2 opcodes * [ETCM-1166] Add gasUsed data in executed Opcodes logs * Add accessed address in create only if the call is not invalid * formatAll Co-authored-by: Aurélien Richez <[email protected]>
1 parent 8873d39 commit 03daea8

File tree

10 files changed

+62
-21
lines changed

10 files changed

+62
-21
lines changed

ets/config/mantis/config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"Constantinople",
1515
"ConstantinopleFix",
1616
"Istanbul",
17+
"Berlin",
1718
"London"
1819
],
1920
"additionalForks" : [

ets/tests

Submodule tests updated 1893 files

src/main/scala/io/iohk/ethereum/extvm/VMClient.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,10 @@ class VMClient(externalVmConfig: VmConfig.ExternalConfig, messageHandler: Messag
113113
resultMsg.logs.map(l => TxLogEntry(l.address, l.topics.map(t => t: ByteString), l.data)),
114114
Nil,
115115
resultMsg.gasRefund,
116-
if (resultMsg.error) Some(OutOfGas) else None
116+
if (resultMsg.error) Some(OutOfGas) else None,
117+
// FIXME handle accessed addresses and storage in extVM
118+
Set.empty,
119+
Set.empty
117120
)
118121
}
119122

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

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -712,7 +712,7 @@ case object SSTORE extends OpCode(0x55, 2, 0, _.G_zero) {
712712

713713
val reset = if (originalValue == newValue.toBigInt) {
714714
if (UInt256(originalValue).isZero)
715-
state.config.feeSchedule.R_sclear + state.config.feeSchedule.G_sreset - state.config.feeSchedule.G_sload
715+
state.config.feeSchedule.G_sset - state.config.feeSchedule.G_sload
716716
else
717717
state.config.feeSchedule.G_sreset - state.config.feeSchedule.G_sload
718718
} else BigInt(0)
@@ -986,16 +986,16 @@ abstract class CreateOp(code: Int, delta: Int) extends OpCode(code, delta, 1, _.
986986
}
987987

988988
result.error match {
989-
case Some(err) =>
990-
val world2 = if (err == InvalidCall) state.world else world1
989+
case Some(error) =>
990+
val world2 = if (error == InvalidCall) state.world else world1
991991
val resultStack = stack2.push(UInt256.Zero)
992-
val returnData = if (err == RevertOccurs) result.returnData else ByteString.empty
992+
val returnData = if (error == RevertOccurs) result.returnData else ByteString.empty
993993
state
994994
.spendGas(startGas - result.gasRemaining)
995995
.withWorld(world2)
996996
.withStack(resultStack)
997997
.withReturnData(returnData)
998-
.addAccessedAddress(newAddress)
998+
.addAccessedAddresses(if (error == InvalidCall) Set.empty else Set(newAddress))
999999
.step()
10001000

10011001
case None =>
@@ -1013,7 +1013,8 @@ abstract class CreateOp(code: Int, delta: Int) extends OpCode(code, delta, 1, _.
10131013
.withMemory(memory1)
10141014
.withInternalTxs(internalTx +: result.internalTxs)
10151015
.withReturnData(ByteString.empty)
1016-
.addAccessedAddress(newAddress)
1016+
.addAccessedStorageKeys(result.accessedStorageKeys)
1017+
.addAccessedAddresses(result.accessedAddresses + newAddress)
10171018
.step()
10181019
}
10191020
}
@@ -1106,6 +1107,7 @@ abstract class CallOp(code: Int, delta: Int, alpha: Int) extends OpCode(code, de
11061107
.withWorld(world1)
11071108
.spendGas(gasAdjustment)
11081109
.withReturnData(result.returnData)
1110+
.addAccessedAddress(toAddr)
11091111
.step()
11101112

11111113
case None =>
@@ -1122,7 +1124,8 @@ abstract class CallOp(code: Int, delta: Int, alpha: Int) extends OpCode(code, de
11221124
.withInternalTxs(internalTx +: result.internalTxs)
11231125
.withLogs(result.logs)
11241126
.withReturnData(result.returnData)
1125-
.addAccessedAddress(toAddr)
1127+
.addAccessedStorageKeys(result.accessedStorageKeys)
1128+
.addAccessedAddresses(result.accessedAddresses + toAddr)
11261129
.step()
11271130
}
11281131
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ object PrecompiledContracts {
107107
Nil,
108108
Nil,
109109
0,
110-
error
110+
error,
111+
Set.empty,
112+
Set.empty
111113
)
112114
}
113115
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,7 @@ case class ProgramResult[W <: WorldStateProxy[W, S], S <: Storage[S]](
2222
logs: Seq[TxLogEntry],
2323
internalTxs: Seq[InternalTransaction],
2424
gasRefund: BigInt,
25-
error: Option[ProgramError]
25+
error: Option[ProgramError],
26+
accessedAddresses: Set[Address],
27+
accessedStorageKeys: Set[(Address, BigInt)]
2628
)

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,12 @@ case class ProgramState[W <: WorldStateProxy[W, S], S <: Storage[S]](
142142
def addAccessedStorageKey(addr: Address, storageKey: BigInt): ProgramState[W, S] =
143143
copy(accessedStorageKeys = accessedStorageKeys + ((addr, storageKey)))
144144

145+
def addAccessedAddresses(addresses: Set[Address]): ProgramState[W, S] =
146+
copy(accessedAddresses = accessedAddresses ++ addresses)
147+
148+
def addAccessedStorageKeys(storageKeys: Set[(Address, BigInt)]): ProgramState[W, S] =
149+
copy(accessedStorageKeys = accessedStorageKeys ++ storageKeys)
150+
145151
def toResult: ProgramResult[W, S] =
146152
ProgramResult[W, S](
147153
returnData,
@@ -151,6 +157,8 @@ case class ProgramState[W <: WorldStateProxy[W, S], S <: Storage[S]](
151157
logs,
152158
internalTxs,
153159
gasRefund,
154-
error
160+
error,
161+
accessedAddresses,
162+
accessedStorageKeys
155163
)
156164
}

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

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class VM[W <: WorldStateProxy[W, S], S <: Storage[S]] extends Logger {
4242
*/
4343
private[vm] def call(context: PC, ownerAddr: Address): PR =
4444
if (!isValidCall(context))
45-
invalidCallResult(context)
45+
invalidCallResult(context, Set.empty, Set.empty)
4646
else {
4747
require(context.recipientAddr.isDefined, "Recipient address must be defined for message call")
4848

@@ -69,7 +69,7 @@ class VM[W <: WorldStateProxy[W, S], S <: Storage[S]] extends Logger {
6969
salt: Option[UInt256] = None
7070
): (PR, Address) =
7171
if (!isValidCall(context))
72-
(invalidCallResult(context), Address(0))
72+
(invalidCallResult(context, Set.empty, Set.empty), Address(0))
7373
else {
7474
require(context.recipientAddr.isEmpty, "recipient address must be empty for contract creation")
7575
require(context.doTransfer, "contract creation will alwyas transfer funds")
@@ -96,15 +96,16 @@ class VM[W <: WorldStateProxy[W, S], S <: Storage[S]] extends Logger {
9696
*/
9797
val originInitialisedAccount = context.originalWorld.initialiseAccount(newAddress)
9898

99-
val world1 =
99+
val world1: W =
100100
context.world.initialiseAccount(newAddress).transfer(context.callerAddr, newAddress, context.endowment)
101101

102102
val code = if (conflict) ByteString(INVALID.code) else context.inputData
103103

104104
val env = ExecEnv(context, code, newAddress).copy(inputData = ByteString.empty)
105105

106106
val initialState: PS =
107-
ProgramState(this, context.copy(world = world1, originalWorld = originInitialisedAccount), env)
107+
ProgramState(this, context.copy(world = world1, originalWorld = originInitialisedAccount): PC, env)
108+
.addAccessedAddress(newAddress)
108109

109110
val execResult = exec(initialState).toResult
110111

@@ -119,7 +120,9 @@ class VM[W <: WorldStateProxy[W, S], S <: Storage[S]] extends Logger {
119120
case Some(opCode) =>
120121
val newState = opCode.execute(state)
121122
import newState._
122-
log.trace(s"$opCode | pc: $pc | depth: ${env.callDepth} | gas: $gas | stack: $stack")
123+
log.trace(
124+
s"$opCode | pc: $pc | depth: ${env.callDepth} | gasUsed: ${state.gas - gas} | gas: $gas | stack: $stack"
125+
)
123126
if (newState.halted)
124127
newState
125128
else
@@ -134,8 +137,23 @@ class VM[W <: WorldStateProxy[W, S], S <: Storage[S]] extends Logger {
134137
context.endowment <= context.world.getBalance(context.callerAddr) &&
135138
context.callDepth <= EvmConfig.MaxCallDepth
136139

137-
private def invalidCallResult(context: PC): PR =
138-
ProgramResult(ByteString.empty, context.startGas, context.world, Set(), Nil, Nil, 0, Some(InvalidCall))
140+
private def invalidCallResult(
141+
context: PC,
142+
accessedAddresses: Set[Address],
143+
accessedStorageKeys: Set[(Address, BigInt)]
144+
): PR =
145+
ProgramResult(
146+
ByteString.empty,
147+
context.startGas,
148+
context.world,
149+
Set(),
150+
Nil,
151+
Nil,
152+
0,
153+
Some(InvalidCall),
154+
accessedAddresses,
155+
accessedStorageKeys
156+
)
139157

140158
private def exceedsMaxContractSize(context: PC, config: EvmConfig, contractCode: ByteString): Boolean = {
141159
lazy val maxCodeSizeExceeded = config.maxCodeSize.exists(codeSizeLimit => contractCode.size > codeSizeLimit)

src/test/scala/io/iohk/ethereum/Mocks.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ object Mocks {
3636
logs = Nil,
3737
internalTxs = Nil,
3838
gasRefund = 20000,
39-
error = None
39+
error = None,
40+
Set.empty,
41+
Set.empty
4042
)
4143

4244
class MockVM(runFn: PC => PR = defaultProgramResult) extends VMImpl {

src/test/scala/io/iohk/ethereum/ledger/LedgerTestSetup.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,9 @@ trait TestSetup extends SecureRandomBuilder with EphemBlockchainTestSetup {
141141
logs = logs,
142142
internalTxs = Nil,
143143
gasRefund = gasRefund,
144-
error = error
144+
error = error,
145+
Set.empty,
146+
Set.empty
145147
)
146148

147149
sealed trait Changes

0 commit comments

Comments
 (0)