Skip to content

Commit e14cefd

Browse files
committed
Merge remote-tracking branch 'origin/phase/3/txExecution' into fix/ECDSASignature
2 parents 58f57f4 + 737abbd commit e14cefd

File tree

2 files changed

+56
-11
lines changed

2 files changed

+56
-11
lines changed

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

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,11 @@ object OpCodes {
163163
}
164164

165165
object OpCode {
166-
def sliceBytes(bytes: ByteString, offset: Int, size: Int): ByteString =
167-
bytes.slice(offset, offset + size).padTo(size, 0.toByte)
166+
def sliceBytes(bytes: ByteString, offset: UInt256, size: UInt256): ByteString = {
167+
val start = offset.min(bytes.size).toInt
168+
val end = (offset + size).min(bytes.size).toInt
169+
bytes.slice(start, end).padTo(size.toInt, 0.toByte)
170+
}
168171
}
169172

170173
/**
@@ -338,7 +341,7 @@ case object CALLVALUE extends ConstOp(0x34)(_.env.value)
338341
case object CALLDATALOAD extends OpCode(0x35, 1, 1, _.G_verylow) with ConstGas {
339342
protected def exec[W <: WorldStateProxy[W, S], S <: Storage[S]](state: ProgramState[W, S]): ProgramState[W, S] = {
340343
val (offset, stack1) = state.stack.pop
341-
val data = OpCode.sliceBytes(state.inputData, offset.toInt, 32)
344+
val data = OpCode.sliceBytes(state.inputData, offset, 32)
342345
val stack2 = stack1.push(UInt256(data))
343346
state.withStack(stack2).step()
344347
}
@@ -349,7 +352,7 @@ case object CALLDATASIZE extends ConstOp(0x36)(_.inputData.size)
349352
case object CALLDATACOPY extends OpCode(0x37, 3, 0, _.G_verylow) {
350353
protected def exec[W <: WorldStateProxy[W, S], S <: Storage[S]](state: ProgramState[W, S]): ProgramState[W, S] = {
351354
val (Seq(memOffset, dataOffset, size), stack1) = state.stack.pop(3)
352-
val data = OpCode.sliceBytes(state.inputData, dataOffset.toInt, size.toInt)
355+
val data = OpCode.sliceBytes(state.inputData, dataOffset, size)
353356
val mem1 = state.memory.store(memOffset, data)
354357
state.withStack(stack1).withMemory(mem1).step()
355358
}
@@ -367,7 +370,7 @@ case object CODESIZE extends ConstOp(0x38)(_.env.program.length)
367370
case object CODECOPY extends OpCode(0x39, 3, 0, _.G_verylow) {
368371
protected def exec[W <: WorldStateProxy[W, S], S <: Storage[S]](state: ProgramState[W, S]): ProgramState[W, S] = {
369372
val (Seq(memOffset, codeOffset, size), stack1) = state.stack.pop(3)
370-
val bytes = state.program.getBytes(codeOffset.toInt, size.toInt)
373+
val bytes = OpCode.sliceBytes(state.program.code, codeOffset, size)
371374
val mem1 = state.memory.store(memOffset, bytes)
372375
state.withStack(stack1).withMemory(mem1).step()
373376
}
@@ -394,7 +397,7 @@ case object EXTCODESIZE extends OpCode(0x3b, 1, 1, _.G_extcode) with ConstGas {
394397
case object EXTCODECOPY extends OpCode(0x3c, 4, 0, _.G_extcode) {
395398
protected def exec[W <: WorldStateProxy[W, S], S <: Storage[S]](state: ProgramState[W, S]): ProgramState[W, S] = {
396399
val (Seq(address, memOffset, codeOffset, size), stack1) = state.stack.pop(4)
397-
val codeCopy = OpCode.sliceBytes(state.world.getCode(Address(address)), codeOffset.toInt, size.toInt)
400+
val codeCopy = OpCode.sliceBytes(state.world.getCode(Address(address)), codeOffset, size)
398401
val mem1 = state.memory.store(memOffset, codeCopy)
399402
state.withStack(stack1).withMemory(mem1).step()
400403
}
@@ -798,7 +801,8 @@ sealed abstract class CallOp(code: Int, delta: Int, alpha: Int) extends OpCode(c
798801

799802
} else {
800803
val stack2 = stack1.push(UInt256.One)
801-
val output = result.returnData.take(outSize.toInt)
804+
val sizeCap = outSize.min(result.returnData.size).toInt
805+
val output = result.returnData.take(sizeCap)
802806
val mem2 = mem1.store(outOffset, output).expand(outOffset, outSize)
803807

804808
state

src/test/scala/io/iohk/ethereum/vm/OpCodeFunSpec.scala

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ class OpCodeFunSpec extends FunSuite with OpCodeTesting with Matchers with Prope
183183
withStackVerification(op, stateIn, stateOut) {
184184
val (offset, _) = stateIn.stack.pop
185185
val (data, _) = stateOut.stack.pop
186-
data shouldEqual UInt256(OpCode.sliceBytes(stateIn.inputData, offset.toInt, 32))
186+
data shouldEqual UInt256(OpCode.sliceBytes(stateIn.inputData, offset, 32))
187187

188188
val expectedState = stateIn.withStack(stateOut.stack).step()
189189
stateOut shouldEqual expectedState
@@ -203,7 +203,7 @@ class OpCodeFunSpec extends FunSuite with OpCodeTesting with Matchers with Prope
203203

204204
withStackVerification(op, stateIn, stateOut) {
205205
val (Seq(memOffset, dataOffset, size), _) = stateIn.stack.pop(3)
206-
val data = OpCode.sliceBytes(stateIn.inputData, dataOffset.toInt, size.toInt)
206+
val data = OpCode.sliceBytes(stateIn.inputData, dataOffset, size)
207207
val (storedInMem, _) = stateOut.memory.load(memOffset, size)
208208
data shouldEqual storedInMem
209209

@@ -225,7 +225,7 @@ class OpCodeFunSpec extends FunSuite with OpCodeTesting with Matchers with Prope
225225

226226
withStackVerification(op, stateIn, stateOut) {
227227
val (Seq(memOffset, codeOffset, size), _) = stateIn.stack.pop(3)
228-
val code = stateIn.program.getBytes(codeOffset.toInt, size.toInt)
228+
val code = OpCode.sliceBytes(stateIn.program.code, codeOffset, size)
229229
val (storedInMem, _) = stateOut.memory.load(memOffset, size)
230230
code shouldEqual storedInMem
231231

@@ -284,7 +284,7 @@ class OpCodeFunSpec extends FunSuite with OpCodeTesting with Matchers with Prope
284284

285285
withStackVerification(op, stateIn, stateOut) {
286286
val (Seq(addr, memOffset, codeOffset, size), _) = stateIn.stack.pop(4)
287-
val code = OpCode.sliceBytes(stateIn.world.getCode(Address(addr)), codeOffset.toInt, size.toInt)
287+
val code = OpCode.sliceBytes(stateIn.world.getCode(Address(addr)), codeOffset, size)
288288
val (storedInMem, _) = stateOut.memory.load(memOffset, size)
289289
code shouldEqual storedInMem
290290

@@ -670,5 +670,46 @@ class OpCodeFunSpec extends FunSuite with OpCodeTesting with Matchers with Prope
670670

671671
verifyAllOpCodesRegistered(except = CREATE, CALL, CALLCODE, DELEGATECALL)
672672

673+
test("sliceBytes helper") {
674+
def zeroes(i: Int): ByteString =
675+
ByteString(Array.fill[Byte](i)(0))
676+
677+
val table = Table[Int, UInt256, UInt256, Int, ByteString => ByteString](
678+
("dataSize", "sliceOffset", "sliceSize", "expectedSize", "expectedContentFn"),
679+
680+
// both offset and size are greater than data size
681+
(0, 16, 32, 32, _ => zeroes(32)),
682+
683+
// offset is within bounds, offset + size is greater than data size
684+
(20, 16, 32, 32, bs => bs.drop(16) ++ zeroes(28)),
685+
686+
// offset + size are within bounds
687+
(64, 16, 31, 31, bs => bs.slice(16, 47)),
688+
689+
// offset is greater than Int.MaxValue
690+
(64, Two ** 128, 32, 32, _ => zeroes(32)),
691+
692+
// offset is within bounds, size is greater than Int.MaxValue
693+
(64, 16, Two ** 64 + 7, 48, bs => bs.drop(16)),
694+
695+
// offset is within bounds, size is greater than Int.MaxValue and size.toInt > dataSize
696+
// this case a bit strange because we purposefully let size overflow when converting to Int
697+
// but sliceBytes is supposed to copy the behaviour of geth:
698+
// https://github.com/ethereum/go-ethereum/blob/5f7826270c9e87509fd7731ec64953a5e4761de0/core/vm/common.go#L42
699+
(64, 40, Two ** 64 + 124, 124, bs => bs.drop(40) ++ zeroes(100)),
700+
701+
// both offset and size are greater than Int.MaxValue
702+
(64, Two ** 33, Two ** 96 + 13, 13, _ => zeroes(13))
703+
)
704+
705+
forAll(table) { (dataSize, sliceOffset, sliceSize, expectedSize, expectedContentFn) =>
706+
val bytes = getByteStringGen(dataSize, dataSize).sample.get
707+
val slice = OpCode.sliceBytes(bytes, sliceOffset, sliceSize)
708+
709+
slice.size shouldEqual expectedSize
710+
slice shouldEqual expectedContentFn(bytes)
711+
}
712+
}
713+
673714
}
674715

0 commit comments

Comments
 (0)