Skip to content

Commit

Permalink
perf: add write versioning check; add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Vovchyk committed Oct 10, 2024
1 parent e1d6fd4 commit ff944f2
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 7 deletions.
21 changes: 18 additions & 3 deletions rskj-core/src/main/java/org/ethereum/vm/program/Memory.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ public class Memory implements ProgramListenerAware {
private static final int WORD_SIZE = 32;

private final List<byte[]> chunks = new LinkedList<>();

private int softSize;
private int version; // versioning for memory changes

private ProgramListener traceListener;

@Override
Expand All @@ -54,7 +57,7 @@ public BytesSlice readSlice(int address, int size) {

extend(address, size);

return new MemorySlice(address, size);
return new MemorySlice(address, size, version);
}

public byte[] read(int address, int size) {
Expand Down Expand Up @@ -87,6 +90,8 @@ public byte[] read(int address, int size) {
}

public void write(int address, byte[] data, int dataSize, boolean limited) {
version++;

if (data.length < dataSize) {
dataSize = data.length;
}
Expand Down Expand Up @@ -123,7 +128,6 @@ public void write(int address, byte[] data, int dataSize, boolean limited) {
}
}


public void extendAndWrite(int address, int allocSize, byte[] data) {
extend(address, allocSize);
write(address, data, data.length, false);
Expand Down Expand Up @@ -239,15 +243,18 @@ private void addChunks(int num) {
private final class MemorySlice implements BytesSlice {
private final int address;
private final int size;
private final int memVersion;

MemorySlice(int address, int size) {
MemorySlice(int address, int size, int memVersion) {
this.address = address;
this.size = size;
this.memVersion = memVersion;
}

@Override
public void arraycopy(int srcPos, byte[] dest, int destPos, int length) {
BoundaryUtils.checkArraycopyParams(length(), srcPos, dest, destPos, length);
checkVersion();

int chunkIndex = (address + srcPos) / CHUNK_SIZE;
int chunkOffset = (address + srcPos) % CHUNK_SIZE;
Expand Down Expand Up @@ -276,7 +283,15 @@ public int length() {
@Override
public byte byteAt(int index) {
BoundaryUtils.checkArrayIndexParam(length(), index);
checkVersion();

return readByte(address + index);
}

private void checkVersion() {
if (this.memVersion != Memory.this.version) {
throw new IllegalStateException("Memory was changed during slice lifetime");
}
}
}
}
35 changes: 31 additions & 4 deletions rskj-core/src/test/java/org/ethereum/vm/MemoryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,15 @@

package org.ethereum.vm;

import co.rsk.core.types.bytes.BytesSlice;
import org.bouncycastle.util.encoders.Hex;
import org.ethereum.vm.program.Memory;
import org.junit.jupiter.api.Test;
import org.bouncycastle.util.encoders.Hex;

import java.util.Arrays;

import static java.lang.Math.ceil;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.*;

class MemoryTest {

Expand Down Expand Up @@ -530,6 +529,34 @@ void memoryWriteLimited_3(){
assertEquals(10, zero);
}

@Test
void memorySliceMatchesWithWritten() {
Memory memory = new Memory();
memory.write(0, new byte[]{1, 2, 3, 4}, 4, false);
BytesSlice memSlice = memory.readSlice(0, 4);

assertArrayEquals(new byte[]{1, 2, 3, 4}, memSlice.copyArray());
assertArrayEquals(memory.read(0, 4), memSlice.copyArray());
}

@Test
void memorySliceMatchesWithWrittenAndExpansion() {
Memory memory = new Memory();
memory.write(0, new byte[]{1, 2, 3, 4}, 4, false);
BytesSlice memSlice = memory.readSlice(0, 8);

assertArrayEquals(new byte[]{1, 2, 3, 4, 0, 0, 0, 0}, memSlice.copyArray());
assertArrayEquals(memory.read(0, 8), memSlice.copyArray());
}

@Test
void memoryWriteInvalidatesSlice() {
Memory memory = new Memory();
memory.write(0, new byte[]{1, 2, 3, 4}, 4, false);
BytesSlice memSlice = memory.readSlice(0, 4);
memory.write(0, new byte[]{4, 3, 2, 1}, 4, false);

assertThrows(IllegalStateException.class, () -> memSlice.byteAt(0), "Memory was changed during slice lifetime");
assertThrows(IllegalStateException.class, () -> memSlice.arraycopy(0, new byte[4], 0, 4), "Memory was changed during slice lifetime");
}
}

0 comments on commit ff944f2

Please sign in to comment.