Skip to content
This repository has been archived by the owner on Dec 5, 2024. It is now read-only.

Make DataWord immutable #884

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ logs
test_db*
testnetSampleDb
sampleDB*
out

# Mac
.DS_Store
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,7 @@ public Source<byte[], ProgramPrecompile> precompileSource() {
new Serializer<byte[], byte[]>() {
public byte[] serialize(byte[] object) {
DataWord ret = new DataWord(object);
ret.add(new DataWord(1));
return ret.getLast20Bytes();
return ret.add(new DataWord(1)).getLast20Bytes();
}
public byte[] deserialize(byte[] stream) {
throw new RuntimeException("Shouldn't be called");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public DataWord getCallGas(OpCode op, DataWord requestedGas, DataWord availableG
if (requestedGas.compareTo(availableGas) > 0) {
throw Program.Exception.notEnoughOpGas(op, requestedGas, availableGas);
}
return requestedGas.clone();
return requestedGas;
}

@Override
Expand Down
6 changes: 1 addition & 5 deletions ethereumj-core/src/main/java/org/ethereum/util/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -230,11 +230,7 @@ public static List<ByteArrayWrapper> dumpKeys(DbSource<byte[]> ds) {
}

public static DataWord allButOne64th(DataWord dw) {
DataWord ret = dw.clone();
DataWord d = dw.clone();
d.div(DIVISOR);
ret.sub(d);
return ret;
return dw.sub(dw.div(DIVISOR));
}

/**
Expand Down
168 changes: 81 additions & 87 deletions ethereumj-core/src/main/java/org/ethereum/vm/DataWord.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
/**
* DataWord is the 32-byte array representation of a 256-bit number
* Calculations can be done on this word with other DataWords
* The data byte array is immutable
*
* @author Roman Mandeleil
* @since 01.06.2014
Expand All @@ -40,12 +41,12 @@ public class DataWord implements Comparable<DataWord> {
/* Maximum value of the DataWord */
public static final BigInteger _2_256 = BigInteger.valueOf(2).pow(256);
public static final BigInteger MAX_VALUE = _2_256.subtract(BigInteger.ONE);
public static final DataWord ZERO = new DataWord(new byte[32]); // don't push it in to the stack
public static final DataWord ZERO_EMPTY_ARRAY = new DataWord(new byte[0]); // don't push it in to the stack
public static final DataWord ZERO = new DataWord();

private byte[] data = new byte[32];
private final byte[] data;

public DataWord() {
this.data = new byte[32];
}

public DataWord(int num) {
Expand Down Expand Up @@ -73,18 +74,20 @@ public DataWord(ByteArrayWrapper wrappedData){
}

public DataWord(byte[] data) {
if (data == null)
if (data == null) {
this.data = ByteUtil.EMPTY_BYTE_ARRAY;
else if (data.length == 32)
this.data = data;
else if (data.length <= 32)
} else if (data.length == 32) {
this.data = Arrays.clone(data);
} else if (data.length <= 32) {
this.data = new byte[32];
System.arraycopy(data, 0, this.data, 32 - data.length, data.length);
}
else
throw new RuntimeException("Data word can't exceed 32 bytes: " + data);
}

public byte[] getData() {
return data;
return copyData();
}

public byte[] getNoLeadZeroesData() {
Expand Down Expand Up @@ -182,158 +185,144 @@ public boolean isNegative() {
return result == 0x80;
}

public DataWord and(DataWord w2) {
private byte[] copyData() {
return Arrays.clone(data);
}

for (int i = 0; i < this.data.length; ++i) {
this.data[i] &= w2.data[i];
public DataWord and(DataWord w2) {
byte[] data = copyData();
for (int i = 0; i < data.length; ++i) {
data[i] &= w2.data[i];
}
return this;
return new DataWord(data);
}

public DataWord or(DataWord w2) {

for (int i = 0; i < this.data.length; ++i) {
this.data[i] |= w2.data[i];
byte[] data = copyData();
for (int i = 0; i < data.length; ++i) {
data[i] |= w2.data[i];
}
return this;
return new DataWord(data);
}

public DataWord xor(DataWord w2) {

for (int i = 0; i < this.data.length; ++i) {
this.data[i] ^= w2.data[i];
byte[] data = copyData();
for (int i = 0; i < data.length; ++i) {
data[i] ^= w2.data[i];
}
return this;
return new DataWord(data);
}

public void negate() {

if (this.isZero()) return;
public DataWord negate() {
if (this.isZero()) {
return this;
}

for (int i = 0; i < this.data.length; ++i) {
this.data[i] = (byte) ~this.data[i];
byte[] data = copyData();
for (int i = 0; i < data.length; ++i) {
data[i] = (byte) ~ data[i];
}

for (int i = this.data.length - 1; i >= 0; --i) {
this.data[i] = (byte) (1 + this.data[i] & 0xFF);
if (this.data[i] != 0) break;
for (int i = data.length - 1; i >= 0; --i) {
data[i] = (byte) (1 + data[i] & 0xFF);
if (data[i] != 0) {
break;
}
}
return new DataWord(data);
}

public void bnot() {
public DataWord bnot() {
if (this.isZero()) {
this.data = ByteUtil.copyToArray(MAX_VALUE);
return;
return new DataWord(ByteUtil.copyToArray(MAX_VALUE));
}
this.data = ByteUtil.copyToArray(MAX_VALUE.subtract(this.value()));
return new DataWord(ByteUtil.copyToArray(MAX_VALUE.subtract(this.value())));
}

// By : Holger
// From : http://stackoverflow.com/a/24023466/459349
public void add(DataWord word) {
public DataWord add(DataWord word) {
byte[] result = new byte[32];
for (int i = 31, overflow = 0; i >= 0; i--) {
int v = (this.data[i] & 0xff) + (word.data[i] & 0xff) + overflow;
result[i] = (byte) v;
overflow = v >>> 8;
}
this.data = result;
}

// old add-method with BigInteger quick hack
public void add2(DataWord word) {
BigInteger result = value().add(word.value());
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
return new DataWord(result);
}

// TODO: mul can be done in more efficient way
// TODO: with shift left shift right trick
// TODO without BigInteger quick hack
public void mul(DataWord word) {
public DataWord mul(DataWord word) {
BigInteger result = value().multiply(word.value());
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
return new DataWord(ByteUtil.copyToArray(result.and(MAX_VALUE)));
}

// TODO: improve with no BigInteger
public void div(DataWord word) {

public DataWord div(DataWord word) {
if (word.isZero()) {
this.and(ZERO);
return;
return ZERO;
}

BigInteger result = value().divide(word.value());
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
return new DataWord(ByteUtil.copyToArray(result.and(MAX_VALUE)));
}

// TODO: improve with no BigInteger
public void sDiv(DataWord word) {

public DataWord sDiv(DataWord word) {
if (word.isZero()) {
this.and(ZERO);
return;
return ZERO;
}

BigInteger result = sValue().divide(word.sValue());
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
return new DataWord(ByteUtil.copyToArray(result.and(MAX_VALUE)));
}

// TODO: improve with no BigInteger
public void sub(DataWord word) {
public DataWord sub(DataWord word) {
BigInteger result = value().subtract(word.value());
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
byte[] data = ByteUtil.copyToArray(result.and(MAX_VALUE));
return new DataWord(data);
}

// TODO: improve with no BigInteger
public void exp(DataWord word) {
public DataWord exp(DataWord word) {
BigInteger result = value().modPow(word.value(), _2_256);
this.data = ByteUtil.copyToArray(result);
return new DataWord(ByteUtil.copyToArray(result));
}

// TODO: improve with no BigInteger
public void mod(DataWord word) {

public DataWord mod(DataWord word) {
if (word.isZero()) {
this.and(ZERO);
return;
return ZERO;
}

BigInteger result = value().mod(word.value());
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
return new DataWord(ByteUtil.copyToArray(result.and(MAX_VALUE)));
}

public void sMod(DataWord word) {

public DataWord sMod(DataWord word) {
if (word.isZero()) {
this.and(ZERO);
return;
return ZERO;
}

BigInteger result = sValue().abs().mod(word.sValue().abs());
result = (sValue().signum() == -1) ? result.negate() : result;

this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
return new DataWord(ByteUtil.copyToArray(result.and(MAX_VALUE)));
}

public void addmod(DataWord word1, DataWord word2) {
public DataWord addmod(DataWord word1, DataWord word2) {
if (word2.isZero()) {
this.data = new byte[32];
return;
return ZERO;
}

BigInteger result = value().add(word1.value()).mod(word2.value());
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
return new DataWord(ByteUtil.copyToArray(result.and(MAX_VALUE)));
}

public void mulmod(DataWord word1, DataWord word2) {

public DataWord mulmod(DataWord word1, DataWord word2) {
if (this.isZero() || word1.isZero() || word2.isZero()) {
this.data = new byte[32];
return;
return ZERO;
}

BigInteger result = value().multiply(word1.value()).mod(word2.value());
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
return new DataWord(ByteUtil.copyToArray(result.and(MAX_VALUE)));
}

@JsonValue
Expand All @@ -358,10 +347,6 @@ public String shortHex() {
return "0x" + hexValue.replaceFirst("^0+(?!$)", "");
}

public DataWord clone() {
return new DataWord(Arrays.clone(data));
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand All @@ -388,13 +373,15 @@ public int compareTo(DataWord o) {
return (int) Math.signum(result);
}

public void signExtend(byte k) {
public DataWord signExtend(byte k) {
if (0 > k || k > 31)
throw new IndexOutOfBoundsException();
byte mask = this.sValue().testBit((k * 8) + 7) ? (byte) 0xff : 0;
byte[] data = copyData();
for (int i = 31; i > k; i--) {
this.data[31 - i] = mask;
data[31 - i] = mask;
}
return new DataWord(data);
}

public int bytesOccupied() {
Expand All @@ -410,4 +397,11 @@ public boolean isHex(String hex) {
public String asString(){
return new String(getNoLeadZeroesData());
}

public DataWord withByte(byte b, int i) {
byte[] data = copyData();
data[i] = b;
return new DataWord(data);
}

}
Loading