Skip to content

Commit 1d34d64

Browse files
julia-zackmarcos-iov
authored andcommitted
Keep isPositiveN method to check whether a chunk is a positive n. Create castToBigInteger in ScriptChunk class to avoid circular dependency with Script class
1 parent 6b87b92 commit 1d34d64

File tree

4 files changed

+41
-16
lines changed

4 files changed

+41
-16
lines changed

src/main/java/co/rsk/bitcoinj/script/RedeemScriptValidator.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,12 @@ protected static boolean hasStandardRedeemScriptStructure(List<ScriptChunk> chun
4646
// Second to last chunk must be a number for the keys
4747
int secondToLastChunkIndex = chunksSize - 2;
4848
ScriptChunk secondToLastChunk = chunks.get(secondToLastChunkIndex);
49-
int numKeys;
5049

51-
try {
52-
firstChunk.decodePositiveN();
53-
numKeys = secondToLastChunk.decodePositiveN();
54-
} catch (IllegalArgumentException e) {
50+
if (!(firstChunk.isPositiveN() && secondToLastChunk.isPositiveN())) {
5551
return false;
5652
}
5753

54+
int numKeys = secondToLastChunk.decodePositiveN();
5855
// and there should be as many data chunks as keys
5956
if (numKeys < 1 || chunksSize != numKeys + 3) { // numKeys + M + N + OP_CHECKMULTISIG
6057
return false;

src/main/java/co/rsk/bitcoinj/script/Script.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -774,7 +774,7 @@ private static boolean castToBool(byte[] data) {
774774
* sizes.
775775
* @throws ScriptException if the chunk is longer than 4 bytes.
776776
*/
777-
public static BigInteger castToBigInteger(byte[] chunk) throws ScriptException {
777+
private static BigInteger castToBigInteger(byte[] chunk) throws ScriptException {
778778
if (chunk.length > 4)
779779
throw new ScriptException("Script attempted to use an integer larger than 4 bytes");
780780
return Utils.decodeMPI(Utils.reverseBytes(chunk), false);

src/main/java/co/rsk/bitcoinj/script/ScriptChunk.java

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
1818
package co.rsk.bitcoinj.script;
1919

2020
import static co.rsk.bitcoinj.script.ScriptOpCodes.*;
21-
import static com.google.common.base.Preconditions.checkNotNull;
2221
import static com.google.common.base.Preconditions.checkState;
22+
import static java.util.Objects.isNull;
2323

24+
import co.rsk.bitcoinj.core.ScriptException;
2425
import co.rsk.bitcoinj.core.Utils;
2526
import com.google.common.base.Objects;
2627
import java.io.IOException;
2728
import java.io.OutputStream;
29+
import java.math.BigInteger;
2830
import java.util.Arrays;
2931
import javax.annotation.Nullable;
3032

@@ -145,6 +147,15 @@ public void write(OutputStream stream) throws IOException {
145147
}
146148
}
147149

150+
public boolean isPositiveN() {
151+
try {
152+
decodePositiveN();
153+
return true;
154+
} catch(IllegalArgumentException | ScriptException e) {
155+
return false;
156+
}
157+
}
158+
148159
public int decodePositiveN() {
149160
if (isOpcodeSmallNumber()) {
150161
return decodeOpN();
@@ -169,7 +180,9 @@ public boolean isOpCheckMultiSig() {
169180
}
170181

171182
private int decodePositiveNConsideringEncoding() {
172-
checkNotNull(data);
183+
if (isNull(data)) {
184+
throw new IllegalArgumentException("Chunk has null data.");
185+
}
173186
int dataLength = data.length;
174187

175188
int signByte = data[dataLength - 1] & 0x80;
@@ -178,10 +191,14 @@ private int decodePositiveNConsideringEncoding() {
178191
throw new IllegalArgumentException("Number from chunk is not positive.");
179192
}
180193

181-
if (dataLength == 1) {
182-
return data[0];
183-
}
184-
return Script.castToBigInteger(data).intValue(); // values down to Integer.MIN_VALUE and up to Integer.MAX_VALUE can be cast as ints
194+
return castToBigInteger(data).intValue(); // values up to Integer.MAX_VALUE can be cast as ints
195+
}
196+
197+
// copied implementation from Script.castToBigInteger to avoid circular dependency
198+
private static BigInteger castToBigInteger(byte[] chunk) throws ScriptException {
199+
if (chunk.length > 4)
200+
throw new ScriptException("Script attempted to use an integer larger than 4 bytes");
201+
return Utils.decodeMPI(Utils.reverseBytes(chunk), false);
185202
}
186203

187204
@Override

src/test/java/co/rsk/bitcoinj/script/ScriptChunkTest.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ public void decodePositiveN_withPositiveSmallNumber_returnsExpectedNumber() {
144144
Script script = builder.build();
145145

146146
ScriptChunk chunk = script.chunks.get(0);
147+
assertTrue(chunk.isPositiveN());
147148
assertEquals(i, chunk.decodePositiveN());
148149
}
149150
}
@@ -157,6 +158,7 @@ public void decodePositiveN_withPositiveNumber_returnsExpectedNumber() {
157158
Script script = builder.build();
158159

159160
ScriptChunk chunk = script.chunks.get(0);
161+
assertTrue(chunk.isPositiveN());
160162
assertEquals(i, chunk.decodePositiveN());
161163
}
162164
}
@@ -169,7 +171,8 @@ public void decodePositiveN_forZero_throwsNPE() {
169171
Script script = builder.build();
170172

171173
ScriptChunk chunk = script.chunks.get(0);
172-
assertThrows(NullPointerException.class, chunk::decodePositiveN);
174+
assertFalse(chunk.isPositiveN());
175+
assertThrows(IllegalArgumentException.class, chunk::decodePositiveN);
173176
}
174177

175178
@Test
@@ -181,34 +184,42 @@ public void decodePositiveN_withNegativeNumber_throwsIAE() {
181184
Script script = builder.build();
182185

183186
ScriptChunk chunk = script.chunks.get(0);
187+
assertFalse(chunk.isPositiveN());
184188
assertThrows(IllegalArgumentException.class, chunk::decodePositiveN);
185189
}
186190
}
187191

188192
@Test
189193
public void decodePositiveN_withNullPushData_throwsNPE() {
190194
ScriptChunk chunk = new ScriptChunk(OP_PUSHDATA1, null);
191-
assertThrows(NullPointerException.class, chunk::decodePositiveN);
195+
assertFalse(chunk.isPositiveN());
196+
assertThrows(IllegalArgumentException.class, chunk::decodePositiveN);
192197

193198
chunk = new ScriptChunk(OP_PUSHDATA2, null);
194-
assertThrows(NullPointerException.class, chunk::decodePositiveN);
199+
assertFalse(chunk.isPositiveN());
200+
assertThrows(IllegalArgumentException.class, chunk::decodePositiveN);
195201

196202
chunk = new ScriptChunk(OP_PUSHDATA4, null);
197-
assertThrows(NullPointerException.class, chunk::decodePositiveN);
203+
assertFalse(chunk.isPositiveN());
204+
assertThrows(IllegalArgumentException.class, chunk::decodePositiveN);
198205
}
199206

200207
@Test
201208
public void decodePositiveN_withWrongOpcodes_throwsIAE() {
202209
ScriptChunk chunk = new ScriptChunk(ScriptOpCodes.OP_CHECKMULTISIG, null);
210+
assertFalse(chunk.isPositiveN());
203211
assertThrows(IllegalArgumentException.class, chunk::decodePositiveN);
204212

205213
chunk = new ScriptChunk(ScriptOpCodes.OP_CHECKSIG, null);
214+
assertFalse(chunk.isPositiveN());
206215
assertThrows(IllegalArgumentException.class, chunk::decodePositiveN);
207216

208217
chunk = new ScriptChunk(ScriptOpCodes.OP_RETURN, null);
218+
assertFalse(chunk.isPositiveN());
209219
assertThrows(IllegalArgumentException.class, chunk::decodePositiveN);
210220

211221
chunk = new ScriptChunk(ScriptOpCodes.OP_DROP, null);
222+
assertFalse(chunk.isPositiveN());
212223
assertThrows(IllegalArgumentException.class, chunk::decodePositiveN);
213224
}
214225
}

0 commit comments

Comments
 (0)