Commit c3362447 authored by Daniel Connolly's avatar Daniel Connolly

Merge ilozanof updates

parents 211c5fa7 d4f474db
......@@ -2,6 +2,7 @@
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
* Copyright 2014-2016 the libsecp256k1 contributors
* Copyright 2018 the bitcoinj-cash developers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -14,10 +15,14 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file has been modified by the bitcoinj-cash developers for the bitcoinj-cash project.
* The original file was from the bitcoinj project (https://github.com/bitcoinj/bitcoinj).
*/
package org.bitcoinj.core;
import org.bitcoinj.core.VerificationException.*;
import org.bitcoinj.crypto.*;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.MoreObjects;
......@@ -580,19 +585,15 @@ public class ECKey implements EncryptableItem {
decoder = new ASN1InputStream(bytes);
DLSequence seq = (DLSequence) decoder.readObject();
if (seq == null)
throw new RuntimeException("Reached past end of ASN.1 stream.");
throw new SignatureFormatError("Reached past end of ASN.1 stream.");
ASN1Integer r, s;
try {
r = (ASN1Integer) seq.getObjectAt(0);
s = (ASN1Integer) seq.getObjectAt(1);
} catch (ClassCastException e) {
throw new IllegalArgumentException(e);
}
r = (ASN1Integer) seq.getObjectAt(0);
s = (ASN1Integer) seq.getObjectAt(1);
// OpenSSL deviates from the DER spec by interpreting these values as unsigned, though they should not be
// Thus, we always use the positive versions. See: http://r6.ca/blog/20111119T211504Z.html
return new ECDSASignature(r.getPositiveValue(), s.getPositiveValue());
} catch (IOException e) {
throw new RuntimeException(e);
} catch (Exception e) {
throw new SignatureFormatError(e);
} finally {
if (decoder != null)
try { decoder.close(); } catch (IOException x) {}
......@@ -713,15 +714,19 @@ public class ECKey implements EncryptableItem {
}
ECDSASigner signer = new ECDSASigner();
ECPublicKeyParameters params = new ECPublicKeyParameters(CURVE.getCurve().decodePoint(pub), CURVE);
signer.init(false, params);
try {
ECPublicKeyParameters params = new ECPublicKeyParameters(CURVE.getCurve().decodePoint(pub), CURVE);
signer.init(false, params);
return signer.verifySignature(data, signature.r, signature.s);
} catch (NullPointerException e) {
// Bouncy Castle contains a bug that can cause NPEs given specially crafted signatures. Those signatures
// are inherently invalid/attack sigs so we just fail them here rather than crash the thread.
log.error("Caught NPE inside bouncy castle", e);
return false;
} catch (IllegalArgumentException e) {
throw new SignatureFormatError(e);
} catch (ArrayIndexOutOfBoundsException e) {
throw new SignatureFormatError(e);
}
}
......
/*
* Copyright 2011 Google Inc.
* Copyright 2018 the bitcoinj-cash developers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -12,18 +13,36 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file has been modified by the bitcoinj-cash developers for the bitcoinj-cash project.
* The original file was from the bitcoinj project (https://github.com/bitcoinj/bitcoinj).
*/
package org.bitcoinj.core;
@SuppressWarnings("serial")
import org.bitcoinj.script.ScriptError;
public class ScriptException extends VerificationException {
public ScriptException(String msg) {
private ScriptError err = null;
public ScriptException(ScriptError err, String msg) {
super(msg);
this.err = err;
}
public ScriptException(String msg, Exception e) {
public ScriptException(ScriptError err, String msg, Exception e) {
super(msg, e);
this.err = err;
}
public ScriptException(String msg) {
super(msg);
}
public ScriptError getError() {
return err;
}
}
......@@ -160,6 +160,24 @@ public class Transaction extends ChildMessage {
// can properly keep track of optimal encoded size
private int optimalEncodingMessageSize;
public boolean isOpReturn() {
if (getOpReturnData() != null) {
return true;
}
return false;
}
public byte[] getOpReturnData() {
// Only one OP_RETURN output per transaction is allowed as "standard" transaction
// So just return the first OP_RETURN data found
for (TransactionOutput output : outputs) {
if (output.isOpReturn()) {
return output.getOpReturnData();
}
}
return null;
}
/**
* This enum describes the underlying reason the transaction was created. It's useful for rendering wallet GUIs
* more appropriately.
......@@ -953,6 +971,12 @@ public class Transaction extends ChildMessage {
return addOutput(new TransactionOutput(params, this, value, address));
}
public TransactionOutput addData(byte[] data) {
Script script = ScriptBuilder.createOpReturnScript(data);
return addOutput(new TransactionOutput(params, this, Coin.ZERO, script.getProgram()));
}
/**
* Creates an output that pays to the given pubkey directly (no address) with the given value, adds it to this
* transaction, and returns the new output.
......@@ -1063,9 +1087,10 @@ public class Transaction extends ChildMessage {
byte[] redeemScript,
Coin value,
SigHash hashType,
boolean anyoneCanPay)
boolean anyoneCanPay,
Set<Script.VerifyFlag> verifyFlags)
{
Sha256Hash hash = hashForSignatureWitness(inputIndex, redeemScript, value, hashType, anyoneCanPay);
Sha256Hash hash = hashForSignatureWitness(inputIndex, redeemScript, value, hashType, anyoneCanPay, verifyFlags);
return new TransactionSignature(key.sign(hash, aesKey), hashType, anyoneCanPay, true);
}
......@@ -1101,9 +1126,10 @@ public class Transaction extends ChildMessage {
Script redeemScript,
Coin value,
SigHash hashType,
boolean anyoneCanPay)
boolean anyoneCanPay,
Set<Script.VerifyFlag> verifyFlags)
{
Sha256Hash hash = hashForSignatureWitness(inputIndex, redeemScript.getProgram(), value, hashType, anyoneCanPay);
Sha256Hash hash = hashForSignatureWitness(inputIndex, redeemScript.getProgram(), value, hashType, anyoneCanPay, verifyFlags);
return new TransactionSignature(key.sign(hash, aesKey), hashType, anyoneCanPay, true);
}
/**
......@@ -1251,6 +1277,18 @@ public class Transaction extends ChildMessage {
* @param type Should be SigHash.ALL
* @param anyoneCanPay should be false.
*/
public synchronized Sha256Hash hashForSignatureWitness(
int inputIndex,
Script scriptCode,
Coin prevValue,
SigHash type,
boolean anyoneCanPay,
Set<Script.VerifyFlag> verifyFlags)
{
byte[] connectedScript = scriptCode.getProgram();
return hashForSignatureWitness(inputIndex, connectedScript, prevValue, type, anyoneCanPay, verifyFlags);
}
public synchronized Sha256Hash hashForSignatureWitness(
int inputIndex,
Script scriptCode,
......@@ -1259,7 +1297,7 @@ public class Transaction extends ChildMessage {
boolean anyoneCanPay)
{
byte[] connectedScript = scriptCode.getProgram();
return hashForSignatureWitness(inputIndex, connectedScript, prevValue, type, anyoneCanPay);
return hashForSignatureWitness(inputIndex, connectedScript, prevValue, type, anyoneCanPay, null);
}
public synchronized Sha256Hash hashForSignatureWitness(
......@@ -1267,11 +1305,38 @@ public class Transaction extends ChildMessage {
byte[] connectedScript,
Coin prevValue,
SigHash type,
boolean anyoneCanPay)
boolean anyoneCanPay) {
return hashForSignatureWitness(inputIndex, connectedScript, prevValue, type, anyoneCanPay, null);
}
public synchronized Sha256Hash hashForSignatureWitness(
int inputIndex,
byte[] connectedScript,
Coin prevValue,
SigHash type,
boolean anyoneCanPay,
Set<Script.VerifyFlag> verifyFlags)
{
byte sigHashType = (byte) TransactionSignature.calcSigHashValue(type, anyoneCanPay, true);
ByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(length == UNKNOWN_LENGTH ? 256 : length + 4);
try {
// Replay Protection Implementation:
// If the "REPLAY PRIOTECTION" Flag is activated, we implement the Replay Protection Algorithm, which
// allows us the use different Fork IDS in the future. The Fork ID will be stored in the 24 more significant
// bits of nSigHashType (which is not a single byte now, but a 32 one).
// The following implementation is based on the one from bitcoin-abc:
int nSigHashType = sigHashType;
if ((verifyFlags!= null) && verifyFlags.contains(Script.VerifyFlag.REPLAY_PROTECTION)) {
// Legacy chain's value for fork id must be of the form 0xffxxxx.
// By xoring with 0xdead, we ensure that the value will be different
// from the original one, even if it already starts with 0xff.
int forkId = 0; // for now, the forkID is ZERO.
int newForkValue = forkId ^ 0xdead;
nSigHashType = sigHashType | ((0xff0000 | newForkValue) << 8);
}
byte[] hashPrevouts = new byte[32];
byte[] hashSequence = new byte[32];
byte[] hashOutputs = new byte[32];
......@@ -1326,7 +1391,8 @@ public class Transaction extends ChildMessage {
uint32ToByteStreamLE(inputs.get(inputIndex).getSequenceNumber(), bos);
bos.write(hashOutputs);
uint32ToByteStreamLE(this.lockTime, bos);
uint32ToByteStreamLE(0x000000ff & sigHashType, bos);
// uint32ToByteStreamLE(0x000000ff & sigHashType, bos);
uint32ToByteStreamLE(nSigHashType, bos);
} catch (IOException e) {
throw new RuntimeException(e); // Cannot happen.
}
......
......@@ -50,6 +50,23 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class TransactionInput extends ChildMessage {
/** Magic sequence number that indicates there is no sequence number. */
public static final long NO_SEQUENCE = 0xFFFFFFFFL;
/**
* BIP68: If this flag set, sequence is NOT interpreted as a relative lock-time.
*/
public static final long SEQUENCE_LOCKTIME_DISABLE_FLAG = 1L << 31;
/**
* BIP68: If sequence encodes a relative lock-time and this flag is set, the relative lock-time has units of 512
* seconds, otherwise it specifies blocks with a granularity of 1.
*/
public static final long SEQUENCE_LOCKTIME_TYPE_FLAG = 1L << 22;
/**
* BIP68: If sequence encodes a relative lock-time, this mask is applied to extract that lock-time from the sequence
* field.
*/
public static final long SEQUENCE_LOCKTIME_MASK = 0x0000ffff;
private static final byte[] EMPTY_ARRAY = new byte[0];
// Magic outpoint index that indicates the input is in fact unconnected.
private static final long UNCONNECTED = 0xFFFFFFFFL;
......
......@@ -427,4 +427,16 @@ public class TransactionOutput extends ChildMessage {
public int hashCode() {
return Objects.hashCode(value, parent, Arrays.hashCode(scriptBytes));
}
public boolean isOpReturn() {
return getScriptPubKey() != null && getScriptPubKey().isOpReturn();
}
public byte[] getOpReturnData() {
if (isOpReturn()) {
return getScriptPubKey().getChunks().get(1).data;
}
return null;
}
}
/*
* Copyright 2011 Google Inc.
* Copyright 2018 the bitcoinj-cash developers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -12,6 +13,9 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file has been modified by the bitcoinj-cash developers for the bitcoinj-cash project.
* The original file was from the bitcoinj project (https://github.com/bitcoinj/bitcoinj).
*/
package org.bitcoinj.core;
......@@ -30,15 +34,22 @@ public class VerificationException extends RuntimeException {
super(msg, t);
}
public static class EmptyInputsOrOutputs extends VerificationException {
public EmptyInputsOrOutputs() {
super("Transaction had no inputs or no outputs.");
public static class BlockVersionOutOfDate extends VerificationException {
public BlockVersionOutOfDate(final long version) {
super("Block version #"
+ version + " is outdated.");
}
}
public static class LargerThanMaxBlockSize extends VerificationException {
public LargerThanMaxBlockSize() {
super("Transaction larger than MAX_BLOCK_SIZE");
public static class CoinbaseHeightMismatch extends VerificationException {
public CoinbaseHeightMismatch(final String message) {
super(message);
}
}
public static class CoinbaseScriptSizeOutOfRange extends VerificationException {
public CoinbaseScriptSizeOutOfRange() {
super("Coinbase script size out of range");
}
}
......@@ -48,9 +59,9 @@ public class VerificationException extends RuntimeException {
}
}
public static class NegativeValueOutput extends VerificationException {
public NegativeValueOutput() {
super("Transaction output negative");
public static class EmptyInputsOrOutputs extends VerificationException {
public EmptyInputsOrOutputs() {
super("Transaction had no inputs or no outputs.");
}
}
......@@ -60,30 +71,32 @@ public class VerificationException extends RuntimeException {
}
}
public static class LargerThanMaxBlockSize extends VerificationException {
public LargerThanMaxBlockSize() {
super("Transaction larger than MAX_BLOCK_SIZE");
}
}
public static class CoinbaseScriptSizeOutOfRange extends VerificationException {
public CoinbaseScriptSizeOutOfRange() {
super("Coinbase script size out of range");
public static class NegativeValueOutput extends VerificationException {
public NegativeValueOutput() {
super("Transaction output negative");
}
}
public static class SignatureFormatError extends VerificationException {
public SignatureFormatError(String msg) {
super(msg);
}
public static class BlockVersionOutOfDate extends VerificationException {
public BlockVersionOutOfDate(final long version) {
super("Block version #"
+ version + " is outdated.");
public SignatureFormatError(Exception e) {
super(e);
}
}
public static class UnexpectedCoinbaseInput extends VerificationException {
public UnexpectedCoinbaseInput() {
super("Coinbase input as input in non-coinbase transaction");
}
}
public static class CoinbaseHeightMismatch extends VerificationException {
public CoinbaseHeightMismatch(final String message) {
super(message);
}
}
}
......@@ -89,6 +89,20 @@ public class TransactionSignature extends ECKey.ECDSASignature {
return sighashFlags;
}
/**
* Checkes if the Hashtype is properly set in the signature.
* (from bicopinj-cash)
*
* @param signature Signature
* @return True (correct Hashtype)/ False
*/
public static boolean isValidHashType(byte[] signature) {
boolean result = true;
int hashType = (signature[signature.length-1] & 0xff) & ~(Transaction.SigHash.ANYONECANPAY.value| SigHash.FORKID.value); // mask the byte to prevent sign-extension hurting us
if (hashType < Transaction.SigHash.ALL.value || hashType > Transaction.SigHash.SINGLE.value)
result = false;
return result;
}
/**
* Returns true if the given signature is has canonical encoding, and will thus be accepted as standard by
* Bitcoin Core. DER and the SIGHASH encoding allow for quite some flexibility in how the same structures
......@@ -103,11 +117,9 @@ public class TransactionSignature extends ECKey.ECDSASignature {
// Where R and S are not negative (their first byte has its highest bit not set), and not
// excessively padded (do not start with a 0 byte, unless an otherwise negative number follows,
// in which case a single 0 byte is necessary and even required).
if (signature.length < 9 || signature.length > 73)
return false;
int hashType = (signature[signature.length-1] & 0xff) & ~(Transaction.SigHash.ANYONECANPAY.value| SigHash.FORKID.value); // mask the byte to prevent sign-extension hurting us
if (hashType < Transaction.SigHash.ALL.value || hashType > Transaction.SigHash.SINGLE.value)
if (signature.length < 9 || signature.length > 73)
return false;
// "wrong type" "wrong length marker"
......
/*
* Copyright 2017 Nicola Atzei
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.script;
import java.util.HashMap;
import java.util.Map;
public enum ScriptError {
SCRIPT_ERR_OK("OK"),
SCRIPT_ERR_UNKNOWN_ERROR("UNKNOWN_ERROR"),
SCRIPT_ERR_EVAL_FALSE("EVAL_FALSE"),
SCRIPT_ERR_OP_RETURN("OP_RETURN"),
SCRIPT_ERR_STANDARD("STANDARD_SCRIPT"),
/* Max sizes */
SCRIPT_ERR_SCRIPT_SIZE("SCRIPT_SIZE"),
SCRIPT_ERR_PUSH_SIZE("PUSH_SIZE"),
SCRIPT_ERR_OP_COUNT("OP_COUNT"),
SCRIPT_ERR_STACK_SIZE("STACK_SIZE"),
SCRIPT_ERR_SIG_COUNT("SIG_COUNT"),
SCRIPT_ERR_PUBKEY_COUNT("PUBKEY_COUNT"),
SCRIPT_ER_OPERAND_SIZE("OPERAND_SIZE"),
/* Failed verify operations */
SCRIPT_ERR_VERIFY("VERIFY"),
SCRIPT_ERR_EQUALVERIFY("EQUALVERIFY"),
SCRIPT_ERR_CHECKMULTISIGVERIFY("CHECKMULTISIGVERIFY"),
SCRIPT_ERR_CHECKSIGVERIFY("CHECKSIGVERIFY"),
SCRIPT_ERR_NUMEQUALVERIFY("NUMEQUALVERIFY"),
/* Logical/Format/Canonical errors */
SCRIPT_ERR_BAD_OPCODE("BAD_OPCODE"),
SCRIPT_ERR_DISABLED_OPCODE("DISABLED_OPCODE"),
SCRIPT_ERR_INVALID_STACK_OPERATION("INVALID_STACK_OPERATION"),
SCRIPT_ERR_INVALID_ALTSTACK_OPERATION("INVALID_ALTSTACK_OPERATION"),
SCRIPT_ERR_UNBALANCED_CONDITIONAL("UNBALANCED_CONDITIONAL"),
/* CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY */
SCRIPT_ERR_NEGATIVE_LOCKTIME("NEGATIVE_LOCKTIME"),
SCRIPT_ERR_UNSATISFIED_LOCKTIME("UNSATISFIED_LOCKTIME"),
/* Malleability */
SCRIPT_ERR_SIG_HASHTYPE("SIG_HASHTYPE"),
SCRIPT_ERR_SIG_DER("SIG_DER"),
SCRIPT_ERR_MINIMALDATA("MINIMALDATA"),
SCRIPT_ERR_SIG_PUSHONLY("SIG_PUSHONLY"),
SCRIPT_ERR_SIG_HIGH_S("SIG_HIGH_S"),
SCRIPT_ERR_SIG_NULLDUMMY("SIG_NULLDUMMY"),
SCRIPT_ERR_PUBKEYTYPE("PUBKEYTYPE"),
SCRIPT_ERR_CLEANSTACK("CLEANSTACK"),
SCRIPT_ERR_MINIMALIF("MINIMALIF"),
SCRIPT_ERR_SIG_NULLFAIL("NULLFAIL"),
/* softfork safeness */
SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS("DISCOURAGE_UPGRADABLE_NOPS"),
SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM("DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"),
/* Other Errors */
SCRIPT_ERR_DIV_BY_ZERO("DIV_BY_ZERO"),
SCRIPT_ERR_MOD_BY_ZERO("MOD_BY_ZERO"),
SCRIPT_ERR_SPLIT_RANGE("SPLIT_RANGE"),
SCRIPT_ERR_IMPOSSIBLE_ENCODING("IMPOSSIBLE_ENCODING"),
SCRIPT_ERR_INVALID_NUMBER_RANGE("INVALID_NUMBER_RANGE"),
SCRIPT_ERR_FORKID("ILLEGAL_FORKID");
private final String mnemonic;
private static final Map<String, ScriptError> mnemonicToScriptErrorMap;
private ScriptError(String name) {
this.mnemonic = name;
}
static {
mnemonicToScriptErrorMap = new HashMap<>();
for (ScriptError err : ScriptError.values()) {
mnemonicToScriptErrorMap.put(err.getMnemonic(), err);
}
}
public String getMnemonic() {
return mnemonic;
}
public static ScriptError fromMnemonic(String name) {
ScriptError err = mnemonicToScriptErrorMap.get(name);
if (err == null)
throw new IllegalArgumentException(name + " is not a valid name");
return err;
}
}
\ No newline at end of file
/*
* Copyright 2013 Google Inc.
* Copyright 2018 the bitcoinj-cash developers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -12,6 +13,9 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file has been modified by the bitcoinj-cash developers for the bitcoinj-cash project.
* The original file was from the bitcoinj project (https://github.com/bitcoinj/bitcoinj).
*/
package org.bitcoinj.script;
......@@ -145,13 +149,15 @@ public class ScriptOpCodes {
// block state
/** Check lock time of the block. Introduced in BIP 65, replacing OP_NOP2 */
public static final int OP_CHECKLOCKTIMEVERIFY = 0xb1;
public static final int OP_CHECKSEQUENCEVERIFY = 0xb2;
// expansion
public static final int OP_NOP1 = 0xb0;
/** Deprecated by BIP 65 */
@Deprecated
public static final int OP_NOP2 = OP_CHECKLOCKTIMEVERIFY;
public static final int OP_NOP3 = 0xb2;
@Deprecated
public static final int OP_NOP3 = OP_CHECKSEQUENCEVERIFY;
public static final int OP_NOP4 = 0xb3;
public static final int OP_NOP5 = 0xb4;
public static final int OP_NOP6 = 0xb5;
......@@ -266,7 +272,7 @@ public class ScriptOpCodes {
.put(OP_CHECKMULTISIGVERIFY, "CHECKMULTISIGVERIFY")
.put(OP_NOP1, "NOP1")
.put(OP_CHECKLOCKTIMEVERIFY, "CHECKLOCKTIMEVERIFY")
.put(OP_NOP3, "NOP3")
.put(OP_CHECKSEQUENCEVERIFY, "CHECKSEQUENCEVERIFY")
.put(OP_NOP4, "NOP4")
.put(OP_NOP5, "NOP5")
.put(OP_NOP6, "NOP6")
......@@ -380,6 +386,7 @@ public class ScriptOpCodes {
.put("NOP1", OP_NOP1)
.put("CHECKLOCKTIMEVERIFY", OP_CHECKLOCKTIMEVERIFY)
.put("NOP2", OP_NOP2)
.put("CHECKSEQUENCEVERIFY", OP_CHECKSEQUENCEVERIFY)
.put("NOP3", OP_NOP3)
.put("NOP4", OP_NOP4)
.put("NOP5", OP_NOP5)
......
......@@ -3804,6 +3804,16 @@ public class Wallet extends BaseTaggableObject
}
public SendResult sendData(TransactionBroadcaster broadcaster, byte[] data, boolean useforkId) throws InsufficientMoneyException {
Transaction tx = new Transaction(params);
tx.addData(data);
SendRequest request = SendRequest.forTx(tx);
request.setUseForkId(useforkId);
return sendCoins(broadcaster, request);
}
public SendResult sendCoins(TransactionBroadcaster broadcaster, Address to, Coin value, boolean useforkId) throws InsufficientMoneyException {
SendRequest request = SendRequest.to(to, value);
request.setUseForkId(useforkId);
......
......@@ -402,8 +402,15 @@ public class ECKeyTest {
in.close();
}
// NOTE: 2018-07-16:
// The "isEncodingCanonical" method in "TransactionSignature" does NOT check the content
// of the SIGHASH byte, since it's out of scope of the DER specification. The
// "sig_noncanonical.json" file contains signatures correct from DER perspective, but with
// WRONG SIGHASH types, therefore they are correct from "encodingCanonical" perspective. If
// we need to also check the content of the SIGHASH, then we need to apply an additional
// method: "isValidHashType". We also renamed the test to reflect this.
@Test
public void testNonCanonicalSigs() throws Exception {
public void testNonCanonicalOrWrongSighashSigs() throws Exception {
// Tests the noncanonical sigs from Bitcoin Core unit tests
InputStream in = getClass().getResourceAsStream("sig_noncanonical.json");
......@@ -420,7 +427,9 @@ public class ECKeyTest {
try {
final String sigStr = sig.toString();
assertFalse(TransactionSignature.isEncodingCanonical(HEX.decode(sigStr)));
byte[] signature = HEX.decode(sigStr);
assertFalse(TransactionSignature.isEncodingCanonical(signature)
&& TransactionSignature.isValidHashType(signature));
} catch (IllegalArgumentException e) {
// Expected for non-hex strings in the JSON that we should ignore
}
......
......@@ -194,8 +194,9 @@ public class TransactionTest {
Script invalidScriptSig2 =
ScriptBuilder.createCLTVPaymentChannelInput(incorrectSig, toSig);
EnumSet<Script.VerifyFlag> flags = EnumSet.of(Script.VerifyFlag.STRICTENC);
try {
scriptSig.correctlySpends(tx, 0, outputScript, Script.ALL_VERIFY_FLAGS);
scriptSig.correctlySpends(tx, 0, outputScript, flags);
} catch (ScriptException e) {
e.printStackTrace();
fail("Settle transaction failed to correctly spend the payment channel");
......@@ -235,8 +236,9 @@ public class TransactionTest {
Script invalidScriptSig =
ScriptBuilder.createCLTVPaymentChannelRefund(incorrectSig);
EnumSet<Script.VerifyFlag> flags = EnumSet.of(Script.VerifyFlag.STRICTENC);
try {
scriptSig.correctlySpends(tx, 0, outputScript, Script.ALL_VERIFY_FLAGS);
scriptSig.correctlySpends(tx, 0, outputScript, flags);
} catch (ScriptException e) {
e.printStackTrace();
fail("Refund failed to correctly spend the payment channel");
......@@ -414,8 +416,33 @@ public class TransactionTest {
Script sig = tx.getInput(0).getScriptSig();
sig.correctlySpends(tx, 0, txConnected.getOutput(1).getScriptPubKey(), txConnected.getOutput(1).getValue(), Script.ALL_VERIFY_FLAGS);
EnumSet<Script.VerifyFlag> flags = EnumSet.of(Script.VerifyFlag.STRICTENC, Script.VerifyFlag.SIGHASH_FORKID);
sig.correctlySpends(tx, 0, txConnected.getOutput(1).getScriptPubKey(), txConnected.getOutput(1).getValue(), flags);
}
@Test
public void testRawParseAndExport() {
NetworkParameters params = MainNetParams.get();
// https://blockchain.info/tx/ed27cf72886af7c830faeff136b3859185310334330a4856f60c768ab46b9c1c
String rawTx1 = "010000000193e3073ecc1d27f17e3d287ccefdfdba5f7d8c160242dbcd547b18baef12f9b31a0000006b483045022100af501dc9ef2907247d28a5169b8362ca494e1993f833928b77264e604329eec40220313594f38f97c255bcea6d5a4a68e920508ef93fd788bcf5b0ad2fa5d34940180121034bb555cc39ba30561793cf39a35c403fe8cf4a89403b02b51e058960520bd1e3ffffffff02b3bb0200000000001976a914f7d52018971f4ab9b56f0036958f84ae0325ccdc88ac98100700000000001976a914f230f0a16a98433eca0fa70487b85fb83f7b61cd88ac00000000";
Transaction tx1 = new Transaction(params, HEX.decode(rawTx1));
assertEquals(rawTx1, HEX.encode(tx1.bitcoinSerialize()));
// https://blockchain.info/tx/0024db8e11da76b2344e0722bf9488ba2aed611913f9803a62ac3b41f5603946
String rawTx2 = "01000000011c9c6bb48a760cf656480a33340331859185b336f1effa30c8f76a8872cf27ed000000006a47304402201c999cf44dc6576783c0f55b8ff836a1e22db87ed67dc3c39515a6676cfb58e902200b4a925f9c8d6895beed841db135051f8664ab349f2e3ea9f8523a6f47f93883012102e58d7b931b5d43780fda0abc50cfd568fcc26fb7da6a71591a43ac8e0738b9a4ffffffff029b010100000000001976a9140f0fcdf818c0c88df6860c85c9cc248b9f37eaff88ac95300100000000001976a9140663d2403f560f8d053a25fbea618eb47071617688ac00000000";
Transaction tx2 = new Transaction(params, HEX.decode(rawTx2));
assertEquals(rawTx2, HEX.encode(tx2.bitcoinSerialize()));
// https://blockchair.com/bitcoin-cash/transaction/0eab89a271380b09987bcee5258fca91f28df4dadcedf892658b9bc261050d96
String rawTx3 = "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2c03ccec051f4d696e656420627920416e74506f6f6c20626a3515d2158520566e53850b00110000008c7a0900ffffffff01e170f895000000001976a9149524440a5b54cca9c46ef277c34739e9b521856d88ac00000000";
Transaction tx3 = new Transaction(params, HEX.decode(rawTx3));
assertEquals(rawTx3, HEX.encode(tx3.bitcoinSerialize()));
// https://blockchair.com/bitcoin-cash/transaction/1e24eaaa72b6c10a4d57084ab3acb612bd123bbf64c2a5746b6221b02202090e
String rawTx4 = "0200000001a73374e059d610c0f8ee6fcbc1f89b54ebf7b109426b38d8e3e744e698abf8a5010000006a47304402200dfc3bacafb825c0c457ff3756e9c243965be45d5d490e70c5dfb2f6060445870220431e3d9f852d4b5803ab0d189d8931dc6c35f3724d6be3e8928043b7c789f66a4121022e46d40245e27e8ef260f8d724838c850a5447b81ae9f77d2d5e28fd2640a36a0000000001d4092800000000001976a9147775f3423eb410a4184d9d3ef93f7ed4d1c1d4e988ac00000000";