Skip to content

Commit

Permalink
Spreadcoin changes bitcoinj#2
Browse files Browse the repository at this point in the history
  • Loading branch information
bitbandi committed Jan 26, 2015
1 parent 0237e2e commit c305bc7
Show file tree
Hide file tree
Showing 31 changed files with 372 additions and 314 deletions.
4 changes: 2 additions & 2 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@
<!-- Format is URN of groupId:artifactId:version:type:classifier:scope:hash -->
<!-- classifier is "null" if not present -->
<urns>
<urn>org.spreadcoinj:orchid:1.0:jar:null:compile:bd98285f39f88875bb91bde940d6ca2d020edaa4</urn>
<urn>org.bitcoinj:orchid:1.0:jar:null:compile:bd98285f39f88875bb91bde940d6ca2d020edaa4</urn>
<urn>cglib:cglib-nodep:2.2:jar:null:test:59afed7ab65e7ec6585d5bc60556c3cbd203532b</urn>
<urn>com.google.code.findbugs:jsr305:2.0.1:jar:null:compile:516c03b21d50a644d538de0f0369c620989cd8f0</urn>
<urn>com.google.guava:guava:16.0.1:jar:null:compile:5fa98cd1a63c99a44dd8d3b77e4762b066a5d0c5</urn>
Expand Down Expand Up @@ -269,7 +269,7 @@
<artifactItem>
<outputDirectory>target/test-classes/</outputDirectory>
<groupId>org.spreadcoinj</groupId>
<artifactId>spreadcoin-core</artifactId>
<artifactId>spreadcoinj-core</artifactId>
<version>${project.version}</version>
</artifactItem>
</artifactItems>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ private boolean add(Block block, boolean tryConnecting,
return false;
} else {
// It connects to somewhere on the chain. Not necessarily the top of the best known chain.
checkDifficultyTransitions(storedPrev, block);
// checkDifficultyTransitions(storedPrev, block);
connectBlock(block, storedPrev, shouldVerifyTransactions(), filteredTxHashList, filteredTxn);
}

Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/org/spreadcoinj/core/Address.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,10 @@ public Address(NetworkParameters params, byte[] hash160) {
/**
* Construct an address from parameters and the standard "human readable" form. Example:<p>
*
* <pre>new Address(NetworkParameters.prodNet(), "17kzeh4N8g49GFvdDzSf8PjaPfyoD1MndL");</pre><p>
* <pre>new Address(NetworkParameters.prodNet(), "SU3zgXqWs3FLnZi5mRRjgHt93TDDyhT52e");</pre><p>
*
* @param params The expected NetworkParameters or null if you don't want validation.
* @param address The textual form of the address, such as "17kzeh4N8g49GFvdDzSf8PjaPfyoD1MndL"
* @param address The textual form of the address, such as "SU3zgXqWs3FLnZi5mRRjgHt93TDDyhT52e"
* @throws AddressFormatException if the given address doesn't parse or the checksum is invalid
* @throws WrongNetworkException if the given address is valid but for a different chain (eg testnet vs prodnet)
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,8 @@ public void serialize(Message message, OutputStream out) throws IOException {
public Message deserialize(ByteBuffer in) throws ProtocolException, IOException {
// A Bitcoin protocol message has the following format.
//
// - 4 byte magic number: 0xfabfb5da for the testnet or
// 0xf9beb4d9 for production
// - 4 byte magic number: 0xc2e3cbfa for the testnet or
// 0x4f3c5cbb for production
// - 12 byte command in ASCII
// - 4 byte payload size
// - 4 byte checksum
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/java/org/spreadcoinj/core/Block.java
Original file line number Diff line number Diff line change
Expand Up @@ -293,10 +293,11 @@ protected void parseLite() throws ProtocolException {
parseTransactions();
length = cursor - offset;
} else {
height = getUint32(Block.HEADER_POS_HEIGHT);
transactionBytesValid = !transactionsParsed || parseRetain && length > getHeaderSize();
}
headerBytesValid = !headerParsed || parseRetain && length >= getHeaderSize();
height = getUint32(Block.HEADER_POS_HEIGHT);
headerBytesValid = !headerParsed || parseRetain && length >= getHeaderSize();
}

/*
Expand Down
65 changes: 51 additions & 14 deletions core/src/main/java/org/spreadcoinj/core/ECKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -469,13 +469,15 @@ public Address toAddress(NetworkParameters params) {
public static class ECDSASignature {
/** The two components of the signature. */
public final BigInteger r, s;
public final int headerByte;

/**
* Constructs a signature with the given components. Does NOT automatically canonicalise the signature.
*/
public ECDSASignature(BigInteger r, BigInteger s) {
public ECDSASignature(BigInteger r, BigInteger s, int headerByte) {
this.r = r;
this.s = s;
this.headerByte = headerByte;
}

/**
Expand All @@ -492,7 +494,7 @@ public ECDSASignature toCanonicalised() {
// N = 10
// s = 8, so (-8 % 10 == 2) thus both (r, 8) and (r, 2) are valid solutions.
// 10 - 8 == 2, giving us always the latter solution, which is canonical.
return new ECDSASignature(r, CURVE.getN().subtract(s));
return new ECDSASignature(r, CURVE.getN().subtract(s), headerByte);
} else {
return this;
}
Expand Down Expand Up @@ -527,7 +529,7 @@ public static ECDSASignature decodeFromDER(byte[] bytes) {
}
// 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());
return new ECDSASignature(r.getPositiveValue(), s.getPositiveValue(), 0);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
Expand All @@ -536,6 +538,36 @@ public static ECDSASignature decodeFromDER(byte[] bytes) {
}
}

public byte[] encodeToCompact() {
try {
return compactByteStream().toByteArray();
} catch (IOException e) {
throw new RuntimeException(e); // Cannot happen.
}
}

public static ECDSASignature decodeFromCompact(byte[] bytes) {
try {
if (bytes.length < 65)
throw new SignatureException("Signature truncated, expected 65 bytes and got " + bytes.length);
BigInteger r = new BigInteger(1, Arrays.copyOfRange(bytes, 1, 33));
BigInteger s = new BigInteger(1, Arrays.copyOfRange(bytes, 33, 65));
int header = bytes[0] & 0xFF;
return new ECDSASignature(r, s, header);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

protected ByteArrayOutputStream compactByteStream() throws IOException {
// Usually 65 bytes.
ByteArrayOutputStream bos = new ByteArrayOutputStream(65);
bos.write(headerByte);
bos.write(Utils.bigIntegerToBytes(r, 32), 0, 32);
bos.write(Utils.bigIntegerToBytes(s, 32), 0, 32);
return bos;
}

protected ByteArrayOutputStream derByteStream() throws IOException {
// Usually 70-72 bytes.
ByteArrayOutputStream bos = new ByteArrayOutputStream(72);
Expand Down Expand Up @@ -614,7 +646,19 @@ protected ECDSASignature doSign(Sha256Hash input, BigInteger privateKeyForSignin
ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(privateKeyForSigning, CURVE);
signer.init(true, privKey);
BigInteger[] components = signer.generateSignature(input.getBytes());
return new ECDSASignature(components[0], components[1]).toCanonicalised();
// Now we have to work backwards to figure out the recId needed to recover the signature.
int recId = -1;
for (int i = 0; i < 4; i++) {
ECKey k = ECKey.recoverFromSignature(i, new ECDSASignature(components[0], components[1], 0).toCanonicalised(), input, false);
if (k != null && k.pub.equals(pub)) {
recId = i;
break;
}
}
if (recId == -1)
throw new RuntimeException("Could not construct a recoverable key. This should never happen.");
int headerByte = recId + 27;
return new ECDSASignature(components[0], components[1], headerByte).toCanonicalised();
}

/**
Expand Down Expand Up @@ -658,7 +702,7 @@ public static boolean verify(byte[] data, ECDSASignature signature, byte[] pub)
public static boolean verify(byte[] data, byte[] signature, byte[] pub) {
if (NativeSecp256k1.enabled)
return NativeSecp256k1.verify(data, signature, pub);
return verify(data, ECDSASignature.decodeFromDER(signature), pub);
return verify(data, ECDSASignature.decodeFromCompact(signature), pub);
}

/**
Expand Down Expand Up @@ -802,7 +846,6 @@ public static ECKey signedMessageToKey(String message, String signatureBase64) t
throw new SignatureException("Header byte out of range: " + header);
BigInteger r = new BigInteger(1, Arrays.copyOfRange(signatureEncoded, 1, 33));
BigInteger s = new BigInteger(1, Arrays.copyOfRange(signatureEncoded, 33, 65));
ECDSASignature sig = new ECDSASignature(r, s);
byte[] messageBytes = Utils.formatMessageForSigning(message);
// Note that the C++ code doesn't actually seem to specify any character encoding. Presumably it's whatever
// JSON-SPIRIT hands back. Assume UTF-8 for now.
Expand All @@ -813,6 +856,7 @@ public static ECKey signedMessageToKey(String message, String signatureBase64) t
header -= 4;
}
int recId = header - 27;
ECDSASignature sig = new ECDSASignature(r, s, recId);
ECKey key = ECKey.recoverFromSignature(recId, sig, messageHash, compressed);
if (key == null)
throw new SignatureException("Could not recover public key from signature");
Expand All @@ -824,17 +868,10 @@ public static ECKey signedToKey(Sha256Hash hash, byte[] signatureEncoded, boolea
if (signatureEncoded.length < 65)
throw new SignatureException("Signature truncated, expected 65 bytes and got " + signatureEncoded.length);
int header = signatureEncoded[0] & 0xFF;
// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
// 0x1D = second key with even y, 0x1E = second key with odd y
if (header < 27 || header > 34)
throw new SignatureException("Header byte out of range: " + header);
BigInteger r = new BigInteger(1, Arrays.copyOfRange(signatureEncoded, 1, 33));
BigInteger s = new BigInteger(1, Arrays.copyOfRange(signatureEncoded, 33, 65));
ECDSASignature sig = new ECDSASignature(r, s);
if (header >= 31) {
compressed = true;
header -= 4;
}
ECDSASignature sig = ECKey.ECDSASignature.decodeFromCompact(signatureEncoded);
int recId = header - 27;
ECKey key = ECKey.recoverFromSignature(recId, sig, hash, compressed);
if (key == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ public Coin getMinNonDustValue(Coin feePerKbRequired) {
* {@link Transaction#MIN_NONDUST_OUTPUT}.
*/
public Coin getMinNonDustValue() {
return getMinNonDustValue(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.multiply(3));
return Coin.ZERO;
}

/**
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/org/spreadcoinj/core/Wallet.java
Original file line number Diff line number Diff line change
Expand Up @@ -2527,7 +2527,7 @@ public String toString(boolean includePrivateKeys, boolean includeTransactions,
StringBuilder builder = new StringBuilder();
Coin estimatedBalance = getBalance(BalanceType.ESTIMATED);
Coin availableBalance = getBalance(BalanceType.AVAILABLE);
builder.append(String.format("Wallet containing %s BTC (available: %s BTC) in:%n",
builder.append(String.format("Wallet containing %s SPR (available: %s SPR) in:%n",
estimatedBalance.toPlainString(), availableBalance.toPlainString()));
builder.append(String.format(" %d pending transactions%n", pending.size()));
builder.append(String.format(" %d unspent transactions%n", unspent.size()));
Expand Down Expand Up @@ -3041,7 +3041,7 @@ public static class SendRequest {
* If you want to modify the default fee for your entire app without having to change each SendRequest you make,
* you can do it here. This is primarily useful for unit tests.
*/
public static Coin DEFAULT_FEE_PER_KB = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE;
public static Coin DEFAULT_FEE_PER_KB = Coin.ZERO;

/**
* <p>Requires that there be enough fee for a default reference client to at least relay the transaction.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ public TransactionSignature(BigInteger r, BigInteger s) {

/** Constructs a signature with the given components and raw sighash flag bytes (needed for rule compatibility). */
public TransactionSignature(BigInteger r, BigInteger s, int sighashFlags) {
super(r, s);
super(r, s, 0);
this.sighashFlags = sighashFlags;
}

/** Constructs a transaction signature based on the ECDSA signature. */
public TransactionSignature(ECKey.ECDSASignature signature, Transaction.SigHash mode, boolean anyoneCanPay) {
super(signature.r, signature.s);
super(signature.r, signature.s, signature.headerByte);
sighashFlags = calcSigHashValue(mode, anyoneCanPay);
}

Expand Down Expand Up @@ -141,7 +141,7 @@ else if (mode == Transaction.SigHash.SINGLE.ordinal() + 1)
*/
public byte[] encodeToBitcoin() {
try {
ByteArrayOutputStream bos = derByteStream();
ByteArrayOutputStream bos = compactByteStream();
bos.write(sighashFlags);
return bos.toByteArray();
} catch (IOException e) {
Expand Down
4 changes: 4 additions & 0 deletions core/src/main/java/org/spreadcoinj/params/RegTestParams.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ public RegTestParams() {
subsidyDecreaseBlockCount = 150;
port = 18444;
id = ID_REGTEST;

firstHardforkBlock = Integer.MAX_VALUE;
secondHardforkBlock = Integer.MAX_VALUE;

}

@Override
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/org/spreadcoinj/params/TestNetParams.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ public TestNetParams() {
p2shHeader = 196;
acceptableAddressCodes = new int[] { addressHeader, p2shHeader };
dumpedPrivateKeyHeader = 239;
genesisBlock.setTime(1406620000L); // real: 1406620000L
genesisBlock.setTime(1406620001L);
genesisBlock.setDifficultyTarget(0x1e0fffffL);
genesisBlock.setNonce(0);
genesisBlock.setHeight(0);
spendableCoinbaseDepth = 100;
subsidyDecreaseBlockCount = 2000000;
String genesisHash = genesisBlock.getHashAsString();
checkState(genesisHash.equals("14dcedae9369344e0542270805a0cef3213f2b17f693d9b2acec76c1b7ed7fa3"));
checkState(genesisHash.equals("31d842d76615b7faa1c2f7a773260acd6aa1a3d5cf720fb2688b712f93337a0b"));
alertSigningKey = Utils.HEX.decode("03f5cee48df4990af166d539f1cc42367034558d62e765a30ed3228ec418cc46bb");

dnsSeeds = new String[] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class UnitTestParams extends NetworkParameters {
public UnitTestParams() {
super();
id = ID_UNITTESTNET;
packetMagic = 0x0b110907;
packetMagic = 0xc2e3cbfa;
addressHeader = 111;
p2shHeader = 196;
acceptableAddressCodes = new int[] { addressHeader, p2shHeader };
Expand All @@ -45,6 +45,12 @@ public UnitTestParams() {
spendableCoinbaseDepth = 5;
subsidyDecreaseBlockCount = 100;
dnsSeeds = null;

firstHardforkBlock = 2200;
secondHardforkBlock = 43000;
// firstHardforkBlock = Integer.MAX_VALUE;
// secondHardforkBlock = Integer.MAX_VALUE;

}

private static UnitTestParams instance;
Expand Down
24 changes: 18 additions & 6 deletions core/src/main/java/org/spreadcoinj/script/Script.java
Original file line number Diff line number Diff line change
Expand Up @@ -217,11 +217,11 @@ private void parse(byte[] program) throws ScriptException {
*/
public boolean isSentToRawPubKey() {
return chunks.size() == 2 && chunks.get(1).equalsOpCode(OP_CHECKSIG) &&
!chunks.get(0).isOpCode() && chunks.get(0).data.length > 1;
!chunks.get(0).isOpCode() && chunks.get(0).data.length != Address.LENGTH;
}

/**
* Returns true if this script is of the form DUP HASH160 <pubkey hash> EQUALVERIFY CHECKSIG, ie, payment to an
* Returns true if this script is of the form <pubkey hash> CHECKSIG, ie, payment to an
* address like 1VayNert3x1KzbpzMGt2qdqrAThiRovi8. This form was originally intended for the case where you wish
* to send somebody money with a written code because their node is offline, but over time has become the standard
* way to make payments due to the short and recognizable base58 form addresses come in.
Expand All @@ -236,7 +236,7 @@ public boolean isSentToAddressOld() {
}

public boolean isSentToAddress() {
return chunks.size() == 2 &&
return chunks.size() == 2 && !chunks.get(0).isOpCode() &&
chunks.get(0).data.length == Address.LENGTH &&
chunks.get(1).equalsOpCode(OP_CHECKSIG);
}
Expand All @@ -250,7 +250,7 @@ public boolean isSentToP2SH() {
}

/**
* If a program matches the standard template DUP HASH160 <pubkey hash> EQUALVERIFY CHECKSIG
* If a program matches the standard template <pubkey hash> CHECKSIG
* then this function retrieves the third element, otherwise it throws a ScriptException.<p>
*
* This is useful for fetching the destination address of a transaction.
Expand Down Expand Up @@ -448,7 +448,7 @@ public Script getScriptSigWithSignature(Script scriptSig, byte[] sigBytes, int i
} else if (isSentToMultiSig()) {
sigsPrefixCount = 1; // OP_0 <sig>*
} else if (isSentToAddress()) {
sigsSuffixCount = 1; // <sig> <pubkey>
sigsSuffixCount = 0; // <sig>
}
return ScriptBuilder.updateScriptWithSignature(scriptSig, sigBytes, index, sigsPrefixCount, sigsSuffixCount);
}
Expand Down Expand Up @@ -621,10 +621,14 @@ public int getNumberOfBytesRequiredToSpend(@Nullable ECKey pubKey, @Nullable Scr
} else if (isSentToRawPubKey()) {
// scriptSig: <sig>
return SIG_SIZE;
} else if (isSentToAddress()) {
} else if (isSentToAddressOld()) {
// scriptSig: <sig> <pubkey>
int uncompressedPubKeySize = 65;
return SIG_SIZE + (pubKey != null ? pubKey.getPubKey().length : uncompressedPubKeySize);
} else if (isSentToAddress()) {
// scriptSig: <sig>
int uncompressedPubKeySize = 65;
return SIG_SIZE; // + (pubKey != null ? pubKey.getPubKey().length : uncompressedPubKeySize);
} else {
throw new IllegalStateException("Unsupported script type");
}
Expand Down Expand Up @@ -1279,6 +1283,14 @@ private static void executeCheckSig(Transaction txContainingThis, int index, Scr
if (stack.size() < 2)
throw new ScriptException("Attempted OP_CHECKSIG(VERIFY) on a stack with size < 2");
byte[] pubKey = stack.pollLast();
if (pubKey.length == 20 && stack.getLast().length == 33) { // spreadcoin sign+pubkey+pubkeyhash
// make the DUP HASH160 x EQUALS here
if (stack.getLast().length < 70)
throw new ScriptException("bajvan!!!");
if (!Arrays.equals(Utils.sha256hash160(stack.getLast()), pubKey))
throw new ScriptException("OP_CHECKSIG(VERIFY): non-equal data");
pubKey = stack.pollLast();
}
byte[] sigBytes = stack.pollLast();

byte[] prog = script.getProgram();
Expand Down
Loading

0 comments on commit c305bc7

Please sign in to comment.