3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-02-11 17:55:53 +00:00

Added dependency on bitcoinj and removed code elements which should taken directly from bitcoinj.

Removed classes with no differences to bitcoinj.
Fixed packages.
This commit is contained in:
Ross Nicoll 2015-04-11 17:08:25 +01:00
parent 09c80d44ff
commit c129d3fc89
569 changed files with 223 additions and 132792 deletions

View File

@ -20,19 +20,19 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.dogecoin</groupId>
<artifactId>dogecoinj-parent</artifactId>
<groupId>org.altcoinj</groupId>
<artifactId>altcoinj-parent</artifactId>
<version>0.13-SNAPSHOT</version>
</parent>
<artifactId>dogecoinj-core</artifactId>
<artifactId>altcoinj-core</artifactId>
<name>dogecoinj</name>
<description>A Java Dogecoin library</description>
<name>altcoinj</name>
<description>Extension library to bitcoinj to add altcoin support</description>
<packaging>jar</packaging>
<url>https://github.com/langerhans/dogecoinj-new</url>
<url>https://altcoinj.github.io</url>
<licenses>
<license>
@ -45,8 +45,8 @@
<!-- Dummy block to make Maven Central happy: authors list is in AUTHORS -->
<developers>
<developer>
<name>The bitcoinj team. Port to Dogecoin by the Dogecoin developers</name>
<email>info@dogecoin.com</email>
<name>The altcoinj team</name>
<email>ross@dogecoin.com</email>
</developer>
</developers>
@ -136,6 +136,7 @@
<link>http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/</link>
</links>
<detectJavaApiLink/>
<quiet>true</quiet>
</configuration>
</plugin>
@ -164,8 +165,10 @@
<!-- Format is URN of groupId:artifactId:version:type:classifier:scope:hash -->
<!-- classifier is "null" if not present -->
<urns>
<urn>com.dogecoin:orchid:1.1:jar:null:compile:393d53cad40f32f1c00a717326deeb4bde8ee57b</urn>
<urn>cglib:cglib-nodep:2.2:jar:null:test:59afed7ab65e7ec6585d5bc60556c3cbd203532b</urn>
<urn>com.fasterxml.jackson.core:jackson-annotations:2.4.0:jar:null:test:d6a66c7a5f01cf500377bd669507a08cfeba882a</urn>
<urn>com.fasterxml.jackson.core:jackson-core:2.4.2:jar:null:test:ceb72830d95c512b4b300a38f29febc85bdf6e4b</urn>
<urn>com.fasterxml.jackson.core:jackson-databind:2.4.2:jar:null:test:8e31266a272ad25ac4c089734d93e8d811652c1f</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>
<urn>com.google.protobuf:protobuf-java:2.5.0:jar:null:compile:a10732c76bfacdbd633a7eb0f7968b1059a65dfa</urn>
@ -173,31 +176,30 @@
<urn>com.lambdaworks:scrypt:1.4.0:jar:null:compile:906506b74f30c8c20bccd9ed4a11112d8941fe87</urn>
<urn>com.madgag.spongycastle:core:1.51.0.0:jar:null:compile:0f642963312ea0e615ad65f28adc5a5b3a2a0862</urn>
<urn>junit:junit:4.11:jar:null:test:4e031bb61df09069aeb2bffb4019e7a5034a4ee0</urn>
<urn>mysql:mysql-connector-java:5.1.33:jar:null:compile:8af455a9a3267e6664cafc87ace71a4e4ef02837</urn>
<urn>net.jcip:jcip-annotations:1.0:jar:null:compile:afba4942caaeaf46aab0b976afd57cc7c181467e</urn>
<urn>org.apache.maven.plugins:maven-clean-plugin:2.5:maven-plugin:null:runtime:75653decaefa85ca8114ff3a4f869bb2ee6d605d</urn>
<urn>org.apache.maven.plugins:maven-compiler-plugin:3.1:maven-plugin:null:runtime:9977a8d04e75609cf01badc4eb6a9c7198c4c5ea</urn>
<urn>org.apache.maven.plugins:maven-dependency-plugin:2.8:maven-plugin:null:runtime:04c8dedf3d9b2a3f45f3daa93e11ca547d2063ca</urn>
<urn>org.apache.maven.plugins:maven-deploy-plugin:2.7:maven-plugin:null:runtime:6dadfb75679ca010b41286794f737088ebfe12fd</urn>
<urn>org.apache.maven.plugins:maven-enforcer-plugin:1.2:maven-plugin:null:runtime:6b755a9a0d618f8f57c0b5c4a0737a012e710a46</urn>
<urn>org.apache.maven.plugins:maven-install-plugin:2.5.1:maven-plugin:null:runtime:b6f5a4b621b9c26699c8deadb20fdc35ce568e35</urn>
<urn>org.apache.maven.plugins:maven-jar-plugin:2.5:maven-plugin:null:runtime:344d667f5ec8b90d03d698d096a1147672fc522f</urn>
<urn>org.apache.maven.plugins:maven-javadoc-plugin:2.9.1:maven-plugin:null:runtime:95ea7abf00e37e08bd927bf7e448c1e7fe4c6cb9</urn>
<urn>org.apache.maven.plugins:maven-resources-plugin:2.6:maven-plugin:null:runtime:dd093ff6a4b680eae7ae83b5ab04310249fc6590</urn>
<urn>org.apache.maven.plugins:maven-clean-plugin:2.6.1:maven-plugin:null:runtime:bfdf7d6c2f8fc8759457e9d54f458ba56ac7b30f</urn>
<urn>org.apache.maven.plugins:maven-compiler-plugin:3.2:maven-plugin:null:runtime:aec10f274ac07fafab8906cb1aa69669d753b2c2</urn>
<urn>org.apache.maven.plugins:maven-dependency-plugin:2.10:maven-plugin:null:runtime:af87ceeb71c6499147c5d27f74c9317bf707538e</urn>
<urn>org.apache.maven.plugins:maven-deploy-plugin:2.8.2:maven-plugin:null:runtime:3c2d83ecd387e9843142ae92a0439792c1500319</urn>
<urn>org.apache.maven.plugins:maven-enforcer-plugin:1.0:maven-plugin:null:runtime:ad032b7593576e9fe9305c73865633e163895b29</urn>
<urn>org.apache.maven.plugins:maven-install-plugin:2.5.2:maven-plugin:null:runtime:8a67631619fc3c1d1f036e59362ddce71e1e496f</urn>
<urn>org.apache.maven.plugins:maven-jar-plugin:2.6:maven-plugin:null:runtime:618f08d0fcdd3929af846ef1b65503b5904f93e3</urn>
<urn>org.apache.maven.plugins:maven-javadoc-plugin:2.10.2:maven-plugin:null:runtime:5f391697fa85cecc7e5bac7ce5a6f9d056a58ba3</urn>
<urn>org.apache.maven.plugins:maven-resources-plugin:2.7:maven-plugin:null:runtime:94af11389943a480ecec7db01b4ded1b9cdf57c5</urn>
<urn>org.apache.maven.plugins:maven-shade-plugin:2.3:maven-plugin:null:runtime:d136adc7abccc9c12adcad6ae7a9bc51b2b7184b</urn>
<urn>org.apache.maven.plugins:maven-site-plugin:3.3:maven-plugin:null:runtime:77ba1752b1ac4c4339d6f11554800960a56a4ae1</urn>
<urn>org.apache.maven.plugins:maven-source-plugin:2.1.2:maven-plugin:null:runtime:35154aa8e6e0e84c2b5c10c3d5220d65670ba984</urn>
<urn>org.apache.maven.plugins:maven-surefire-plugin:2.12.4:maven-plugin:null:runtime:2b435f7f77777d2e62354fdc690da3f1dc47a26b</urn>
<urn>org.codehaus.mojo:cobertura-maven-plugin:2.6:maven-plugin:null:runtime:5204735a0642b42f5647d8ec876d4301e328c0d5</urn>
<urn>org.apache.maven.plugins:maven-site-plugin:3.4:maven-plugin:null:runtime:659cd5f1dd8bff554cf52603339494cbf7f283c5</urn>
<urn>org.apache.maven.plugins:maven-source-plugin:2.4:maven-plugin:null:runtime:46f0d7f7823d729ba300d3f8929900c7e9cb5ac0</urn>
<urn>org.apache.maven.plugins:maven-surefire-plugin:2.18.1:maven-plugin:null:runtime:402fd3066fd6d85ea4a1a3e7cd82a7e35037e6e8</urn>
<urn>org.easymock:easymock:3.0:jar:null:test:f28a4c31c330f95c9acbf1108cea19952b5c496f</urn>
<urn>org.eluder.coveralls:coveralls-maven-plugin:3.1.0:maven-plugin:null:runtime:ca9d2915e2b1e99f15c9f54ad653eda893d42a69</urn>
<urn>org.hamcrest:hamcrest-core:1.3:jar:null:test:42a25dc3219429f0e5d060061f71acb49bf010a0</urn>
<urn>org.jacoco:jacoco-maven-plugin:0.7.4.201502262128:maven-plugin:null:runtime:ee12ed04db135c74d0ae99e9c4e4754ee1582edb</urn>
<urn>org.objenesis:objenesis:1.2:jar:null:test:bfcb0539a071a4c5a30690388903ac48c0667f2a</urn>
<urn>org.slf4j:slf4j-api:1.7.6:jar:null:compile:562424e36df3d2327e8e9301a76027fca17d54ea</urn>
<urn>org.slf4j:slf4j-jdk14:1.7.6:jar:null:test:1a3301a32ea7d90c3d33e9d60edbfdc9589fc748</urn>
<url>com.fasterxml.jackson.core:jackson-databind:2.4.2:jar:null:test:8e31266a272ad25ac4c089734d93e8d811652c1f</url>
<url>com.fasterxml.jackson.core:jackson-core:2.4.2:jar:null:test:ceb72830d95c512b4b300a38f29febc85bdf6e4b</url>
<url>com.fasterxml.jackson.core:jackson-annotations:2.4.2:jar:null:test:6bb52af09372d5064206d47d7887d41671f00f7d</url>
<urn>org.jacoco:jacoco-maven-plugin:0.7.2.201409121644:maven-plugin:null:runtime:b2cb310459d082db505fdfa66dbadd4d8bac8e34</urn>
<urn>org.eluder.coveralls:coveralls-maven-plugin:3.0.1:maven-plugin:null:runtime:3907ee5cf1e5c85af7bb90e486ce4c7b1408a552</urn>
<urn>org.sonatype.plugins:nexus-staging-maven-plugin:1.6.5:maven-plugin:null:runtime:455ca2aa8cd14a06608f1538bd6a1efd09561563</urn>
<urn>postgresql:postgresql:9.1-901.jdbc4:jar:null:compile:153f2f92a786f12fc111d0111f709012df87c808</urn>
<!-- A check for the rules themselves -->
<urn>uk.co.froot.maven.enforcer:digest-enforcer-rules:0.0.1:jar:null:runtime:16a9e04f3fe4bb143c42782d07d5faf65b32106f</urn>
</urns>
@ -254,7 +256,7 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.2.201409121644</version>
<version>0.7.4.201502262128</version>
<configuration>
<excludes>
<exclude>**/Protos*.class</exclude> <!-- Exclude generated protobuf classes -->
@ -298,17 +300,17 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<argLine>${surefireArgLine}</argLine> <!-- This is required for code coverage to work. -->
<runOrder>alphabetical</runOrder>
</configuration>
</plugin>
<!-- Coveralls is a online code coverage tool, you can track code coverage here: https://coveralls.io/r/bitcoinj/bitcoinj -->
<!-- Coveralls is a online code coverage tool, you can track code coverage here: https://coveralls.io/r/altcoinj/altcoinj -->
<plugin>
<groupId>org.eluder.coveralls</groupId>
<artifactId>coveralls-maven-plugin</artifactId>
<version>3.0.1</version>
<version>3.1.0</version>
</plugin>
<!-- Create a bundled executable test jar that runs the regtester/pulltester.
@ -334,8 +336,8 @@
<artifactItems>
<artifactItem>
<outputDirectory>target/test-classes/</outputDirectory>
<groupId>com.dogecoin</groupId>
<artifactId>dogecoinj-core</artifactId>
<groupId>org.altcoinj</groupId>
<artifactId>altcoinj-core</artifactId>
<version>${project.version}</version>
</artifactItem>
</artifactItems>
@ -356,32 +358,6 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>test-jar</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>com.dogecoin.dogecoinj.core.BitcoindComparisonTool</mainClass>
<addClasspath>false</addClasspath>
</manifest>
</archive>
<finalName>pull</finalName> <!-- becomes pull-tests.jar on disk (hacky) -->
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
@ -398,7 +374,7 @@
<version>3.0</version>
<scope>test</scope>
</dependency>
<!-- dogecoinj consumers are expected to provide their own SLF4J adapters
<!-- altcoinj consumers are expected to provide their own SLF4J adapters
such as logback, slf4j-log4j12, slf4j-jcl and so on
see http://www.slf4j.org/faq.html -->
<dependency>
@ -466,10 +442,21 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.dogecoin</groupId>
<groupId>org.fusesource.leveldbjni</groupId>
<artifactId>leveldbjni-all</artifactId>
<version>1.8</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.bitcoinj</groupId>
<artifactId>orchid</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.bitcoinj</groupId>
<artifactId>bitcoinj-core</artifactId>
<version>0.13-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

View File

@ -1,48 +0,0 @@
/**
* Copyright 2013 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import java.util.List;
/**
* Default no-op implementation of {@link BlockChainListener}.
*/
public class AbstractBlockChainListener implements BlockChainListener {
@Override
public void notifyNewBestBlock(StoredBlock block) throws VerificationException {
}
@Override
public void reorganize(StoredBlock splitPoint, List<StoredBlock> oldBlocks, List<StoredBlock> newBlocks) throws VerificationException {
}
@Override
public boolean isTransactionRelevant(Transaction tx) throws ScriptException {
return false;
}
@Override
public void receiveFromBlock(Transaction tx, StoredBlock block, BlockChain.NewBlockType blockType,
int relativityOffset) throws VerificationException {
}
@Override
public boolean notifyTransactionIsInBlock(Sha256Hash txHash, StoredBlock block, BlockChain.NewBlockType blockType,
int relativityOffset) throws VerificationException {
return false;
}
}

View File

@ -1,60 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import java.util.List;
import java.util.Set;
/**
* Convenience implementation of {@link PeerEventListener}.
*/
public class AbstractPeerEventListener implements PeerEventListener {
@Override
public void onPeersDiscovered(Set<PeerAddress> peerAddresses) {
}
@Override
public void onBlocksDownloaded(Peer peer, Block block, int blocksLeft) {
}
@Override
public void onChainDownloadStarted(Peer peer, int blocksLeft) {
}
@Override
public void onPeerConnected(Peer peer, int peerCount) {
}
@Override
public void onPeerDisconnected(Peer peer, int peerCount) {
}
@Override
public Message onPreMessageReceived(Peer peer, Message m) {
// Just pass the message right through for further processing.
return m;
}
@Override
public void onTransaction(Peer peer, Transaction t) {
}
@Override
public List<Message> getData(Peer peer, GetDataMessage m) {
return null;
}
}

View File

@ -1,65 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import com.dogecoin.dogecoinj.script.Script;
import com.dogecoin.dogecoinj.wallet.AbstractKeyChainEventListener;
import java.util.List;
/**
* Convenience implementation of {@link WalletEventListener}.
*/
public abstract class AbstractWalletEventListener extends AbstractKeyChainEventListener implements WalletEventListener {
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
onChange();
}
@Override
public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
onChange();
}
@Override
public void onReorganize(Wallet wallet) {
onChange();
}
@Override
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) {
onChange();
}
@Override
public void onKeysAdded(List<ECKey> keys) {
onChange();
}
@Override
public void onScriptsChanged(Wallet wallet, List<Script> scripts, boolean isAddingScripts) {
onChange();
}
@Override
public void onWalletChanged(Wallet wallet) {
onChange();
}
public void onChange() {
}
}

View File

@ -1,179 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Giannis Dzegoutanis
*
* 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 com.dogecoin.dogecoinj.core;
import com.dogecoin.dogecoinj.params.Networks;
import com.dogecoin.dogecoinj.script.Script;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* <p>A Bitcoin address looks like 1MsScoe2fTJoq4ZPdQgqyhgWeoNamYPevy and is derived from an elliptic curve public key
* plus a set of network parameters. Not to be confused with a {@link PeerAddress} or {@link AddressMessage}
* which are about network (TCP) addresses.</p>
*
* <p>A standard address is built by taking the RIPE-MD160 hash of the public key bytes, with a version prefix and a
* checksum suffix, then encoding it textually as base58. The version prefix is used to both denote the network for
* which the address is valid (see {@link NetworkParameters}, and also to indicate how the bytes inside the address
* should be interpreted. Whilst almost all addresses today are hashes of public keys, another (currently unsupported
* type) can contain a hash of a script instead.</p>
*/
public class Address extends VersionedChecksummedBytes {
/**
* An address is a RIPEMD160 hash of a public key, therefore is always 160 bits or 20 bytes.
*/
public static final int LENGTH = 20;
transient final NetworkParameters params;
/**
* Construct an address from parameters, the address version, and the hash160 form. Example:<p>
*
* <pre>new Address(MainNetParams.get(), NetworkParameters.getAddressHeader(), Hex.decode("4a22c3c4cbb31e4d03b15550636762bda0baf85a"));</pre>
*/
public Address(NetworkParameters params, int version, byte[] hash160) throws WrongNetworkException {
super(version, hash160);
checkNotNull(params);
checkArgument(hash160.length == 20, "Addresses are 160-bit hashes, so you must provide 20 bytes");
if (!isAcceptableVersion(params, version))
throw new WrongNetworkException(version, params.getAcceptableAddressCodes());
this.params = params;
}
/** Returns an Address that represents the given P2SH script hash. */
public static Address fromP2SHHash(NetworkParameters params, byte[] hash160) {
try {
return new Address(params, params.getP2SHHeader(), hash160);
} catch (WrongNetworkException e) {
throw new RuntimeException(e); // Cannot happen.
}
}
/** Returns an Address that represents the script hash extracted from the given scriptPubKey */
public static Address fromP2SHScript(NetworkParameters params, Script scriptPubKey) {
checkArgument(scriptPubKey.isPayToScriptHash(), "Not a P2SH script");
return fromP2SHHash(params, scriptPubKey.getPubKeyHash());
}
/**
* Construct an address from parameters and the hash160 form. Example:<p>
*
* <pre>new Address(MainNetParams.get(), Hex.decode("4a22c3c4cbb31e4d03b15550636762bda0baf85a"));</pre>
*/
public Address(NetworkParameters params, byte[] hash160) {
super(params.getAddressHeader(), hash160);
checkArgument(hash160.length == 20, "Addresses are 160-bit hashes, so you must provide 20 bytes");
this.params = params;
}
/**
* Construct an address from parameters and the standard "human readable" form. Example:<p>
*
* <pre>new Address(MainNetParams.get(), "17kzeh4N8g49GFvdDzSf8PjaPfyoD1MndL");</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"
* @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 mainnet)
*/
public Address(@Nullable NetworkParameters params, String address) throws AddressFormatException {
super(address);
if (params != null) {
if (!isAcceptableVersion(params, version)) {
throw new WrongNetworkException(version, params.getAcceptableAddressCodes());
}
this.params = params;
} else {
NetworkParameters paramsFound = null;
for (NetworkParameters p : Networks.get()) {
if (isAcceptableVersion(p, version)) {
paramsFound = p;
break;
}
}
if (paramsFound == null)
throw new AddressFormatException("No network found for " + address);
this.params = paramsFound;
}
}
/** The (big endian) 20 byte hash that is the core of a Bitcoin address. */
public byte[] getHash160() {
return bytes;
}
/*
* Returns true if this address is a Pay-To-Script-Hash (P2SH) address.
* See also https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki: Address Format for pay-to-script-hash
*/
public boolean isP2SHAddress() {
final NetworkParameters parameters = getParameters();
return parameters != null && this.version == parameters.p2shHeader;
}
/**
* Examines the version byte of the address and attempts to find a matching NetworkParameters. If you aren't sure
* which network the address is intended for (eg, it was provided by a user), you can use this to decide if it is
* compatible with the current wallet. You should be able to handle a null response from this method. Note that the
* parameters returned is not necessarily the same as the one the Address was created with.
*
* @return a NetworkParameters representing the network the address is intended for.
*/
public NetworkParameters getParameters() {
return params;
}
/**
* Given an address, examines the version byte and attempts to find a matching NetworkParameters. If you aren't sure
* which network the address is intended for (eg, it was provided by a user), you can use this to decide if it is
* compatible with the current wallet.
* @return a NetworkParameters of the address
* @throws AddressFormatException if the string wasn't of a known version
*/
public static NetworkParameters getParametersFromAddress(String address) throws AddressFormatException {
try {
return new Address(null, address).getParameters();
} catch (WrongNetworkException e) {
throw new RuntimeException(e); // Cannot happen.
}
}
/**
* Check if a given address version is valid given the NetworkParameters.
*/
private static boolean isAcceptableVersion(NetworkParameters params, int version) {
for (int v : params.getAcceptableAddressCodes()) {
if (version == v) {
return true;
}
}
return false;
}
/**
* This implementation narrows the return type to <code>Address</code>.
*/
@Override
public Address clone() throws CloneNotSupportedException {
return (Address) super.clone();
}
}

View File

@ -1,28 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
@SuppressWarnings("serial")
public class AddressFormatException extends Exception {
public AddressFormatException() {
super();
}
public AddressFormatException(String message) {
super(message);
}
}

View File

@ -1,154 +0,0 @@
package com.dogecoin.dogecoinj.core;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Represents an "addr" message on the P2P network, which contains broadcast IP addresses of other peers. This is
* one of the ways peers can find each other without using the DNS or IRC discovery mechanisms. However storing and
* using addr messages is not presently implemented.
*/
public class AddressMessage extends Message {
private static final long serialVersionUID = 8058283864924679460L;
private static final long MAX_ADDRESSES = 1024;
private List<PeerAddress> addresses;
private transient long numAddresses = -1;
/**
* Contruct a new 'addr' message.
* @param params NetworkParameters object.
* @param offset The location of the first payload byte within the array.
* @param parseLazy Whether to perform a full parse immediately or delay until a read is requested.
* @param parseRetain Whether to retain the backing byte array for quick reserialization.
* If true and the backing byte array is invalidated due to modification of a field then
* the cached bytes may be repopulated and retained if the message is serialized again in the future.
* @param length The length of message if known. Usually this is provided when deserializing of the wire
* as the length will be provided as part of the header. If unknown then set to Message.UNKNOWN_LENGTH
* @throws ProtocolException
*/
AddressMessage(NetworkParameters params, byte[] payload, int offset, boolean parseLazy, boolean parseRetain, int length) throws ProtocolException {
super(params, payload, offset, parseLazy, parseRetain, length);
}
/**
* Contruct a new 'addr' message.
* @param params NetworkParameters object.
* @param parseLazy Whether to perform a full parse immediately or delay until a read is requested.
* @param parseRetain Whether to retain the backing byte array for quick reserialization.
* If true and the backing byte array is invalidated due to modification of a field then
* the cached bytes may be repopulated and retained if the message is serialized again in the future.
* @param length The length of message if known. Usually this is provided when deserializing of the wire
* as the length will be provided as part of the header. If unknown then set to Message.UNKNOWN_LENGTH
* @throws ProtocolException
*/
AddressMessage(NetworkParameters params, byte[] payload, boolean parseLazy, boolean parseRetain, int length) throws ProtocolException {
super(params, payload, 0, parseLazy, parseRetain, length);
}
AddressMessage(NetworkParameters params, byte[] payload, int offset) throws ProtocolException {
super(params, payload, offset, false, false, UNKNOWN_LENGTH);
}
AddressMessage(NetworkParameters params, byte[] payload) throws ProtocolException {
super(params, payload, 0, false, false, UNKNOWN_LENGTH);
}
@Override
protected void parseLite() throws ProtocolException {
}
@Override
void parse() throws ProtocolException {
numAddresses = readVarInt();
// Guard against ultra large messages that will crash us.
if (numAddresses > MAX_ADDRESSES)
throw new ProtocolException("Address message too large.");
addresses = new ArrayList<PeerAddress>((int) numAddresses);
for (int i = 0; i < numAddresses; i++) {
PeerAddress addr = new PeerAddress(params, payload, cursor, protocolVersion, this, parseLazy, parseRetain);
addresses.add(addr);
cursor += addr.getMessageSize();
}
length = cursor - offset;
}
/* (non-Javadoc)
* @see Message#bitcoinSerializeToStream(java.io.OutputStream)
*/
@Override
void bitcoinSerializeToStream(OutputStream stream) throws IOException {
if (addresses == null)
return;
stream.write(new VarInt(addresses.size()).encode());
for (PeerAddress addr : addresses) {
addr.bitcoinSerialize(stream);
}
}
@Override
public int getMessageSize() {
if (length != UNKNOWN_LENGTH)
return length;
if (addresses != null) {
length = new VarInt(addresses.size()).getSizeInBytes();
// The 4 byte difference is the uint32 timestamp that was introduced in version 31402
length += addresses.size() * (protocolVersion > 31402 ? PeerAddress.MESSAGE_SIZE : PeerAddress.MESSAGE_SIZE - 4);
}
return length;
}
/**
* AddressMessage cannot cache checksum in non-retain mode due to dynamic time being used.
*/
@Override
void setChecksum(byte[] checksum) {
if (parseRetain)
super.setChecksum(checksum);
else
this.checksum = null;
}
/**
* @return An unmodifiableList view of the backing List of addresses. Addresses contained within the list may be safely modified.
*/
public List<PeerAddress> getAddresses() {
maybeParse();
return Collections.unmodifiableList(addresses);
}
public void addAddress(PeerAddress address) {
unCache();
maybeParse();
address.setParent(this);
addresses.add(address);
if (length == UNKNOWN_LENGTH)
getMessageSize();
else
length += address.getMessageSize();
}
public void removeAddress(int index) {
unCache();
PeerAddress address = addresses.remove(index);
address.setParent(null);
if (length == UNKNOWN_LENGTH)
getMessageSize();
else
length -= address.getMessageSize();
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("addr: ");
for (PeerAddress a : addresses) {
builder.append(a.toString());
builder.append(" ");
}
return builder.toString();
}
}

View File

@ -1,255 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
/**
* Alerts are signed messages that are broadcast on the peer-to-peer network if they match a hard-coded signing key.
* The private keys are held by a small group of core Bitcoin developers, and alerts may be broadcast in the event of
* an available upgrade or a serious network problem. Alerts have an expiration time, data that specifies what
* set of software versions it matches and the ability to cancel them by broadcasting another type of alert.<p>
*
* The right course of action on receiving an alert is usually to either ensure a human will see it (display on screen,
* log, email), or if you decide to use alerts for notifications that are specific to your app in some way, to parse it.
* For example, you could treat it as an upgrade notification specific to your app. Satoshi designed alerts to ensure
* that software upgrades could be distributed independently of a hard-coded website, in order to allow everything to
* be purely peer-to-peer. You don't have to use this of course, and indeed it often makes more sense not to.<p>
*
* Before doing anything with an alert, you should check {@link AlertMessage#isSignatureValid()}.
*/
public class AlertMessage extends Message {
private byte[] content;
private byte[] signature;
// See the getters for documentation of what each field means.
private long version = 1;
private Date relayUntil;
private Date expiration;
private long id;
private long cancel;
private Set<Long> cancelSet;
private long minVer, maxVer;
private Set<String> matchingSubVers;
private long priority;
private String comment, statusBar, reserved;
// Chosen arbitrarily to avoid memory blowups.
private static final long MAX_SET_SIZE = 100;
public AlertMessage(NetworkParameters params, byte[] payloadBytes) throws ProtocolException {
super(params, payloadBytes, 0);
}
@Override
public String toString() {
return "ALERT: " + getStatusBar();
}
@Override
void parse() throws ProtocolException {
// Alerts are formatted in two levels. The top level contains two byte arrays: a signature, and a serialized
// data structure containing the actual alert data.
int startPos = cursor;
content = readByteArray();
signature = readByteArray();
// Now we need to parse out the contents of the embedded structure. Rewind back to the start of the message.
cursor = startPos;
readVarInt(); // Skip the length field on the content array.
// We're inside the embedded structure.
version = readUint32();
// Read the timestamps. Bitcoin uses seconds since the epoch.
relayUntil = new Date(readUint64().longValue() * 1000);
expiration = new Date(readUint64().longValue() * 1000);
id = readUint32();
cancel = readUint32();
// Sets are serialized as <len><item><item><item>....
long cancelSetSize = readVarInt();
if (cancelSetSize < 0 || cancelSetSize > MAX_SET_SIZE) {
throw new ProtocolException("Bad cancel set size: " + cancelSetSize);
}
// Using a hashset here is very inefficient given that this will normally be only one item. But Java doesn't
// make it easy to do better. What we really want is just an array-backed set.
cancelSet = new HashSet<Long>((int)cancelSetSize);
for (long i = 0; i < cancelSetSize; i++) {
cancelSet.add(readUint32());
}
minVer = readUint32();
maxVer = readUint32();
// Read the subver matching set.
long subverSetSize = readVarInt();
if (subverSetSize < 0 || subverSetSize > MAX_SET_SIZE) {
throw new ProtocolException("Bad subver set size: " + subverSetSize);
}
matchingSubVers = new HashSet<String>((int)subverSetSize);
for (long i = 0; i < subverSetSize; i++) {
matchingSubVers.add(readStr());
}
priority = readUint32();
comment = readStr();
statusBar = readStr();
reserved = readStr();
length = cursor - offset;
}
/**
* Returns true if the digital signature attached to the message verifies. Don't do anything with the alert if it
* doesn't verify, because that would allow arbitrary attackers to spam your users.
*/
public boolean isSignatureValid() {
return ECKey.verify(Utils.doubleDigest(content), signature, params.getAlertSigningKey());
}
@Override
protected void parseLite() throws ProtocolException {
// Do nothing, lazy parsing isn't useful for alerts.
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Field accessors.
/**
* The time at which the alert should stop being broadcast across the network. Note that you can still receive
* the alert after this time from other nodes if the alert still applies to them or to you.
*/
public Date getRelayUntil() {
return relayUntil;
}
public void setRelayUntil(Date relayUntil) {
this.relayUntil = relayUntil;
}
/**
* The time at which the alert ceases to be relevant. It should not be presented to the user or app administrator
* after this time.
*/
public Date getExpiration() {
return expiration;
}
public void setExpiration(Date expiration) {
this.expiration = expiration;
}
/**
* The numeric identifier of this alert. Each alert should have a unique ID, but the signer can choose any number.
* If an alert is broadcast with a cancel field higher than this ID, this alert is considered cancelled.
* @return uint32
*/
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
/**
* A marker that results in any alerts with an ID lower than this value to be considered cancelled.
* @return uint32
*/
public long getCancel() {
return cancel;
}
public void setCancel(long cancel) {
this.cancel = cancel;
}
/**
* The inclusive lower bound on software versions that are considered for the purposes of this alert. The Satoshi
* client compares this against a protocol version field, but as long as the subVer field is used to restrict it your
* alerts could use any version numbers.
* @return uint32
*/
public long getMinVer() {
return minVer;
}
public void setMinVer(long minVer) {
this.minVer = minVer;
}
/**
* The inclusive upper bound on software versions considered for the purposes of this alert. The Satoshi
* client compares this against a protocol version field, but as long as the subVer field is used to restrict it your
* alerts could use any version numbers.
* @return
*/
public long getMaxVer() {
return maxVer;
}
public void setMaxVer(long maxVer) {
this.maxVer = maxVer;
}
/**
* Provides an integer ordering amongst simultaneously active alerts.
* @return uint32
*/
public long getPriority() {
return priority;
}
public void setPriority(long priority) {
this.priority = priority;
}
/**
* This field is unused. It is presumably intended for the author of the alert to provide a justification for it
* visible to protocol developers but not users.
*/
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
/**
* A string that is intended to display in the status bar of the official GUI client. It contains the user-visible
* message. English only.
*/
public String getStatusBar() {
return statusBar;
}
public void setStatusBar(String statusBar) {
this.statusBar = statusBar;
}
/**
* This field is never used.
*/
public String getReserved() {
return reserved;
}
public void setReserved(String reserved) {
this.reserved = reserved;
}
public long getVersion() {
return version;
}
}

View File

@ -1,141 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
/**
* This is the code to deserialize the AuxPoW header data
*/
public class AuxPoWMessage extends Message {
private static final Logger log = LoggerFactory.getLogger(AuxPoWMessage.class);
private AuxHeader header;
public AuxPoWMessage(byte[] payload, int cursor) throws ProtocolException {
this.payload = payload;
this.cursor = cursor;
this.header = new AuxHeader();
}
@Override
void parse() throws ProtocolException {
header.parentCoinbaseVerion = readUint32();
header.parentCoinbaseTxInCount = readVarInt();
header.parentCointbasePrevOut = readBytes(36); // Always the same on coinbase
header.parentCoinbaseInScriptLength = readVarInt();
header.parentCoinbaseInScript = readBytes((int) header.parentCoinbaseInScriptLength); // Script length is limited so this cast should be fine.
header.parentCoinBaseSequenceNumber = readUint32();
header.parentCoinbaseTxOutCount = readVarInt();
header.parentCoinbaseOuts = new ArrayList<AuxCoinbaseOut>();
for (int i = 0; i < header.parentCoinbaseTxOutCount; i++) {
AuxCoinbaseOut out = new AuxCoinbaseOut();
out.amount = readInt64();
out.scriptLength = readVarInt();
out.script = readBytes((int) out.scriptLength); // Script length is limited so this cast should be fine.
header.parentCoinbaseOuts.add(out);
}
header.parentCoinbaseLockTime = readUint32();
header.parentBlockHeaderHash = readHash();
header.numOfCoinbaseLinks = readVarInt();
header.coinbaseLinks = new ArrayList<Sha256Hash>();
for (int i = 0; i < header.numOfCoinbaseLinks; i++) {
header.coinbaseLinks.add(readHash());
}
header.coinbaseBranchBitmask = readUint32();
header.numOfAuxChainLinks = readVarInt();
header.auxChainLinks = new ArrayList<Sha256Hash>();
for (int i = 0; i < header.numOfAuxChainLinks; i++) {
header.auxChainLinks.add(readHash());
}
header.auxChainBranchBitmask = readUint32();
header.parentBlockVersion = readUint32();
header.parentBlockPrev = readHash();
header.parentBlockMerkleRoot = readHash();
header.parentBlockTime = readUint32();
header.parentBlockBits = readUint32();
header.parentBlockNonce = readUint32();
}
@Override
protected void parseLite() throws ProtocolException {
// noop
}
public byte[] constructParentHeader() {
ByteArrayOutputStream stream = new UnsafeByteArrayOutputStream(Block.HEADER_SIZE);
try {
Utils.uint32ToByteStreamLE(header.parentBlockVersion, stream);
stream.write(Utils.reverseBytes(header.parentBlockPrev.getBytes()));
stream.write(Utils.reverseBytes(header.parentBlockMerkleRoot.getBytes()));
Utils.uint32ToByteStreamLE(header.parentBlockTime, stream);
Utils.uint32ToByteStreamLE(header.parentBlockBits, stream);
Utils.uint32ToByteStreamLE(header.parentBlockNonce, stream);
} catch (IOException e) {
throw new RuntimeException(); // Can't actually happen
}
return stream.toByteArray();
}
public class AuxHeader {
// Parent coinbase
public long parentCoinbaseVerion;
public long parentCoinbaseTxInCount;
public byte[] parentCointbasePrevOut;
public long parentCoinbaseInScriptLength;
public byte[] parentCoinbaseInScript;
public long parentCoinBaseSequenceNumber;
public long parentCoinbaseTxOutCount;
public ArrayList<AuxCoinbaseOut> parentCoinbaseOuts;
public long parentCoinbaseLockTime;
// Coinbase link
public Sha256Hash parentBlockHeaderHash;
public long numOfCoinbaseLinks;
public ArrayList<Sha256Hash> coinbaseLinks;
public long coinbaseBranchBitmask;
// Aux chanin link
public long numOfAuxChainLinks;
public ArrayList<Sha256Hash> auxChainLinks;
public long auxChainBranchBitmask;
// Parent block header
public long parentBlockVersion;
public Sha256Hash parentBlockPrev;
public Sha256Hash parentBlockMerkleRoot;
public long parentBlockTime;
public long parentBlockBits;
public long parentBlockNonce;
}
public class AuxCoinbaseOut {
public long amount;
public long scriptLength;
public byte[] script;
}
}

View File

@ -1,204 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.util.Arrays;
/**
* <p>Base58 is a way to encode Bitcoin addresses as numbers and letters. Note that this is not the same base58 as used by
* Flickr, which you may see reference to around the internet.</p>
*
* <p>You may instead wish to work with {@link VersionedChecksummedBytes}, which adds support for testing the prefix
* and suffix bytes commonly found in addresses.</p>
*
* <p>Satoshi says: why base-58 instead of standard base-64 encoding?<p>
*
* <ul>
* <li>Don't want 0OIl characters that look the same in some fonts and
* could be used to create visually identical looking account numbers.</li>
* <li>A string with non-alphanumeric characters is not as easily accepted as an account number.</li>
* <li>E-mail usually won't line-break if there's no punctuation to break at.</li>
* <li>Doubleclicking selects the whole number as one word if it's all alphanumeric.</li>
* </ul>
*/
public class Base58 {
public static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
private static final int[] INDEXES = new int[128];
static {
for (int i = 0; i < INDEXES.length; i++) {
INDEXES[i] = -1;
}
for (int i = 0; i < ALPHABET.length; i++) {
INDEXES[ALPHABET[i]] = i;
}
}
/** Encodes the given bytes in base58. No checksum is appended. */
public static String encode(byte[] input) {
if (input.length == 0) {
return "";
}
input = copyOfRange(input, 0, input.length);
// Count leading zeroes.
int zeroCount = 0;
while (zeroCount < input.length && input[zeroCount] == 0) {
++zeroCount;
}
// The actual encoding.
byte[] temp = new byte[input.length * 2];
int j = temp.length;
int startAt = zeroCount;
while (startAt < input.length) {
byte mod = divmod58(input, startAt);
if (input[startAt] == 0) {
++startAt;
}
temp[--j] = (byte) ALPHABET[mod];
}
// Strip extra '1' if there are some after decoding.
while (j < temp.length && temp[j] == ALPHABET[0]) {
++j;
}
// Add as many leading '1' as there were leading zeros.
while (--zeroCount >= 0) {
temp[--j] = (byte) ALPHABET[0];
}
byte[] output = copyOfRange(temp, j, temp.length);
try {
return new String(output, "US-ASCII");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e); // Cannot happen.
}
}
public static byte[] decode(String input) throws AddressFormatException {
if (input.length() == 0) {
return new byte[0];
}
byte[] input58 = new byte[input.length()];
// Transform the String to a base58 byte sequence
for (int i = 0; i < input.length(); ++i) {
char c = input.charAt(i);
int digit58 = -1;
if (c >= 0 && c < 128) {
digit58 = INDEXES[c];
}
if (digit58 < 0) {
throw new AddressFormatException("Illegal character " + c + " at " + i);
}
input58[i] = (byte) digit58;
}
// Count leading zeroes
int zeroCount = 0;
while (zeroCount < input58.length && input58[zeroCount] == 0) {
++zeroCount;
}
// The encoding
byte[] temp = new byte[input.length()];
int j = temp.length;
int startAt = zeroCount;
while (startAt < input58.length) {
byte mod = divmod256(input58, startAt);
if (input58[startAt] == 0) {
++startAt;
}
temp[--j] = mod;
}
// Do no add extra leading zeroes, move j to first non null byte.
while (j < temp.length && temp[j] == 0) {
++j;
}
return copyOfRange(temp, j - zeroCount, temp.length);
}
public static BigInteger decodeToBigInteger(String input) throws AddressFormatException {
return new BigInteger(1, decode(input));
}
/**
* Uses the checksum in the last 4 bytes of the decoded data to verify the rest are correct. The checksum is
* removed from the returned data.
*
* @throws AddressFormatException if the input is not base 58 or the checksum does not validate.
*/
public static byte[] decodeChecked(String input) throws AddressFormatException {
byte tmp [] = decode(input);
if (tmp.length < 4)
throw new AddressFormatException("Input too short");
byte[] bytes = copyOfRange(tmp, 0, tmp.length - 4);
byte[] checksum = copyOfRange(tmp, tmp.length - 4, tmp.length);
tmp = Utils.doubleDigest(bytes);
byte[] hash = copyOfRange(tmp, 0, 4);
if (!Arrays.equals(checksum, hash))
throw new AddressFormatException("Checksum does not validate");
return bytes;
}
//
// number -> number / 58, returns number % 58
//
private static byte divmod58(byte[] number, int startAt) {
int remainder = 0;
for (int i = startAt; i < number.length; i++) {
int digit256 = (int) number[i] & 0xFF;
int temp = remainder * 256 + digit256;
number[i] = (byte) (temp / 58);
remainder = temp % 58;
}
return (byte) remainder;
}
//
// number -> number / 256, returns number % 256
//
private static byte divmod256(byte[] number58, int startAt) {
int remainder = 0;
for (int i = startAt; i < number58.length; i++) {
int digit58 = (int) number58[i] & 0xFF;
int temp = remainder * 58 + digit58;
number58[i] = (byte) (temp / 256);
remainder = temp % 256;
}
return (byte) remainder;
}
private static byte[] copyOfRange(byte[] source, int from, int to) {
byte[] range = new byte[to - from];
System.arraycopy(source, from, range, 0, range.length);
return range;
}
}

View File

@ -1,328 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* 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 com.dogecoin.dogecoinj.core;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import static com.dogecoin.dogecoinj.core.Utils.*;
/**
* <p>Methods to serialize and de-serialize messages to the Bitcoin network format as defined in
* <a href="https://en.bitcoin.it/wiki/Protocol_specification">the protocol specification</a>.</p>
*
* <p>To be able to serialize and deserialize new Message subclasses the following criteria needs to be met.</p>
*
* <ul>
* <li>The proper Class instance needs to be mapped to its message name in the names variable below</li>
* <li>There needs to be a constructor matching: NetworkParameters params, byte[] payload</li>
* <li>Message.bitcoinSerializeToStream() needs to be properly subclassed</li>
* </ul>
*/
public class BitcoinSerializer {
private static final Logger log = LoggerFactory.getLogger(BitcoinSerializer.class);
private static final int COMMAND_LEN = 12;
private NetworkParameters params;
private boolean parseLazy = false;
private boolean parseRetain = false;
private static Map<Class<? extends Message>, String> names = new HashMap<Class<? extends Message>, String>();
static {
names.put(VersionMessage.class, "version");
names.put(InventoryMessage.class, "inv");
names.put(Block.class, "block");
names.put(GetDataMessage.class, "getdata");
names.put(Transaction.class, "tx");
names.put(AddressMessage.class, "addr");
names.put(Ping.class, "ping");
names.put(Pong.class, "pong");
names.put(VersionAck.class, "verack");
names.put(GetBlocksMessage.class, "getblocks");
names.put(GetHeadersMessage.class, "getheaders");
names.put(GetAddrMessage.class, "getaddr");
names.put(HeadersMessage.class, "headers");
names.put(BloomFilter.class, "filterload");
names.put(FilteredBlock.class, "merkleblock");
names.put(NotFoundMessage.class, "notfound");
names.put(MemoryPoolMessage.class, "mempool");
names.put(RejectMessage.class, "reject");
names.put(GetUTXOsMessage.class, "getutxos");
names.put(UTXOsMessage.class, "utxos");
}
/**
* Constructs a BitcoinSerializer with the given behavior.
*
* @param params networkParams used to create Messages instances and termining packetMagic
*/
public BitcoinSerializer(NetworkParameters params) {
this(params, false, false);
}
/**
* Constructs a BitcoinSerializer with the given behavior.
*
* @param params networkParams used to create Messages instances and termining packetMagic
* @param parseLazy deserialize messages in lazy mode.
* @param parseRetain retain the backing byte array of a message for fast reserialization.
*/
public BitcoinSerializer(NetworkParameters params, boolean parseLazy, boolean parseRetain) {
this.params = params;
this.parseLazy = parseLazy;
this.parseRetain = parseRetain;
}
/**
* Writes message to to the output stream.
*/
public void serialize(String name, byte[] message, OutputStream out) throws IOException {
byte[] header = new byte[4 + COMMAND_LEN + 4 + 4 /* checksum */];
uint32ToByteArrayBE(params.getPacketMagic(), header, 0);
// The header array is initialized to zero by Java so we don't have to worry about
// NULL terminating the string here.
for (int i = 0; i < name.length() && i < COMMAND_LEN; i++) {
header[4 + i] = (byte) (name.codePointAt(i) & 0xFF);
}
Utils.uint32ToByteArrayLE(message.length, header, 4 + COMMAND_LEN);
byte[] hash = doubleDigest(message);
System.arraycopy(hash, 0, header, 4 + COMMAND_LEN + 4, 4);
out.write(header);
out.write(message);
if (log.isDebugEnabled())
log.debug("Sending {} message: {}", name, HEX.encode(header) + HEX.encode(message));
}
/**
* Writes message to to the output stream.
*/
public void serialize(Message message, OutputStream out) throws IOException {
String name = names.get(message.getClass());
if (name == null) {
throw new Error("BitcoinSerializer doesn't currently know how to serialize " + message.getClass());
}
serialize(name, message.bitcoinSerialize(), out);
}
/**
* Reads a message from the given ByteBuffer and returns it.
*/
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
// - 12 byte command in ASCII
// - 4 byte payload size
// - 4 byte checksum
// - Payload data
//
// The checksum is the first 4 bytes of a SHA256 hash of the message payload. It isn't
// present for all messages, notably, the first one on a connection.
//
// Satoshi's implementation ignores garbage before the magic header bytes. We have to do the same because
// sometimes it sends us stuff that isn't part of any message.
seekPastMagicBytes(in);
BitcoinPacketHeader header = new BitcoinPacketHeader(in);
// Now try to read the whole message.
return deserializePayload(header, in);
}
/**
* Deserializes only the header in case packet meta data is needed before decoding
* the payload. This method assumes you have already called seekPastMagicBytes()
*/
public BitcoinPacketHeader deserializeHeader(ByteBuffer in) throws ProtocolException, IOException {
return new BitcoinPacketHeader(in);
}
/**
* Deserialize payload only. You must provide a header, typically obtained by calling
* {@link BitcoinSerializer#deserializeHeader}.
*/
public Message deserializePayload(BitcoinPacketHeader header, ByteBuffer in) throws ProtocolException, BufferUnderflowException {
byte[] payloadBytes = new byte[header.size];
in.get(payloadBytes, 0, header.size);
// Verify the checksum.
byte[] hash;
hash = doubleDigest(payloadBytes);
if (header.checksum[0] != hash[0] || header.checksum[1] != hash[1] ||
header.checksum[2] != hash[2] || header.checksum[3] != hash[3]) {
throw new ProtocolException("Checksum failed to verify, actual " +
HEX.encode(hash) +
" vs " + HEX.encode(header.checksum));
}
if (log.isDebugEnabled()) {
log.debug("Received {} byte '{}' message: {}", header.size, header.command,
HEX.encode(payloadBytes));
}
try {
return makeMessage(header.command, header.size, payloadBytes, hash, header.checksum);
} catch (Exception e) {
throw new ProtocolException("Error deserializing message " + HEX.encode(payloadBytes) + "\n", e);
}
}
private Message makeMessage(String command, int length, byte[] payloadBytes, byte[] hash, byte[] checksum) throws ProtocolException {
// We use an if ladder rather than reflection because reflection is very slow on Android.
Message message;
if (command.equals("version")) {
return new VersionMessage(params, payloadBytes);
} else if (command.equals("inv")) {
message = new InventoryMessage(params, payloadBytes, parseLazy, parseRetain, length);
} else if (command.equals("block")) {
message = new Block(params, payloadBytes, parseLazy, parseRetain, length);
} else if (command.equals("merkleblock")) {
message = new FilteredBlock(params, payloadBytes);
} else if (command.equals("getdata")) {
message = new GetDataMessage(params, payloadBytes, parseLazy, parseRetain, length);
} else if (command.equals("getblocks")) {
message = new GetBlocksMessage(params, payloadBytes);
} else if (command.equals("getheaders")) {
message = new GetHeadersMessage(params, payloadBytes);
} else if (command.equals("tx")) {
Transaction tx = new Transaction(params, payloadBytes, null, parseLazy, parseRetain, length);
if (hash != null)
tx.setHash(new Sha256Hash(Utils.reverseBytes(hash)));
message = tx;
} else if (command.equals("addr")) {
message = new AddressMessage(params, payloadBytes, parseLazy, parseRetain, length);
} else if (command.equals("ping")) {
message = new Ping(params, payloadBytes);
} else if (command.equals("pong")) {
message = new Pong(params, payloadBytes);
} else if (command.equals("verack")) {
return new VersionAck(params, payloadBytes);
} else if (command.equals("headers")) {
return new HeadersMessage(params, payloadBytes);
} else if (command.equals("alert")) {
return new AlertMessage(params, payloadBytes);
} else if (command.equals("filterload")) {
return new BloomFilter(params, payloadBytes);
} else if (command.equals("notfound")) {
return new NotFoundMessage(params, payloadBytes);
} else if (command.equals("mempool")) {
return new MemoryPoolMessage();
} else if (command.equals("reject")) {
return new RejectMessage(params, payloadBytes);
} else if (command.equals("utxos")) {
return new UTXOsMessage(params, payloadBytes);
} else if (command.equals("getutxos")) {
return new GetUTXOsMessage(params, payloadBytes);
} else {
log.warn("No support for deserializing message with name {}", command);
return new UnknownMessage(params, command, payloadBytes);
}
if (checksum != null)
message.setChecksum(checksum);
return message;
}
public void seekPastMagicBytes(ByteBuffer in) throws BufferUnderflowException {
int magicCursor = 3; // Which byte of the magic we're looking for currently.
while (true) {
byte b = in.get();
// We're looking for a run of bytes that is the same as the packet magic but we want to ignore partial
// magics that aren't complete. So we keep track of where we're up to with magicCursor.
byte expectedByte = (byte)(0xFF & params.getPacketMagic() >>> (magicCursor * 8));
if (b == expectedByte) {
magicCursor--;
if (magicCursor < 0) {
// We found the magic sequence.
return;
} else {
// We still have further to go to find the next message.
}
} else {
magicCursor = 3;
}
}
}
/**
* Whether the serializer will produce lazy parse mode Messages
*/
public boolean isParseLazyMode() {
return parseLazy;
}
/**
* Whether the serializer will produce cached mode Messages
*/
public boolean isParseRetainMode() {
return parseRetain;
}
public static class BitcoinPacketHeader {
/** The largest number of bytes that a header can represent */
public static final int HEADER_LENGTH = COMMAND_LEN + 4 + 4;
public final byte[] header;
public final String command;
public final int size;
public final byte[] checksum;
public BitcoinPacketHeader(ByteBuffer in) throws ProtocolException, BufferUnderflowException {
header = new byte[HEADER_LENGTH];
in.get(header, 0, header.length);
int cursor = 0;
// The command is a NULL terminated string, unless the command fills all twelve bytes
// in which case the termination is implicit.
for (; header[cursor] != 0 && cursor < COMMAND_LEN; cursor++) ;
byte[] commandBytes = new byte[cursor];
System.arraycopy(header, 0, commandBytes, 0, cursor);
try {
command = new String(commandBytes, "US-ASCII");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e); // Cannot happen.
}
cursor = COMMAND_LEN;
size = (int) readUint32(header, cursor);
cursor += 4;
if (size > Message.MAX_SIZE)
throw new ProtocolException("Message size too large: " + size);
// Old clients don't send the checksum.
checksum = new byte[4];
// Note that the size read above includes the checksum bytes.
System.arraycopy(header, cursor, checksum, 0, 4);
cursor += 4;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,157 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* 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 com.dogecoin.dogecoinj.core;
import static com.google.common.base.Preconditions.checkArgument;
import com.dogecoin.dogecoinj.store.BlockStore;
import com.dogecoin.dogecoinj.store.BlockStoreException;
import java.util.ArrayList;
import java.util.List;
/**
* <p>A BlockChain implements the <i>simplified payment verification</i> mode of the Bitcoin protocol. It is the right
* choice to use for programs that have limited resources as it won't verify transactions signatures or attempt to store
* all of the block chain. Really, this class should be called SPVBlockChain but for backwards compatibility it is not.
* </p>
*/
public class BlockChain extends AbstractBlockChain {
/** Keeps a map of block hashes to StoredBlocks. */
protected final BlockStore blockStore;
/**
* <p>Constructs a BlockChain connected to the given wallet and store. To obtain a {@link Wallet} you can construct
* one from scratch, or you can deserialize a saved wallet from disk using {@link Wallet#loadFromFile(java.io.File)}
* </p>
*
* <p>For the store, you should use {@link com.dogecoin.dogecoinj.store.SPVBlockStore} or you could also try a
* {@link com.dogecoin.dogecoinj.store.MemoryBlockStore} if you want to hold all headers in RAM and don't care about
* disk serialization (this is rare).</p>
*/
public BlockChain(NetworkParameters params, Wallet wallet, BlockStore blockStore) throws BlockStoreException {
this(params, new ArrayList<BlockChainListener>(), blockStore);
if (wallet != null)
addWallet(wallet);
}
/**
* Constructs a BlockChain that has no wallet at all. This is helpful when you don't actually care about sending
* and receiving coins but rather, just want to explore the network data structures.
*/
public BlockChain(NetworkParameters params, BlockStore blockStore) throws BlockStoreException {
this(params, new ArrayList<BlockChainListener>(), blockStore);
}
/**
* Constructs a BlockChain connected to the given list of listeners and a store.
*/
public BlockChain(NetworkParameters params, List<BlockChainListener> wallets,
BlockStore blockStore) throws BlockStoreException {
super(params, wallets, blockStore);
this.blockStore = blockStore;
}
@Override
protected StoredBlock addToBlockStore(StoredBlock storedPrev, Block blockHeader, TransactionOutputChanges txOutChanges)
throws BlockStoreException, VerificationException {
StoredBlock newBlock = storedPrev.build(blockHeader);
blockStore.put(newBlock);
return newBlock;
}
@Override
protected StoredBlock addToBlockStore(StoredBlock storedPrev, Block blockHeader)
throws BlockStoreException, VerificationException {
StoredBlock newBlock = storedPrev.build(blockHeader);
blockStore.put(newBlock);
return newBlock;
}
@Override
protected void rollbackBlockStore(int height) throws BlockStoreException {
lock.lock();
try {
int currentHeight = getBestChainHeight();
checkArgument(height >= 0 && height <= currentHeight, "Bad height: %s", height);
if (height == currentHeight)
return; // nothing to do
// Look for the block we want to be the new chain head
StoredBlock newChainHead = blockStore.getChainHead();
while (newChainHead.getHeight() > height) {
newChainHead = newChainHead.getPrev(blockStore);
if (newChainHead == null)
throw new BlockStoreException("Unreachable height");
}
// Modify store directly
blockStore.put(newChainHead);
this.setChainHead(newChainHead);
} finally {
lock.unlock();
}
}
@Override
protected boolean shouldVerifyTransactions() {
return false;
}
@Override
protected TransactionOutputChanges connectTransactions(int height, Block block) {
// Don't have to do anything as this is only called if(shouldVerifyTransactions())
throw new UnsupportedOperationException();
}
@Override
protected TransactionOutputChanges connectTransactions(StoredBlock newBlock) {
// Don't have to do anything as this is only called if(shouldVerifyTransactions())
throw new UnsupportedOperationException();
}
@Override
protected void disconnectTransactions(StoredBlock block) {
// Don't have to do anything as this is only called if(shouldVerifyTransactions())
throw new UnsupportedOperationException();
}
@Override
protected void doSetChainHead(StoredBlock chainHead) throws BlockStoreException {
blockStore.setChainHead(chainHead);
}
@Override
protected void notSettingChainHead() throws BlockStoreException {
// We don't use DB transactions here, so we don't need to do anything
}
@Override
protected StoredBlock getStoredBlockInCurrentScope(Sha256Hash hash) throws BlockStoreException {
return blockStore.get(hash);
}
@Override
public boolean add(FilteredBlock block) throws VerificationException, PrunedException {
boolean success = super.add(block);
if (success) {
trackFilteredTransactions(block.getTransactionCount());
}
return success;
}
}

View File

@ -1,95 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import java.util.List;
/**
* Implementors can be connected to a {@link BlockChain} and have its methods called when various things
* happen that modify the state of the chain, for example: new blocks being received, a re-org occurring, or the
* best chain head changing.
*/
public interface BlockChainListener {
/**
* Called when a new block on the best chain is seen, after relevant transactions are extracted and sent to
* us via either {@link #receiveFromBlock(Transaction, StoredBlock, com.dogecoin.dogecoinj.core.BlockChain.NewBlockType, int)}
* or {@link #notifyTransactionIsInBlock(Sha256Hash, StoredBlock, com.dogecoin.dogecoinj.core.BlockChain.NewBlockType, int)}.
* If this block is causing a re-organise to a new chain, this method is NOT called even though the block may be
* the new best block: your reorganize implementation is expected to do whatever would normally be done do for a new
* best block in this case.
*/
void notifyNewBestBlock(StoredBlock block) throws VerificationException;
/**
* Called by the {@link BlockChain} when the best chain (representing total work done) has changed. In this case,
* we need to go through our transactions and find out if any have become invalid. It's possible for our balance
* to go down in this case: money we thought we had can suddenly vanish if the rest of the network agrees it
* should be so.<p>
*
* The oldBlocks/newBlocks lists are ordered height-wise from top first to bottom last (i.e. newest blocks first).
*/
void reorganize(StoredBlock splitPoint, List<StoredBlock> oldBlocks,
List<StoredBlock> newBlocks) throws VerificationException;
/**
* Returns true if the given transaction is interesting to the listener. If yes, then the transaction will
* be provided via the receiveFromBlock method. This method is essentially an optimization that lets BlockChain
* bypass verification of a blocks merkle tree if no listeners are interested, which can save time when processing
* full blocks on mobile phones. It's likely the method will be removed in future and replaced with an alternative
* mechanism that involves listeners providing all keys that are interesting.
*/
boolean isTransactionRelevant(Transaction tx) throws ScriptException;
/**
* <p>Called by the {@link BlockChain} when we receive a new block that contains a relevant transaction.</p>
*
* <p>A transaction may be received multiple times if is included into blocks in parallel chains. The blockType
* parameter describes whether the containing block is on the main/best chain or whether it's on a presently
* inactive side chain.</p>
*
* <p>The relativityOffset parameter is an arbitrary number used to establish an ordering between transactions
* within the same block. In the case where full blocks are being downloaded, it is simply the index of the
* transaction within that block. When Bloom filtering is in use, we don't find out the exact offset into a block
* that a transaction occurred at, so the relativity count is not reflective of anything in an absolute sense but
* rather exists only to order the transaction relative to the others.</p>
*/
void receiveFromBlock(Transaction tx, StoredBlock block,
BlockChain.NewBlockType blockType,
int relativityOffset) throws VerificationException;
/**
* <p>Called by the {@link BlockChain} when we receive a new {@link FilteredBlock} that contains the given
* transaction hash in its merkle tree.</p>
*
* <p>A transaction may be received multiple times if is included into blocks in parallel chains. The blockType
* parameter describes whether the containing block is on the main/best chain or whether it's on a presently
* inactive side chain.</p>
*
* <p>The relativityOffset parameter in this case is an arbitrary (meaningless) number, that is useful only when
* compared to the relativity count of another transaction received inside the same block. It is used to establish
* an ordering of transactions relative to one another.</p>
*
* <p>This method should return false if the given tx hash isn't known about, e.g. because the the transaction was
* a Bloom false positive. If it was known about and stored, it should return true. The caller may need to know
* this to calculate the effective FP rate.</p>
*
* @return whether the transaction is known about i.e. was considered relevant previously.
*/
boolean notifyTransactionIsInBlock(Sha256Hash txHash, StoredBlock block,
BlockChain.NewBlockType blockType,
int relativityOffset) throws VerificationException;
}

View File

@ -1,369 +0,0 @@
/*
* Copyright 2012 Matt Corallo
*
* 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 com.dogecoin.dogecoinj.core;
import com.dogecoin.dogecoinj.script.Script;
import com.dogecoin.dogecoinj.script.ScriptChunk;
import com.google.common.base.Objects;
import com.google.common.collect.Lists;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.Math.*;
/**
* <p>A Bloom filter is a probabilistic data structure which can be sent to another client so that it can avoid
* sending us transactions that aren't relevant to our set of keys. This allows for significantly more efficient
* use of available network bandwidth and CPU time.</p>
*
* <p>Because a Bloom filter is probabilistic, it has a configurable false positive rate. So the filter will sometimes
* match transactions that weren't inserted into it, but it will never fail to match transactions that were. This is
* a useful privacy feature - if you have spare bandwidth the false positive rate can be increased so the remote peer
* gets a noisy picture of what transactions are relevant to your wallet.</p>
*/
public class BloomFilter extends Message {
/** The BLOOM_UPDATE_* constants control when the bloom filter is auto-updated by the peer using
it as a filter, either never, for all outputs or only for pay-2-pubkey outputs (default) */
public enum BloomUpdate {
UPDATE_NONE, // 0
UPDATE_ALL, // 1
/** Only adds outpoints to the filter if the output is a pay-to-pubkey/pay-to-multisig script */
UPDATE_P2PUBKEY_ONLY //2
}
private byte[] data;
private long hashFuncs;
private long nTweak;
private byte nFlags;
// Same value as the reference client
// A filter of 20,000 items and a false positive rate of 0.1% or one of 10,000 items and 0.0001% is just under 36,000 bytes
private static final long MAX_FILTER_SIZE = 36000;
// There is little reason to ever have more hash functions than 50 given a limit of 36,000 bytes
private static final int MAX_HASH_FUNCS = 50;
/**
* Construct a BloomFilter by deserializing payloadBytes
*/
public BloomFilter(NetworkParameters params, byte[] payloadBytes) throws ProtocolException {
super(params, payloadBytes, 0);
}
/**
* Constructs a filter with the given parameters which is updated on pay2pubkey outputs only.
*/
public BloomFilter(int elements, double falsePositiveRate, long randomNonce) {
this(elements, falsePositiveRate, randomNonce, BloomUpdate.UPDATE_P2PUBKEY_ONLY);
}
/**
* <p>Constructs a new Bloom Filter which will provide approximately the given false positive rate when the given
* number of elements have been inserted. If the filter would otherwise be larger than the maximum allowed size,
* it will be automatically downsized to the maximum size.</p>
*
* <p>To check the theoretical false positive rate of a given filter, use
* {@link BloomFilter#getFalsePositiveRate(int)}.</p>
*
* <p>The anonymity of which coins are yours to any peer which you send a BloomFilter to is controlled by the
* false positive rate. For reference, as of block 187,000, the total number of addresses used in the chain was
* roughly 4.5 million. Thus, if you use a false positive rate of 0.001 (0.1%), there will be, on average, 4,500
* distinct public keys/addresses which will be thought to be yours by nodes which have your bloom filter, but
* which are not actually yours. Keep in mind that a remote node can do a pretty good job estimating the order of
* magnitude of the false positive rate of a given filter you provide it when considering the anonymity of a given
* filter.</p>
*
* <p>In order for filtered block download to function efficiently, the number of matched transactions in any given
* block should be less than (with some headroom) the maximum size of the MemoryPool used by the Peer
* doing the downloading (default is {@link TxConfidenceTable#MAX_SIZE}). See the comment in processBlock(FilteredBlock)
* for more information on this restriction.</p>
*
* <p>randomNonce is a tweak for the hash function used to prevent some theoretical DoS attacks.
* It should be a random value, however secureness of the random value is of no great consequence.</p>
*
* <p>updateFlag is used to control filter behaviour on the server (remote node) side when it encounters a hit.
* See {@link com.dogecoin.dogecoinj.core.BloomFilter.BloomUpdate} for a brief description of each mode. The purpose
* of this flag is to reduce network round-tripping and avoid over-dirtying the filter for the most common
* wallet configurations.</p>
*/
public BloomFilter(int elements, double falsePositiveRate, long randomNonce, BloomUpdate updateFlag) {
// The following formulas were stolen from Wikipedia's page on Bloom Filters (with the addition of min(..., MAX_...))
// Size required for a given number of elements and false-positive rate
int size = (int)(-1 / (pow(log(2), 2)) * elements * log(falsePositiveRate));
size = max(1, min(size, (int) MAX_FILTER_SIZE * 8) / 8);
data = new byte[size];
// Optimal number of hash functions for a given filter size and element count.
hashFuncs = (int)(data.length * 8 / (double)elements * log(2));
hashFuncs = max(1, min(hashFuncs, MAX_HASH_FUNCS));
this.nTweak = randomNonce;
this.nFlags = (byte)(0xff & updateFlag.ordinal());
}
/**
* Returns the theoretical false positive rate of this filter if were to contain the given number of elements.
*/
public double getFalsePositiveRate(int elements) {
return pow(1 - pow(E, -1.0 * (hashFuncs * elements) / (data.length * 8)), hashFuncs);
}
@Override
public String toString() {
return "Bloom Filter of size " + data.length + " with " + hashFuncs + " hash functions.";
}
@Override
void parse() throws ProtocolException {
data = readByteArray();
if (data.length > MAX_FILTER_SIZE)
throw new ProtocolException ("Bloom filter out of size range.");
hashFuncs = readUint32();
if (hashFuncs > MAX_HASH_FUNCS)
throw new ProtocolException("Bloom filter hash function count out of range");
nTweak = readUint32();
nFlags = readBytes(1)[0];
length = cursor - offset;
}
/**
* Serializes this message to the provided stream. If you just want the raw bytes use bitcoinSerialize().
*/
@Override
void bitcoinSerializeToStream(OutputStream stream) throws IOException {
stream.write(new VarInt(data.length).encode());
stream.write(data);
Utils.uint32ToByteStreamLE(hashFuncs, stream);
Utils.uint32ToByteStreamLE(nTweak, stream);
stream.write(nFlags);
}
@Override
protected void parseLite() throws ProtocolException {
// Do nothing, lazy parsing isn't useful for bloom filters.
}
private static int rotateLeft32(int x, int r) {
return (x << r) | (x >>> (32 - r));
}
/**
* Applies the MurmurHash3 (x86_32) algorithm to the given data.
* See this <a href="http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp">C++ code for the original.</a>
*/
public static int murmurHash3(byte[] data, long nTweak, int hashNum, byte[] object) {
int h1 = (int)(hashNum * 0xFBA4C795L + nTweak);
final int c1 = 0xcc9e2d51;
final int c2 = 0x1b873593;
int numBlocks = (object.length / 4) * 4;
// body
for(int i = 0; i < numBlocks; i += 4) {
int k1 = (object[i] & 0xFF) |
((object[i+1] & 0xFF) << 8) |
((object[i+2] & 0xFF) << 16) |
((object[i+3] & 0xFF) << 24);
k1 *= c1;
k1 = rotateLeft32(k1, 15);
k1 *= c2;
h1 ^= k1;
h1 = rotateLeft32(h1, 13);
h1 = h1*5+0xe6546b64;
}
int k1 = 0;
switch(object.length & 3)
{
case 3:
k1 ^= (object[numBlocks + 2] & 0xff) << 16;
// Fall through.
case 2:
k1 ^= (object[numBlocks + 1] & 0xff) << 8;
// Fall through.
case 1:
k1 ^= (object[numBlocks] & 0xff);
k1 *= c1; k1 = rotateLeft32(k1, 15); k1 *= c2; h1 ^= k1;
// Fall through.
default:
// Do nothing.
break;
}
// finalization
h1 ^= object.length;
h1 ^= h1 >>> 16;
h1 *= 0x85ebca6b;
h1 ^= h1 >>> 13;
h1 *= 0xc2b2ae35;
h1 ^= h1 >>> 16;
return (int)((h1&0xFFFFFFFFL) % (data.length * 8));
}
/**
* Returns true if the given object matches the filter either because it was inserted, or because we have a
* false-positive.
*/
public synchronized boolean contains(byte[] object) {
for (int i = 0; i < hashFuncs; i++) {
if (!Utils.checkBitLE(data, murmurHash3(data, nTweak, i, object)))
return false;
}
return true;
}
/** Insert the given arbitrary data into the filter */
public synchronized void insert(byte[] object) {
for (int i = 0; i < hashFuncs; i++)
Utils.setBitLE(data, murmurHash3(data, nTweak, i, object));
}
/** Inserts the given key and equivalent hashed form (for the address). */
public synchronized void insert(ECKey key) {
insert(key.getPubKey());
insert(key.getPubKeyHash());
}
/**
* Sets this filter to match all objects. A Bloom filter which matches everything may seem pointless, however,
* it is useful in order to reduce steady state bandwidth usage when you want full blocks. Instead of receiving
* all transaction data twice, you will receive the vast majority of all transactions just once, at broadcast time.
* Solved blocks will then be send just as Merkle trees of tx hashes, meaning a constant 32 bytes of data for each
* transaction instead of 100-300 bytes as per usual.
*/
public synchronized void setMatchAll() {
data = new byte[] {(byte) 0xff};
}
/**
* Copies filter into this. Filter must have the same size, hash function count and nTweak or an
* IllegalArgumentException will be thrown.
*/
public synchronized void merge(BloomFilter filter) {
if (!this.matchesAll() && !filter.matchesAll()) {
checkArgument(filter.data.length == this.data.length &&
filter.hashFuncs == this.hashFuncs &&
filter.nTweak == this.nTweak);
for (int i = 0; i < data.length; i++)
this.data[i] |= filter.data[i];
} else {
this.data = new byte[] {(byte) 0xff};
}
}
/**
* Returns true if this filter will match anything. See {@link com.dogecoin.dogecoinj.core.BloomFilter#setMatchAll()}
* for when this can be a useful thing to do.
*/
public synchronized boolean matchesAll() {
for (byte b : data)
if (b != (byte) 0xff)
return false;
return true;
}
/**
* The update flag controls how application of the filter to a block modifies the filter. See the enum javadocs
* for information on what occurs and when.
*/
public synchronized BloomUpdate getUpdateFlag() {
if (nFlags == 0)
return BloomUpdate.UPDATE_NONE;
else if (nFlags == 1)
return BloomUpdate.UPDATE_ALL;
else if (nFlags == 2)
return BloomUpdate.UPDATE_P2PUBKEY_ONLY;
else
throw new IllegalStateException("Unknown flag combination");
}
/**
* Creates a new FilteredBlock from the given Block, using this filter to select transactions. Matches can cause the
* filter to be updated with the matched element, this ensures that when a filter is applied to a block, spends of
* matched transactions are also matched. However it means this filter can be mutated by the operation. The returned
* filtered block already has the matched transactions associated with it.
*/
public synchronized FilteredBlock applyAndUpdate(Block block) {
List<Transaction> txns = block.getTransactions();
List<Sha256Hash> txHashes = new ArrayList<Sha256Hash>(txns.size());
List<Transaction> matched = Lists.newArrayList();
byte[] bits = new byte[(int) Math.ceil(txns.size() / 8.0)];
for (int i = 0; i < txns.size(); i++) {
Transaction tx = txns.get(i);
txHashes.add(tx.getHash());
if (applyAndUpdate(tx)) {
Utils.setBitLE(bits, i);
matched.add(tx);
}
}
PartialMerkleTree pmt = PartialMerkleTree.buildFromLeaves(block.getParams(), bits, txHashes);
FilteredBlock filteredBlock = new FilteredBlock(block.getParams(), block.cloneAsHeader(), pmt);
for (Transaction transaction : matched)
filteredBlock.provideTransaction(transaction);
return filteredBlock;
}
public synchronized boolean applyAndUpdate(Transaction tx) {
if (contains(tx.getHash().getBytes()))
return true;
boolean found = false;
BloomUpdate flag = getUpdateFlag();
for (TransactionOutput output : tx.getOutputs()) {
Script script = output.getScriptPubKey();
for (ScriptChunk chunk : script.getChunks()) {
if (!chunk.isPushData())
continue;
if (contains(chunk.data)) {
boolean isSendingToPubKeys = script.isSentToRawPubKey() || script.isSentToMultiSig();
if (flag == BloomUpdate.UPDATE_ALL || (flag == BloomUpdate.UPDATE_P2PUBKEY_ONLY && isSendingToPubKeys))
insert(output.getOutPointFor().bitcoinSerialize());
found = true;
}
}
}
if (found) return true;
for (TransactionInput input : tx.getInputs()) {
if (contains(input.getOutpoint().bitcoinSerialize())) {
return true;
}
for (ScriptChunk chunk : input.getScriptSig().getChunks()) {
if (chunk.isPushData() && contains(chunk.data))
return true;
}
}
return false;
}
@Override
public synchronized boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BloomFilter other = (BloomFilter) o;
return hashFuncs == other.hashFuncs &&
nTweak == other.nTweak &&
Arrays.equals(data, other.data);
}
@Override
public synchronized int hashCode() {
return Objects.hashCode(hashFuncs, nTweak, Arrays.hashCode(data));
}
}

View File

@ -1,225 +0,0 @@
/**
* Copyright 2013 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import com.dogecoin.dogecoinj.store.BlockStore;
import com.dogecoin.dogecoinj.store.BlockStoreException;
import com.dogecoin.dogecoinj.store.FullPrunedBlockStore;
import com.google.common.base.Charsets;
import com.google.common.hash.HashCode;
import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
import com.google.common.io.BaseEncoding;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Map;
import java.util.TreeMap;
import static com.google.common.base.Preconditions.*;
/**
* <p>Vends hard-coded {@link StoredBlock}s for blocks throughout the chain. Checkpoints serve two purposes:</p>
* <ol>
* <li>They act as a safety mechanism against huge re-orgs that could rewrite large chunks of history, thus
* constraining the block chain to be a consensus mechanism only for recent parts of the timeline.</li>
* <li>They allow synchronization to the head of the chain for new wallets/users much faster than syncing all
* headers from the genesis block.</li>
* </ol>
*
* <p>Checkpoints are used by the SPV {@link BlockChain} to initialize fresh
* {@link com.dogecoin.dogecoinj.store.SPVBlockStore}s. They are not used by fully validating mode, which instead has a
* different concept of checkpoints that are used to hard-code the validity of blocks that violate BIP30 (duplicate
* coinbase transactions). Those "checkpoints" can be found in NetworkParameters.</p>
*
* <p>The file format consists of the string "CHECKPOINTS 1", followed by a uint32 containing the number of signatures
* to read. The value may not be larger than 256 (so it could have been a byte but isn't for historical reasons).
* If the number of signatures is larger than zero, each 65 byte ECDSA secp256k1 signature then follows. The signatures
* sign the hash of all bytes that follow the last signature.</p>
*
* <p>After the signatures come an int32 containing the number of checkpoints in the file. Then each checkpoint follows
* one after the other. A checkpoint is 12 bytes for the total work done field, 4 bytes for the height, 80 bytes
* for the block header and then 1 zero byte at the end (i.e. number of transactions in the block: always zero).</p>
*/
public class CheckpointManager {
private static final Logger log = LoggerFactory.getLogger(CheckpointManager.class);
private static final String BINARY_MAGIC = "CHECKPOINTS 1";
private static final String TEXTUAL_MAGIC = "TXT CHECKPOINTS 1";
private static final int MAX_SIGNATURES = 256;
// Map of block header time to data.
protected final TreeMap<Long, StoredBlock> checkpoints = new TreeMap<Long, StoredBlock>();
protected final NetworkParameters params;
protected final Sha256Hash dataHash;
public static final BaseEncoding BASE64 = BaseEncoding.base64().omitPadding();
public CheckpointManager(NetworkParameters params, InputStream inputStream) throws IOException {
this.params = checkNotNull(params);
checkNotNull(inputStream);
inputStream = new BufferedInputStream(inputStream);
inputStream.mark(1);
int first = inputStream.read();
inputStream.reset();
if (first == BINARY_MAGIC.charAt(0))
dataHash = readBinary(inputStream);
else if (first == TEXTUAL_MAGIC.charAt(0))
dataHash = readTextual(inputStream);
else
throw new IOException("Unsupported format.");
}
private Sha256Hash readBinary(InputStream inputStream) throws IOException {
DataInputStream dis = null;
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
DigestInputStream digestInputStream = new DigestInputStream(inputStream, digest);
dis = new DataInputStream(digestInputStream);
digestInputStream.on(false);
byte[] header = new byte[BINARY_MAGIC.length()];
dis.readFully(header);
if (!Arrays.equals(header, BINARY_MAGIC.getBytes("US-ASCII")))
throw new IOException("Header bytes did not match expected version");
int numSignatures = checkPositionIndex(dis.readInt(), MAX_SIGNATURES, "Num signatures out of range");
for (int i = 0; i < numSignatures; i++) {
byte[] sig = new byte[65];
dis.readFully(sig);
// TODO: Do something with the signature here.
}
digestInputStream.on(true);
int numCheckpoints = dis.readInt();
checkState(numCheckpoints > 0);
final int size = StoredBlock.COMPACT_SERIALIZED_SIZE;
ByteBuffer buffer = ByteBuffer.allocate(size);
for (int i = 0; i < numCheckpoints; i++) {
if (dis.read(buffer.array(), 0, size) < size)
throw new IOException("Incomplete read whilst loading checkpoints.");
StoredBlock block = StoredBlock.deserializeCompact(params, buffer);
buffer.position(0);
checkpoints.put(block.getHeader().getTimeSeconds(), block);
}
Sha256Hash dataHash = new Sha256Hash(digest.digest());
log.info("Read {} checkpoints, hash is {}", checkpoints.size(), dataHash);
return dataHash;
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e); // Cannot happen.
} catch (ProtocolException e) {
throw new IOException(e);
} finally {
if (dis != null) dis.close();
inputStream.close();
}
}
private Sha256Hash readTextual(InputStream inputStream) throws IOException {
Hasher hasher = Hashing.sha256().newHasher();
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(inputStream, Charsets.US_ASCII));
String magic = reader.readLine();
if (!TEXTUAL_MAGIC.equals(magic))
throw new IOException("unexpected magic: " + magic);
int numSigs = Integer.parseInt(reader.readLine());
for (int i = 0; i < numSigs; i++)
reader.readLine(); // Skip sigs for now.
int numCheckpoints = Integer.parseInt(reader.readLine());
checkState(numCheckpoints > 0);
// Hash numCheckpoints in a way compatible to the binary format.
hasher.putBytes(ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(numCheckpoints).array());
final int size = StoredBlock.COMPACT_SERIALIZED_SIZE;
ByteBuffer buffer = ByteBuffer.allocate(size);
for (int i = 0; i < numCheckpoints; i++) {
byte[] bytes = BASE64.decode(reader.readLine());
hasher.putBytes(bytes);
buffer.position(0);
buffer.put(bytes);
buffer.position(0);
StoredBlock block = StoredBlock.deserializeCompact(params, buffer);
checkpoints.put(block.getHeader().getTimeSeconds(), block);
}
HashCode hash = hasher.hash();
log.info("Read {} checkpoints, hash is {}", checkpoints.size(), hash);
return new Sha256Hash(hash.asBytes());
} finally {
if (reader != null) reader.close();
}
}
/**
* Returns a {@link StoredBlock} representing the last checkpoint before the given time, for example, normally
* you would want to know the checkpoint before the earliest wallet birthday.
*/
public StoredBlock getCheckpointBefore(long time) {
try {
checkArgument(time > params.getGenesisBlock().getTimeSeconds());
// This is thread safe because the map never changes after creation.
Map.Entry<Long, StoredBlock> entry = checkpoints.floorEntry(time);
if (entry != null) return entry.getValue();
Block genesis = params.getGenesisBlock().cloneAsHeader();
return new StoredBlock(genesis, genesis.getWork(), 0);
} catch (VerificationException e) {
throw new RuntimeException(e); // Cannot happen.
}
}
/** Returns the number of checkpoints that were loaded. */
public int numCheckpoints() {
return checkpoints.size();
}
/** Returns a hash of the concatenated checkpoint data. */
public Sha256Hash getDataHash() {
return dataHash;
}
/**
* <p>Convenience method that creates a CheckpointManager, loads the given data, gets the checkpoint for the given
* time, then inserts it into the store and sets that to be the chain head. Useful when you have just created
* a new store from scratch and want to use configure it all in one go.</p>
*
* <p>Note that time is adjusted backwards by a week to account for possible clock drift in the block headers.</p>
*/
public static void checkpoint(NetworkParameters params, InputStream checkpoints, BlockStore store, long time)
throws IOException, BlockStoreException {
checkNotNull(params);
checkNotNull(store);
checkArgument(!(store instanceof FullPrunedBlockStore), "You cannot use checkpointing with a full store.");
time -= 86400 * 7;
BufferedInputStream stream = new BufferedInputStream(checkpoints);
CheckpointManager manager = new CheckpointManager(params, stream);
StoredBlock checkpoint = manager.getCheckpointBefore(time);
store.put(checkpoint);
store.setChainHead(checkpoint);
}
}

View File

@ -1,87 +0,0 @@
/**
* Copyright 2011 Steve Coughlan.
*
* 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 com.dogecoin.dogecoinj.core;
import javax.annotation.Nullable;
/**
* Represents a Message type that can be contained within another Message. ChildMessages that have a cached
* backing byte array need to invalidate their parent's caches as well as their own if they are modified.
*/
public abstract class ChildMessage extends Message {
private static final long serialVersionUID = -7657113383624517931L;
@Nullable protected Message parent;
protected ChildMessage() {
}
public ChildMessage(NetworkParameters params) {
super(params);
}
public ChildMessage(NetworkParameters params, byte[] payload, int offset, int protocolVersion) throws ProtocolException {
super(params, payload, offset, protocolVersion);
}
public ChildMessage(NetworkParameters params, byte[] payload, int offset, int protocolVersion, Message parent, boolean parseLazy,
boolean parseRetain, int length) throws ProtocolException {
super(params, payload, offset, protocolVersion, parseLazy, parseRetain, length);
this.parent = parent;
}
public ChildMessage(NetworkParameters params, byte[] payload, int offset) throws ProtocolException {
super(params, payload, offset);
}
public ChildMessage(NetworkParameters params, byte[] payload, int offset, @Nullable Message parent, boolean parseLazy, boolean parseRetain, int length)
throws ProtocolException {
super(params, payload, offset, parseLazy, parseRetain, length);
this.parent = parent;
}
public void setParent(@Nullable Message parent) {
if (this.parent != null && this.parent != parent && parent != null) {
// After old parent is unlinked it won't be able to receive notice if this ChildMessage
// changes internally. To be safe we invalidate the parent cache to ensure it rebuilds
// manually on serialization.
this.parent.unCache();
}
this.parent = parent;
}
/* (non-Javadoc)
* @see Message#unCache()
*/
@Override
protected void unCache() {
super.unCache();
if (parent != null)
parent.unCache();
}
protected void adjustLength(int adjustment) {
adjustLength(0, adjustment);
}
@Override
protected void adjustLength(int newArraySize, int adjustment) {
super.adjustLength(newArraySize, adjustment);
if (parent != null)
parent.adjustLength(newArraySize, adjustment);
}
}

View File

@ -1,281 +0,0 @@
/**
* Copyright 2014 Andreas Schildbach
*
* 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 com.dogecoin.dogecoinj.core;
import com.dogecoin.dogecoinj.utils.MonetaryFormat;
import com.google.common.math.LongMath;
import java.io.Serializable;
import java.math.BigDecimal;
import static com.google.common.base.Preconditions.checkArgument;
/**
* Represents a monetary Bitcoin value. This class is immutable.
*/
public final class Coin implements Monetary, Comparable<Coin>, Serializable {
/**
* Number of decimals for one Bitcoin. This constant is useful for quick adapting to other coins because a lot of
* constants derive from it.
*/
public static final int SMALLEST_UNIT_EXPONENT = 8;
/**
* The number of satoshis equal to one bitcoin.
*/
private static final long COIN_VALUE = LongMath.pow(10, SMALLEST_UNIT_EXPONENT);
/**
* Zero Bitcoins.
*/
public static final Coin ZERO = Coin.valueOf(0);
/**
* One Bitcoin.
*/
public static final Coin COIN = Coin.valueOf(COIN_VALUE);
/**
* 0.01 Bitcoins. This unit is not really used much.
*/
public static final Coin CENT = COIN.divide(100);
/**
* 0.001 Bitcoins, also known as 1 mBTC.
*/
public static final Coin MILLICOIN = COIN.divide(1000);
/**
* 0.000001 Bitcoins, also known as 1 µBTC or 1 uBTC.
*/
public static final Coin MICROCOIN = MILLICOIN.divide(1000);
/**
* A satoshi is the smallest unit that can be transferred. 100 million of them fit into a Bitcoin.
*/
public static final Coin SATOSHI = Coin.valueOf(1);
public static final Coin FIFTY_COINS = COIN.multiply(50);
/**
* Represents a monetary value of minus one satoshi.
*/
public static final Coin NEGATIVE_SATOSHI = Coin.valueOf(-1);
/**
* The number of satoshis of this monetary value.
*/
public final long value;
private final long MAX_SATOSHIS = Long.MAX_VALUE;
private Coin(final long satoshis) {
checkArgument(-MAX_SATOSHIS <= satoshis && satoshis <= MAX_SATOSHIS,
"%s satoshis exceeds maximum possible quantity of Bitcoin.", satoshis);
this.value = satoshis;
}
public static Coin valueOf(final long satoshis) {
return new Coin(satoshis);
}
@Override
public int smallestUnitExponent() {
return SMALLEST_UNIT_EXPONENT;
}
/**
* Returns the number of satoshis of this monetary value.
*/
@Override
public long getValue() {
return value;
}
/**
* Convert an amount expressed in the way humans are used to into satoshis.
*/
public static Coin valueOf(final int coins, final int cents) {
checkArgument(cents < 100);
checkArgument(cents >= 0);
checkArgument(coins >= 0);
final Coin coin = COIN.multiply(coins).add(CENT.multiply(cents));
checkArgument(coin.compareTo(NetworkParameters.MAX_MONEY) <= 0);
return coin;
}
/**
* Parses an amount expressed in the way humans are used to.<p>
* <p/>
* This takes string in a format understood by {@link BigDecimal#BigDecimal(String)},
* for example "0", "1", "0.10", "1.23E3", "1234.5E-5".
*
* @throws IllegalArgumentException if you try to specify fractional satoshis, or a value out of range.
*/
public static Coin parseCoin(final String str) {
try {
long satoshis = new BigDecimal(str).movePointRight(SMALLEST_UNIT_EXPONENT).toBigIntegerExact().longValue();
return Coin.valueOf(satoshis);
} catch (ArithmeticException e) {
throw new IllegalArgumentException(e); // Repackage exception to honor method contract
}
}
public Coin add(final Coin value) {
return new Coin(LongMath.checkedAdd(this.value, value.value));
}
public Coin subtract(final Coin value) {
return new Coin(LongMath.checkedSubtract(this.value, value.value));
}
public Coin multiply(final long factor) {
return new Coin(LongMath.checkedMultiply(this.value, factor));
}
public Coin divide(final long divisor) {
return new Coin(this.value / divisor);
}
public Coin[] divideAndRemainder(final long divisor) {
return new Coin[] { new Coin(this.value / divisor), new Coin(this.value % divisor) };
}
public long divide(final Coin divisor) {
return this.value / divisor.value;
}
/**
* Returns true if and only if this instance represents a monetary value greater than zero,
* otherwise false.
*/
public boolean isPositive() {
return signum() == 1;
}
/**
* Returns true if and only if this instance represents a monetary value less than zero,
* otherwise false.
*/
public boolean isNegative() {
return signum() == -1;
}
/**
* Returns true if and only if this instance represents zero monetary value,
* otherwise false.
*/
public boolean isZero() {
return signum() == 0;
}
/**
* Returns true if the monetary value represented by this instance is greater than that
* of the given other Coin, otherwise false.
*/
public boolean isGreaterThan(Coin other) {
return compareTo(other) > 0;
}
/**
* Returns true if the monetary value represented by this instance is less than that
* of the given other Coin, otherwise false.
*/
public boolean isLessThan(Coin other) {
return compareTo(other) < 0;
}
public Coin shiftLeft(final int n) {
return new Coin(this.value << n);
}
public Coin shiftRight(final int n) {
return new Coin(this.value >> n);
}
@Override
public int signum() {
if (this.value == 0)
return 0;
return this.value < 0 ? -1 : 1;
}
public Coin negate() {
return new Coin(-this.value);
}
/**
* Returns the number of satoshis of this monetary value. It's deprecated in favour of accessing {@link #value}
* directly.
*/
public long longValue() {
return this.value;
}
private static final MonetaryFormat FRIENDLY_FORMAT = MonetaryFormat.BTC.minDecimals(2).repeatOptionalDecimals(1, 6).postfixCode();
/**
* Returns the value as a 0.12 type string. More digits after the decimal place will be used
* if necessary, but two will always be present.
*/
public String toFriendlyString() {
return FRIENDLY_FORMAT.format(this).toString();
}
private static final MonetaryFormat PLAIN_FORMAT = MonetaryFormat.BTC.minDecimals(0).repeatOptionalDecimals(1, 8).noCode();
/**
* <p>
* Returns the value as a plain string denominated in BTC.
* The result is unformatted with no trailing zeroes.
* For instance, a value of 150000 satoshis gives an output string of "0.0015" BTC
* </p>
*/
public String toPlainString() {
return PLAIN_FORMAT.format(this).toString();
}
@Override
public String toString() {
return Long.toString(value);
}
@Override
public boolean equals(final Object o) {
if (o == this)
return true;
if (o == null || o.getClass() != getClass())
return false;
final Coin other = (Coin) o;
if (this.value != other.value)
return false;
return true;
}
@Override
public int hashCode() {
return (int) this.value;
}
@Override
public int compareTo(final Coin other) {
if (this.value == other.value)
return 0;
return this.value > other.value ? 1 : -1;
}
}

View File

@ -1,25 +0,0 @@
package com.dogecoin.dogecoinj.core;
/**
* The Context object holds various objects that are scoped to a specific instantiation of bitcoinj for a specific
* network. You can get an instance of this class through {@link AbstractBlockChain#getContext()}. At the momemnt it
* only contains a {@link com.dogecoin.dogecoinj.core.TxConfidenceTable} but in future it will likely contain file paths and
* other global configuration of use.
*/
public class Context {
protected TxConfidenceTable confidenceTable;
protected Context() {
confidenceTable = new TxConfidenceTable();
}
/**
* Returns the {@link TxConfidenceTable} created by this context. The pool tracks advertised
* and downloaded transactions so their confidence can be measured as a proportion of how many peers announced it.
* With an un-tampered with internet connection, the more peers announce a transaction the more confidence you can
* have that it's really valid.
*/
public TxConfidenceTable getConfidenceTable() {
return confidenceTable;
}
}

View File

@ -1,111 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DateFormat;
import java.util.Date;
import java.util.concurrent.Semaphore;
// TODO: Rename this to DownloadProgressTracker or something more appropriate.
/**
* <p>An implementation of {@link AbstractPeerEventListener} that listens to chain download events and tracks progress
* as a percentage. The default implementation prints progress to stdout, but you can subclass it and override the
* progress method to update a GUI instead.</p>
*/
public class DownloadListener extends AbstractPeerEventListener {
private static final Logger log = LoggerFactory.getLogger(DownloadListener.class);
private int originalBlocksLeft = -1;
private int lastPercent = 0;
private Semaphore done = new Semaphore(0);
private boolean caughtUp = false;
@Override
public void onChainDownloadStarted(Peer peer, int blocksLeft) {
startDownload(blocksLeft);
// Only mark this the first time, because this method can be called more than once during a chain download
// if we switch peers during it.
if (originalBlocksLeft == -1)
originalBlocksLeft = blocksLeft;
else
log.info("Chain download switched to {}", peer);
if (blocksLeft == 0) {
doneDownload();
done.release();
}
}
@Override
public void onBlocksDownloaded(Peer peer, Block block, int blocksLeft) {
if (caughtUp)
return;
if (blocksLeft == 0) {
caughtUp = true;
doneDownload();
done.release();
}
if (blocksLeft < 0 || originalBlocksLeft <= 0)
return;
double pct = 100.0 - (100.0 * (blocksLeft / (double) originalBlocksLeft));
if ((int) pct != lastPercent) {
progress(pct, blocksLeft, new Date(block.getTimeSeconds() * 1000));
lastPercent = (int) pct;
}
}
/**
* Called when download progress is made.
*
* @param pct the percentage of chain downloaded, estimated
* @param date the date of the last block downloaded
*/
protected void progress(double pct, int blocksSoFar, Date date) {
log.info(String.format("Chain download %d%% done with %d blocks to go, block date %s", (int) pct,
blocksSoFar, DateFormat.getDateTimeInstance().format(date)));
}
/**
* Called when download is initiated.
*
* @param blocks the number of blocks to download, estimated
*/
protected void startDownload(int blocks) {
if (blocks > 0 && originalBlocksLeft == -1)
log.info("Downloading block chain of size " + blocks + ". " +
(blocks > 1000 ? "This may take a while." : ""));
}
/**
* Called when we are done downloading the block chain.
*/
protected void doneDownload() {
}
/**
* Wait for the chain to be downloaded.
*/
public void await() throws InterruptedException {
done.acquire();
}
}

View File

@ -1,122 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* 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 com.dogecoin.dogecoinj.core;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.concurrent.ExecutionException;
/**
* <p>An implementation of {@link AbstractPeerEventListener} that listens to chain download events and tracks progress
* as a percentage. The default implementation prints progress to stdout, but you can subclass it and override the
* progress method to update a GUI instead.</p>
*/
public class DownloadProgressTracker extends AbstractPeerEventListener {
private static final Logger log = LoggerFactory.getLogger(DownloadProgressTracker.class);
private int originalBlocksLeft = -1;
private int lastPercent = 0;
private SettableFuture<Long> future = SettableFuture.create();
private boolean caughtUp = false;
@Override
public void onChainDownloadStarted(Peer peer, int blocksLeft) {
if (blocksLeft > 0 && originalBlocksLeft == -1)
startDownload(blocksLeft);
// Only mark this the first time, because this method can be called more than once during a chain download
// if we switch peers during it.
if (originalBlocksLeft == -1)
originalBlocksLeft = blocksLeft;
else
log.info("Chain download switched to {}", peer);
if (blocksLeft == 0) {
doneDownload();
future.set(peer.getBestHeight());
}
}
@Override
public void onBlocksDownloaded(Peer peer, Block block, int blocksLeft) {
if (caughtUp)
return;
if (blocksLeft == 0) {
caughtUp = true;
doneDownload();
future.set(peer.getBestHeight());
}
if (blocksLeft < 0 || originalBlocksLeft <= 0)
return;
double pct = 100.0 - (100.0 * (blocksLeft / (double) originalBlocksLeft));
if ((int) pct != lastPercent) {
progress(pct, blocksLeft, new Date(block.getTimeSeconds() * 1000));
lastPercent = (int) pct;
}
}
/**
* Called when download progress is made.
*
* @param pct the percentage of chain downloaded, estimated
* @param date the date of the last block downloaded
*/
protected void progress(double pct, int blocksSoFar, Date date) {
log.info(String.format("Chain download %d%% done with %d blocks to go, block date %s", (int) pct, blocksSoFar,
Utils.dateTimeFormat(date)));
}
/**
* Called when download is initiated.
*
* @param blocks the number of blocks to download, estimated
*/
protected void startDownload(int blocks) {
log.info("Downloading block chain of size " + blocks + ". " +
(blocks > 1000 ? "This may take a while." : ""));
}
/**
* Called when we are done downloading the block chain.
*/
protected void doneDownload() {
}
/**
* Wait for the chain to be downloaded.
*/
public void await() throws InterruptedException {
try {
future.get();
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Returns a listenable future that completes with the height of the best chain (as reported by the peer) once chain
* download seems to be finished.
*/
public ListenableFuture<Long> getFuture() {
return future;
}
}

View File

@ -1,95 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import java.util.Arrays;
/**
* Parses and generates private keys in the form used by the Bitcoin "dumpprivkey" command. This is the private key
* bytes with a header byte and 4 checksum bytes at the end. If there are 33 private key bytes instead of 32, then
* the last byte is a discriminator value for the compressed pubkey.
*/
public class DumpedPrivateKey extends VersionedChecksummedBytes {
private boolean compressed;
// Used by ECKey.getPrivateKeyEncoded()
DumpedPrivateKey(NetworkParameters params, byte[] keyBytes, boolean compressed) {
super(params.getDumpedPrivateKeyHeader(), encode(keyBytes, compressed));
this.compressed = compressed;
}
private static byte[] encode(byte[] keyBytes, boolean compressed) {
Preconditions.checkArgument(keyBytes.length == 32, "Private keys must be 32 bytes");
if (!compressed) {
return keyBytes;
} else {
// Keys that have compressed public components have an extra 1 byte on the end in dumped form.
byte[] bytes = new byte[33];
System.arraycopy(keyBytes, 0, bytes, 0, 32);
bytes[32] = 1;
return bytes;
}
}
/**
* Parses the given private key as created by the "dumpprivkey" Bitcoin C++ RPC.
*
* @param params The expected network parameters of the key. If you don't care, provide null.
* @param encoded The base58 encoded string.
* @throws AddressFormatException If the string is invalid or the header byte doesn't match the network params.
*/
public DumpedPrivateKey(NetworkParameters params, String encoded) throws AddressFormatException {
super(encoded);
if (params != null && version != params.getDumpedPrivateKeyHeader())
throw new AddressFormatException("Mismatched version number, trying to cross networks? " + version +
" vs " + params.getDumpedPrivateKeyHeader());
if (bytes.length == 33 && bytes[32] == 1) {
compressed = true;
bytes = Arrays.copyOf(bytes, 32); // Chop off the additional marker byte.
} else if (bytes.length == 32) {
compressed = false;
} else {
throw new AddressFormatException("Wrong number of bytes for a private key, not 32 or 33");
}
}
/**
* Returns an ECKey created from this encoded private key.
*/
public ECKey getKey() {
final ECKey key = ECKey.fromPrivate(bytes);
return compressed ? key : key.decompress();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DumpedPrivateKey other = (DumpedPrivateKey) o;
return Arrays.equals(bytes, other.bytes) &&
version == other.version &&
compressed == other.compressed;
}
@Override
public int hashCode() {
return Objects.hashCode(bytes, version, compressed);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,83 +0,0 @@
/**
* Copyright 2011 Steve Coughlan.
*
* 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 com.dogecoin.dogecoinj.core;
import java.io.IOException;
import java.io.OutputStream;
/**
* Parent class for header only messages that don't have a payload.
* Currently this includes getaddr, verack and special bitcoinj class UnknownMessage.
*/
public abstract class EmptyMessage extends Message {
private static final long serialVersionUID = 8240801253854151802L;
public EmptyMessage() {
length = 0;
}
public EmptyMessage(NetworkParameters params) {
super(params);
length = 0;
}
public EmptyMessage(NetworkParameters params, byte[] payload, int offset) throws ProtocolException {
super(params, payload, offset);
length = 0;
}
@Override
final protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
}
@Override
public int getMessageSize() {
return 0;
}
/* (non-Javadoc)
* @see Message#parse()
*/
@Override
void parse() throws ProtocolException {
}
/* (non-Javadoc)
* @see Message#parseLite()
*/
@Override
protected void parseLite() throws ProtocolException {
length = 0;
}
/* (non-Javadoc)
* @see Message#ensureParsed()
*/
@Override
public void ensureParsed() throws ProtocolException {
parsed = true;
}
/* (non-Javadoc)
* @see Message#bitcoinSerialize()
*/
@Override
public byte[] bitcoinSerialize() {
return new byte[0];
}
}

View File

@ -1,171 +0,0 @@
/**
* Copyright 2012 Matt Corallo
*
* 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 com.dogecoin.dogecoinj.core;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
/**
* <p>A FilteredBlock is used to relay a block with its transactions filtered using a {@link BloomFilter}. It consists
* of the block header and a {@link PartialMerkleTree} which contains the transactions which matched the filter.</p>
*/
public class FilteredBlock extends Message {
/** The protocol version at which Bloom filtering started to be supported. */
public static final int MIN_PROTOCOL_VERSION = 70001;
private Block header;
private PartialMerkleTree merkleTree;
private List<Sha256Hash> cachedTransactionHashes = null;
// A set of transactions whose hashes are a subset of getTransactionHashes()
// These were relayed as a part of the filteredblock getdata, ie likely weren't previously received as loose transactions
private Map<Sha256Hash, Transaction> associatedTransactions = new HashMap<Sha256Hash, Transaction>();
public FilteredBlock(NetworkParameters params, byte[] payloadBytes) throws ProtocolException {
super(params, payloadBytes, 0);
}
public FilteredBlock(NetworkParameters params, Block header, PartialMerkleTree pmt) {
super(params);
this.header = header;
this.merkleTree = pmt;
}
@Override
public void bitcoinSerializeToStream(OutputStream stream) throws IOException {
if (header.transactions == null)
header.bitcoinSerializeToStream(stream);
else
header.cloneAsHeader().bitcoinSerializeToStream(stream);
merkleTree.bitcoinSerializeToStream(stream);
}
@Override
void parse() throws ProtocolException {
long blockVersion = Utils.readUint32(payload, cursor);
byte[] headerBytes = new byte[Block.HEADER_SIZE];
System.arraycopy(payload, 0, headerBytes, 0, Block.HEADER_SIZE);
if (blockVersion == Block.BLOCK_VERSION_AUXPOW_AUXBLOCK) {
AuxPoWMessage auxPoWMessage = new AuxPoWMessage(payload, cursor + Block.HEADER_SIZE);
auxPoWMessage.parse();
this.cursor = auxPoWMessage.cursor;
header = new Block(params, headerBytes, new Block(params, auxPoWMessage.constructParentHeader()));
byte[] filteredBlock = new byte[Block.HEADER_SIZE + payload.length - cursor];
System.arraycopy(headerBytes, 0, filteredBlock, 0, headerBytes.length-1);
System.arraycopy(payload, cursor, filteredBlock, Block.HEADER_SIZE, payload.length-cursor);
merkleTree = new PartialMerkleTree(params, filteredBlock, Block.HEADER_SIZE);
} else {
header = new Block(params, headerBytes);
merkleTree = new PartialMerkleTree(params, payload, Block.HEADER_SIZE);
}
length = Block.HEADER_SIZE + merkleTree.getMessageSize();
}
@Override
protected void parseLite() throws ProtocolException {
}
/**
* Gets a list of leaf hashes which are contained in the partial merkle tree in this filtered block
*
* @throws ProtocolException If the partial merkle block is invalid or the merkle root of the partial merkle block doesnt match the block header
*/
public List<Sha256Hash> getTransactionHashes() throws VerificationException {
if (cachedTransactionHashes != null)
return Collections.unmodifiableList(cachedTransactionHashes);
List<Sha256Hash> hashesMatched = new LinkedList<Sha256Hash>();
if (header.getMerkleRoot().equals(merkleTree.getTxnHashAndMerkleRoot(hashesMatched))) {
cachedTransactionHashes = hashesMatched;
return Collections.unmodifiableList(cachedTransactionHashes);
} else
throw new VerificationException("Merkle root of block header does not match merkle root of partial merkle tree.");
}
/**
* Gets a copy of the block header
*/
public Block getBlockHeader() {
return header.cloneAsHeader();
}
/** Gets the hash of the block represented in this Filtered Block */
@Override
public Sha256Hash getHash() {
return header.getHash();
}
/**
* Provide this FilteredBlock with a transaction which is in its merkle tree
* @returns false if the tx is not relevant to this FilteredBlock
*/
public boolean provideTransaction(Transaction tx) throws VerificationException {
Sha256Hash hash = tx.getHash();
if (getTransactionHashes().contains(hash)) {
associatedTransactions.put(hash, tx);
return true;
} else
return false;
}
/** Gets the set of transactions which were provided using provideTransaction() which match in getTransactionHashes() */
public Map<Sha256Hash, Transaction> getAssociatedTransactions() {
return Collections.unmodifiableMap(associatedTransactions);
}
/** Number of transactions in this block, before it was filtered */
public int getTransactionCount() {
return merkleTree.getTransactionCount();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FilteredBlock block = (FilteredBlock) o;
if (!associatedTransactions.equals(block.associatedTransactions)) return false;
if (!header.equals(block.header)) return false;
if (!merkleTree.equals(block.merkleTree)) return false;
return true;
}
@Override
public int hashCode() {
int result = header.hashCode();
result = 31 * result + merkleTree.hashCode();
result = 31 * result + associatedTransactions.hashCode();
return result;
}
@Override
public String toString() {
return "FilteredBlock{" +
"merkleTree=" + merkleTree +
", header=" + header +
'}';
}
}

View File

@ -1,517 +0,0 @@
/*
* Copyright 2012 Matt Corallo.
* Copyright 2014 Andreas Schildbach
*
* 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 com.dogecoin.dogecoinj.core;
import com.dogecoin.dogecoinj.script.Script;
import com.dogecoin.dogecoinj.script.Script.VerifyFlag;
import com.dogecoin.dogecoinj.store.BlockStoreException;
import com.dogecoin.dogecoinj.store.FullPrunedBlockStore;
import com.dogecoin.dogecoinj.utils.DaemonThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import java.util.concurrent.*;
import static com.google.common.base.Preconditions.checkState;
/**
* <p>A FullPrunedBlockChain works in conjunction with a {@link FullPrunedBlockStore} to verify all the rules of the
* Bitcoin system, with the downside being a larg cost in system resources. Fully verifying means all unspent transaction
* outputs are stored. Once a transaction output is spent and that spend is buried deep enough, the data related to it
* is deleted to ensure disk space usage doesn't grow forever. For this reason a pruning node cannot serve the full
* block chain to other clients, but it nevertheless provides the same security guarantees as a regular Satoshi
* client does.</p>
*/
public class FullPrunedBlockChain extends AbstractBlockChain {
private static final Logger log = LoggerFactory.getLogger(FullPrunedBlockChain.class);
/** Keeps a map of block hashes to StoredBlocks. */
protected final FullPrunedBlockStore blockStore;
// Whether or not to execute scriptPubKeys before accepting a transaction (i.e. check signatures).
private boolean runScripts = true;
/**
* Constructs a BlockChain connected to the given wallet and store. To obtain a {@link Wallet} you can construct
* one from scratch, or you can deserialize a saved wallet from disk using {@link Wallet#loadFromFile(java.io.File)}
*/
public FullPrunedBlockChain(NetworkParameters params, Wallet wallet, FullPrunedBlockStore blockStore) throws BlockStoreException {
this(params, new ArrayList<BlockChainListener>(), blockStore);
if (wallet != null)
addWallet(wallet);
}
/**
* Constructs a BlockChain that has no wallet at all. This is helpful when you don't actually care about sending
* and receiving coins but rather, just want to explore the network data structures.
*/
public FullPrunedBlockChain(NetworkParameters params, FullPrunedBlockStore blockStore) throws BlockStoreException {
this(params, new ArrayList<BlockChainListener>(), blockStore);
}
/**
* Constructs a BlockChain connected to the given list of wallets and a store.
*/
public FullPrunedBlockChain(NetworkParameters params, List<BlockChainListener> listeners,
FullPrunedBlockStore blockStore) throws BlockStoreException {
super(params, listeners, blockStore);
this.blockStore = blockStore;
// Ignore upgrading for now
this.chainHead = blockStore.getVerifiedChainHead();
}
@Override
protected StoredBlock addToBlockStore(StoredBlock storedPrev, Block header, TransactionOutputChanges txOutChanges)
throws BlockStoreException, VerificationException {
StoredBlock newBlock = storedPrev.build(header);
blockStore.put(newBlock, new StoredUndoableBlock(newBlock.getHeader().getHash(), txOutChanges));
return newBlock;
}
@Override
protected StoredBlock addToBlockStore(StoredBlock storedPrev, Block block)
throws BlockStoreException, VerificationException {
StoredBlock newBlock = storedPrev.build(block);
blockStore.put(newBlock, new StoredUndoableBlock(newBlock.getHeader().getHash(), block.transactions));
return newBlock;
}
@Override
protected void rollbackBlockStore(int height) throws BlockStoreException {
throw new BlockStoreException("Unsupported");
}
@Override
protected boolean shouldVerifyTransactions() {
return true;
}
/**
* Whether or not to run scripts whilst accepting blocks (i.e. checking signatures, for most transactions).
* If you're accepting data from an untrusted node, such as one found via the P2P network, this should be set
* to true (which is the default). If you're downloading a chain from a node you control, script execution
* is redundant because you know the connected node won't relay bad data to you. In that case it's safe to set
* this to false and obtain a significant speedup.
*/
public void setRunScripts(boolean value) {
this.runScripts = value;
}
//TODO: Remove lots of duplicated code in the two connectTransactions
// TODO: execute in order of largest transaction (by input count) first
ExecutorService scriptVerificationExecutor = Executors.newFixedThreadPool(
Runtime.getRuntime().availableProcessors(), new DaemonThreadFactory());
/** A job submitted to the executor which verifies signatures. */
private static class Verifier implements Callable<VerificationException> {
final Transaction tx;
final List<Script> prevOutScripts;
final Set<VerifyFlag> verifyFlags;
public Verifier(final Transaction tx, final List<Script> prevOutScripts, final Set<VerifyFlag> verifyFlags) {
this.tx = tx; this.prevOutScripts = prevOutScripts; this.verifyFlags = verifyFlags;
}
@Nullable
@Override
public VerificationException call() throws Exception {
try{
ListIterator<Script> prevOutIt = prevOutScripts.listIterator();
for (int index = 0; index < tx.getInputs().size(); index++) {
tx.getInputs().get(index).getScriptSig().correctlySpends(tx, index, prevOutIt.next(), verifyFlags);
}
} catch (VerificationException e) {
return e;
}
return null;
}
}
/** Get the {@link Script} from the script bytes or null if it doesn't parse. */
@Nullable
private Script getScript(byte[] scriptBytes) {
try {
return new Script(scriptBytes);
} catch (Exception e) {
return null;
}
}
/**
* Get the address from the {@link Script} if it exists otherwise return empty string "".
* @param script The script.
* @return The address.
*/
private String getScriptAddress(@Nullable Script script) {
String address = "";
try {
if (script != null) {
address = script.getToAddress(params, true).toString();
}
} catch (Exception e) {
}
return address;
}
/**
* Get the {@link Script.ScriptType} of this script.
* @param script The script.
* @return The script type.
*/
private Script.ScriptType getScriptType(@Nullable Script script) {
if (script != null) {
return script.getScriptType();
}
return Script.ScriptType.NO_TYPE;
}
@Override
protected TransactionOutputChanges connectTransactions(int height, Block block)
throws VerificationException, BlockStoreException {
checkState(lock.isHeldByCurrentThread());
if (block.transactions == null)
throw new RuntimeException("connectTransactions called with Block that didn't have transactions!");
if (!params.passesCheckpoint(height, block.getHash()))
throw new VerificationException("Block failed checkpoint lockin at " + height);
blockStore.beginDatabaseBatchWrite();
LinkedList<UTXO> txOutsSpent = new LinkedList<UTXO>();
LinkedList<UTXO> txOutsCreated = new LinkedList<UTXO>();
long sigOps = 0;
final Set<VerifyFlag> verifyFlags = EnumSet.noneOf(VerifyFlag.class);
if (block.getTimeSeconds() >= NetworkParameters.BIP16_ENFORCE_TIME)
verifyFlags.add(VerifyFlag.P2SH);
if (scriptVerificationExecutor.isShutdown())
scriptVerificationExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
List<Future<VerificationException>> listScriptVerificationResults = new ArrayList<Future<VerificationException>>(block.transactions.size());
try {
if (!params.isCheckpoint(height)) {
// BIP30 violator blocks are ones that contain a duplicated transaction. They are all in the
// checkpoints list and we therefore only check non-checkpoints for duplicated transactions here. See the
// BIP30 document for more details on this: https://github.com/bitcoin/bips/blob/master/bip-0030.mediawiki
for (Transaction tx : block.transactions) {
Sha256Hash hash = tx.getHash();
// If we already have unspent outputs for this hash, we saw the tx already. Either the block is
// being added twice (bug) or the block is a BIP30 violator.
if (blockStore.hasUnspentOutputs(hash, tx.getOutputs().size()))
throw new VerificationException("Block failed BIP30 test!");
if (verifyFlags.contains(VerifyFlag.P2SH)) // We already check non-BIP16 sigops in Block.verifyTransactions(true)
sigOps += tx.getSigOpCount();
}
}
Coin totalFees = Coin.ZERO;
Coin coinbaseValue = null;
for (final Transaction tx : block.transactions) {
boolean isCoinBase = tx.isCoinBase();
Coin valueIn = Coin.ZERO;
Coin valueOut = Coin.ZERO;
final List<Script> prevOutScripts = new LinkedList<Script>();
if (!isCoinBase) {
// For each input of the transaction remove the corresponding output from the set of unspent
// outputs.
for (int index = 0; index < tx.getInputs().size(); index++) {
TransactionInput in = tx.getInputs().get(index);
UTXO prevOut = blockStore.getTransactionOutput(in.getOutpoint().getHash(),
in.getOutpoint().getIndex());
if (prevOut == null)
throw new VerificationException("Attempted to spend a non-existent or already spent output!");
// Coinbases can't be spent until they mature, to avoid re-orgs destroying entire transaction
// chains. The assumption is there will ~never be re-orgs deeper than the spendable coinbase
// chain depth.
if (prevOut.isCoinbase()) {
if (height - prevOut.getHeight() < params.getSpendableCoinbaseDepth()) {
throw new VerificationException("Tried to spend coinbase at depth " + (height - prevOut.getHeight()));
}
}
// TODO: Check we're not spending the genesis transaction here. Satoshis code won't allow it.
valueIn = valueIn.add(prevOut.getValue());
if (verifyFlags.contains(VerifyFlag.P2SH)) {
if (new Script(prevOut.getScriptBytes()).isPayToScriptHash())
sigOps += Script.getP2SHSigOpCount(in.getScriptBytes());
if (sigOps > Block.MAX_BLOCK_SIGOPS)
throw new VerificationException("Too many P2SH SigOps in block");
}
prevOutScripts.add(new Script(prevOut.getScriptBytes()));
//in.getScriptSig().correctlySpends(tx, index, new Script(params, prevOut.getScriptBytes(), 0, prevOut.getScriptBytes().length));
blockStore.removeUnspentTransactionOutput(prevOut);
txOutsSpent.add(prevOut);
}
}
Sha256Hash hash = tx.getHash();
for (TransactionOutput out : tx.getOutputs()) {
valueOut = valueOut.add(out.getValue());
// For each output, add it to the set of unspent outputs so it can be consumed in future.
Script script = getScript(out.getScriptBytes());
UTXO newOut = new UTXO(hash,
out.getIndex(),
out.getValue(),
height, isCoinBase,
out.getScriptBytes(),
getScriptAddress(script),
getScriptType(script).ordinal());
blockStore.addUnspentTransactionOutput(newOut);
txOutsCreated.add(newOut);
}
// All values were already checked for being non-negative (as it is verified in Transaction.verify())
// but we check again here just for defence in depth. Transactions with zero output value are OK.
if (valueOut.signum() < 0 || valueOut.compareTo(NetworkParameters.MAX_MONEY) > 0)
throw new VerificationException("Transaction output value out of range");
if (isCoinBase) {
coinbaseValue = valueOut;
} else {
if (valueIn.compareTo(valueOut) < 0 || valueIn.compareTo(NetworkParameters.MAX_MONEY) > 0)
throw new VerificationException("Transaction input value out of range");
totalFees = totalFees.add(valueIn.subtract(valueOut));
}
if (!isCoinBase && runScripts) {
// Because correctlySpends modifies transactions, this must come after we are done with tx
FutureTask<VerificationException> future = new FutureTask<VerificationException>(new Verifier(tx, prevOutScripts, verifyFlags));
scriptVerificationExecutor.execute(future);
listScriptVerificationResults.add(future);
}
}
if (totalFees.compareTo(NetworkParameters.MAX_MONEY) > 0 || block.getBlockInflation(height).add(totalFees).compareTo(coinbaseValue) < 0)
throw new VerificationException("Transaction fees out of range");
for (Future<VerificationException> future : listScriptVerificationResults) {
VerificationException e;
try {
e = future.get();
} catch (InterruptedException thrownE) {
throw new RuntimeException(thrownE); // Shouldn't happen
} catch (ExecutionException thrownE) {
log.error("Script.correctlySpends threw a non-normal exception: " + thrownE.getCause());
throw new VerificationException("Bug in Script.correctlySpends, likely script malformed in some new and interesting way.", thrownE);
}
if (e != null)
throw e;
}
} catch (VerificationException e) {
scriptVerificationExecutor.shutdownNow();
blockStore.abortDatabaseBatchWrite();
throw e;
} catch (BlockStoreException e) {
scriptVerificationExecutor.shutdownNow();
blockStore.abortDatabaseBatchWrite();
throw e;
}
return new TransactionOutputChanges(txOutsCreated, txOutsSpent);
}
@Override
/**
* Used during reorgs to connect a block previously on a fork
*/
protected synchronized TransactionOutputChanges connectTransactions(StoredBlock newBlock)
throws VerificationException, BlockStoreException, PrunedException {
checkState(lock.isHeldByCurrentThread());
if (!params.passesCheckpoint(newBlock.getHeight(), newBlock.getHeader().getHash()))
throw new VerificationException("Block failed checkpoint lockin at " + newBlock.getHeight());
blockStore.beginDatabaseBatchWrite();
StoredUndoableBlock block = blockStore.getUndoBlock(newBlock.getHeader().getHash());
if (block == null) {
// We're trying to re-org too deep and the data needed has been deleted.
blockStore.abortDatabaseBatchWrite();
throw new PrunedException(newBlock.getHeader().getHash());
}
TransactionOutputChanges txOutChanges;
try {
List<Transaction> transactions = block.getTransactions();
if (transactions != null) {
LinkedList<UTXO> txOutsSpent = new LinkedList<UTXO>();
LinkedList<UTXO> txOutsCreated = new LinkedList<UTXO>();
long sigOps = 0;
final Set<VerifyFlag> verifyFlags = EnumSet.noneOf(VerifyFlag.class);
if (newBlock.getHeader().getTimeSeconds() >= NetworkParameters.BIP16_ENFORCE_TIME)
verifyFlags.add(VerifyFlag.P2SH);
if (!params.isCheckpoint(newBlock.getHeight())) {
for(Transaction tx : transactions) {
Sha256Hash hash = tx.getHash();
if (blockStore.hasUnspentOutputs(hash, tx.getOutputs().size()))
throw new VerificationException("Block failed BIP30 test!");
}
}
Coin totalFees = Coin.ZERO;
Coin coinbaseValue = null;
if (scriptVerificationExecutor.isShutdown())
scriptVerificationExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
List<Future<VerificationException>> listScriptVerificationResults = new ArrayList<Future<VerificationException>>(transactions.size());
for(final Transaction tx : transactions) {
boolean isCoinBase = tx.isCoinBase();
Coin valueIn = Coin.ZERO;
Coin valueOut = Coin.ZERO;
final List<Script> prevOutScripts = new LinkedList<Script>();
if (!isCoinBase) {
for (int index = 0; index < tx.getInputs().size(); index++) {
final TransactionInput in = tx.getInputs().get(index);
final UTXO prevOut = blockStore.getTransactionOutput(in.getOutpoint().getHash(),
in.getOutpoint().getIndex());
if (prevOut == null)
throw new VerificationException("Attempted spend of a non-existent or already spent output!");
if (prevOut.isCoinbase() && newBlock.getHeight() - prevOut.getHeight() < params.getSpendableCoinbaseDepth())
throw new VerificationException("Tried to spend coinbase at depth " + (newBlock.getHeight() - prevOut.getHeight()));
valueIn = valueIn.add(prevOut.getValue());
if (verifyFlags.contains(VerifyFlag.P2SH)) {
Script script = new Script(prevOut.getScriptBytes());
if (script.isPayToScriptHash())
sigOps += Script.getP2SHSigOpCount(in.getScriptBytes());
if (sigOps > Block.MAX_BLOCK_SIGOPS)
throw new VerificationException("Too many P2SH SigOps in block");
}
prevOutScripts.add(new Script(prevOut.getScriptBytes()));
blockStore.removeUnspentTransactionOutput(prevOut);
txOutsSpent.add(prevOut);
}
}
Sha256Hash hash = tx.getHash();
for (TransactionOutput out : tx.getOutputs()) {
valueOut = valueOut.add(out.getValue());
Script script = getScript(out.getScriptBytes());
UTXO newOut = new UTXO(hash,
out.getIndex(),
out.getValue(),
newBlock.getHeight(),
isCoinBase,
out.getScriptBytes(),
getScriptAddress(script),
getScriptType(script).ordinal());
blockStore.addUnspentTransactionOutput(newOut);
txOutsCreated.add(newOut);
}
// All values were already checked for being non-negative (as it is verified in Transaction.verify())
// but we check again here just for defence in depth. Transactions with zero output value are OK.
if (valueOut.signum() < 0 || valueOut.compareTo(NetworkParameters.MAX_MONEY) > 0)
throw new VerificationException("Transaction output value out of range");
if (isCoinBase) {
coinbaseValue = valueOut;
} else {
if (valueIn.compareTo(valueOut) < 0 || valueIn.compareTo(NetworkParameters.MAX_MONEY) > 0)
throw new VerificationException("Transaction input value out of range");
totalFees = totalFees.add(valueIn.subtract(valueOut));
}
if (!isCoinBase) {
// Because correctlySpends modifies transactions, this must come after we are done with tx
FutureTask<VerificationException> future = new FutureTask<VerificationException>(new Verifier(tx, prevOutScripts, verifyFlags));
scriptVerificationExecutor.execute(future);
listScriptVerificationResults.add(future);
}
}
if (totalFees.compareTo(NetworkParameters.MAX_MONEY) > 0 ||
newBlock.getHeader().getBlockInflation(newBlock.getHeight()).add(totalFees).compareTo(coinbaseValue) < 0)
throw new VerificationException("Transaction fees out of range");
txOutChanges = new TransactionOutputChanges(txOutsCreated, txOutsSpent);
for (Future<VerificationException> future : listScriptVerificationResults) {
VerificationException e;
try {
e = future.get();
} catch (InterruptedException thrownE) {
throw new RuntimeException(thrownE); // Shouldn't happen
} catch (ExecutionException thrownE) {
log.error("Script.correctlySpends threw a non-normal exception: " + thrownE.getCause());
throw new VerificationException("Bug in Script.correctlySpends, likely script malformed in some new and interesting way.", thrownE);
}
if (e != null)
throw e;
}
} else {
txOutChanges = block.getTxOutChanges();
if (!params.isCheckpoint(newBlock.getHeight()))
for(UTXO out : txOutChanges.txOutsCreated) {
Sha256Hash hash = out.getHash();
if (blockStore.getTransactionOutput(hash, out.getIndex()) != null)
throw new VerificationException("Block failed BIP30 test!");
}
for (UTXO out : txOutChanges.txOutsCreated)
blockStore.addUnspentTransactionOutput(out);
for (UTXO out : txOutChanges.txOutsSpent)
blockStore.removeUnspentTransactionOutput(out);
}
} catch (VerificationException e) {
scriptVerificationExecutor.shutdownNow();
blockStore.abortDatabaseBatchWrite();
throw e;
} catch (BlockStoreException e) {
scriptVerificationExecutor.shutdownNow();
blockStore.abortDatabaseBatchWrite();
throw e;
}
return txOutChanges;
}
/**
* This is broken for blocks that do not pass BIP30, so all BIP30-failing blocks which are allowed to fail BIP30
* must be checkpointed.
*/
@Override
protected void disconnectTransactions(StoredBlock oldBlock) throws PrunedException, BlockStoreException {
checkState(lock.isHeldByCurrentThread());
blockStore.beginDatabaseBatchWrite();
try {
StoredUndoableBlock undoBlock = blockStore.getUndoBlock(oldBlock.getHeader().getHash());
if (undoBlock == null) throw new PrunedException(oldBlock.getHeader().getHash());
TransactionOutputChanges txOutChanges = undoBlock.getTxOutChanges();
for(UTXO out : txOutChanges.txOutsSpent)
blockStore.addUnspentTransactionOutput(out);
for(UTXO out : txOutChanges.txOutsCreated)
blockStore.removeUnspentTransactionOutput(out);
} catch (PrunedException e) {
blockStore.abortDatabaseBatchWrite();
throw e;
} catch (BlockStoreException e) {
blockStore.abortDatabaseBatchWrite();
throw e;
}
}
@Override
protected void doSetChainHead(StoredBlock chainHead) throws BlockStoreException {
checkState(lock.isHeldByCurrentThread());
blockStore.setVerifiedChainHead(chainHead);
blockStore.commitDatabaseBatchWrite();
}
@Override
protected void notSettingChainHead() throws BlockStoreException {
blockStore.abortDatabaseBatchWrite();
}
@Override
protected StoredBlock getStoredBlockInCurrentScope(Sha256Hash hash) throws BlockStoreException {
checkState(lock.isHeldByCurrentThread());
return blockStore.getOnceUndoableStoredBlock(hash);
}
}

View File

@ -1,30 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
/**
* Represents the "getaddr" P2P protocol message, which requests network {@link AddressMessage}s from a peer. Not to
* be confused with {@link Address} which is sort of like an account number.
*/
public class GetAddrMessage extends EmptyMessage {
private static final long serialVersionUID = 6204437624599661503L;
public GetAddrMessage(NetworkParameters params) {
super(params);
}
}

View File

@ -1,122 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
/**
* Represents the "getblocks" P2P network message, which requests the hashes of the parts of the block chain we're
* missing. Those blocks can then be downloaded with a {@link GetDataMessage}.
*/
public class GetBlocksMessage extends Message {
private static final long serialVersionUID = 3479412877853645644L;
protected long version;
protected List<Sha256Hash> locator;
protected Sha256Hash stopHash;
public GetBlocksMessage(NetworkParameters params, List<Sha256Hash> locator, Sha256Hash stopHash) {
super(params);
this.version = protocolVersion;
this.locator = locator;
this.stopHash = stopHash;
}
public GetBlocksMessage(NetworkParameters params, byte[] payload) throws ProtocolException {
super(params, payload, 0);
}
@Override
protected void parseLite() throws ProtocolException {
cursor = offset;
version = readUint32();
int startCount = (int) readVarInt();
if (startCount > 500)
throw new ProtocolException("Number of locators cannot be > 500, received: " + startCount);
length = (int) (cursor - offset + ((startCount + 1) * 32));
}
@Override
public void parse() throws ProtocolException {
cursor = offset;
version = readUint32();
int startCount = (int) readVarInt();
if (startCount > 500)
throw new ProtocolException("Number of locators cannot be > 500, received: " + startCount);
locator = new ArrayList<Sha256Hash>(startCount);
for (int i = 0; i < startCount; i++) {
locator.add(readHash());
}
stopHash = readHash();
}
public List<Sha256Hash> getLocator() {
return locator;
}
public Sha256Hash getStopHash() {
return stopHash;
}
@Override
public String toString() {
StringBuffer b = new StringBuffer();
b.append("getblocks: ");
for (Sha256Hash hash : locator) {
b.append(hash.toString());
b.append(" ");
}
return b.toString();
}
@Override
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
// Version, for some reason.
Utils.uint32ToByteStreamLE(NetworkParameters.PROTOCOL_VERSION, stream);
// Then a vector of block hashes. This is actually a "block locator", a set of block
// identifiers that spans the entire chain with exponentially increasing gaps between
// them, until we end up at the genesis block. See CBlockLocator::Set()
stream.write(new VarInt(locator.size()).encode());
for (Sha256Hash hash : locator) {
// Have to reverse as wire format is little endian.
stream.write(Utils.reverseBytes(hash.getBytes()));
}
// Next, a block ID to stop at.
stream.write(Utils.reverseBytes(stopHash.getBytes()));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GetBlocksMessage other = (GetBlocksMessage) o;
return version == other.version &&
locator.size() == other.locator.size() &&
locator.containsAll(other.locator) &&
stopHash.equals(other.stopHash);
}
@Override
public int hashCode() {
int hashCode = (int) version ^ "getblocks".hashCode();
for (Sha256Hash aLocator : locator) hashCode ^= aLocator.hashCode();
hashCode ^= stopHash.hashCode();
return hashCode;
}
}

View File

@ -1,66 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
/**
* Represents the "getdata" P2P network message, which requests the contents of blocks or transactions given their
* hashes.
*/
public class GetDataMessage extends ListMessage {
private static final long serialVersionUID = 2754681589501709887L;
public GetDataMessage(NetworkParameters params, byte[] payloadBytes) throws ProtocolException {
super(params, payloadBytes);
}
/**
* Deserializes a 'getdata' message.
* @param params NetworkParameters object.
* @param payload Bitcoin protocol formatted byte array containing message content.
* @param parseLazy Whether to perform a full parse immediately or delay until a read is requested.
* @param parseRetain Whether to retain the backing byte array for quick reserialization.
* If true and the backing byte array is invalidated due to modification of a field then
* the cached bytes may be repopulated and retained if the message is serialized again in the future.
* @param length The length of message if known. Usually this is provided when deserializing of the wire
* as the length will be provided as part of the header. If unknown then set to Message.UNKNOWN_LENGTH
* @throws ProtocolException
*/
public GetDataMessage(NetworkParameters params, byte[] payload, boolean parseLazy, boolean parseRetain, int length)
throws ProtocolException {
super(params, payload, parseLazy, parseRetain, length);
}
public GetDataMessage(NetworkParameters params) {
super(params);
}
public void addTransaction(Sha256Hash hash) {
addItem(new InventoryItem(InventoryItem.Type.Transaction, hash));
}
public void addBlock(Sha256Hash hash) {
addItem(new InventoryItem(InventoryItem.Type.Block, hash));
}
public void addFilteredBlock(Sha256Hash hash) {
addItem(new InventoryItem(InventoryItem.Type.FilteredBlock, hash));
}
public Sha256Hash getHashOf(int i) {
return getItems().get(i).hash;
}
}

View File

@ -1,69 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import java.util.List;
/**
* The "getheaders" command is structurally identical to "getblocks", but has different meaning. On receiving this
* message a Bitcoin node returns matching blocks up to the limit, but without the bodies. It is useful as an
* optimization: when your wallet does not contain any keys created before a particular time, you don't have to download
* the bodies for those blocks because you know there are no relevant transactions.
*/
public class GetHeadersMessage extends GetBlocksMessage {
public GetHeadersMessage(NetworkParameters params, List<Sha256Hash> locator, Sha256Hash stopHash) {
super(params, locator, stopHash);
}
public GetHeadersMessage(NetworkParameters params, byte[] payload) throws ProtocolException {
super(params, payload);
}
@Override
public String toString() {
StringBuffer b = new StringBuffer();
b.append("getheaders: ");
for (Sha256Hash hash : locator) {
b.append(hash.toString());
b.append(" ");
}
return b.toString();
}
/**
* Compares two getheaders messages. Note that even though they are structurally identical a GetHeadersMessage
* will not compare equal to a GetBlocksMessage containing the same data.
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GetHeadersMessage other = (GetHeadersMessage) o;
return version == other.version &&
locator.size() == other.locator.size() &&
locator.containsAll(other.locator) &&
stopHash.equals(other.stopHash);
}
@Override
public int hashCode() {
int hashCode = (int) version ^ "getheaders".hashCode();
for (Sha256Hash aLocator : locator) hashCode ^= aLocator.hashCode();
hashCode ^= stopHash.hashCode();
return hashCode;
}
}

View File

@ -1,105 +0,0 @@
/*
* Copyright 2014 the bitcoinj authors
*
* 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 com.dogecoin.dogecoinj.core;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
/**
* This command is supported only by <a href="http://github.com/bitcoinxt/bitcoinxt">Bitcoin XT</a> nodes, which
* advertise themselves using the second service bit flag. It requests a query of the UTXO set keyed by a set of
* outpoints (i.e. tx hash and output index). The result contains a bitmap of spentness flags, and the contents of
* the associated outputs if they were found. The results aren't authenticated by anything, so the peer could lie,
* or a man in the middle could swap out its answer for something else.
*/
public class GetUTXOsMessage extends Message {
public static final int MIN_PROTOCOL_VERSION = 70002;
/** Bitmask of service flags required for a node to support this command (0x3) */
public static final int SERVICE_FLAGS_REQUIRED = 3;
private boolean includeMempool;
private ImmutableList<TransactionOutPoint> outPoints;
public GetUTXOsMessage(NetworkParameters params, List<TransactionOutPoint> outPoints, boolean includeMempool) {
super(params);
this.outPoints = ImmutableList.copyOf(outPoints);
this.includeMempool = includeMempool;
}
public GetUTXOsMessage(NetworkParameters params, byte[] payloadBytes) {
super(params, payloadBytes, 0);
}
@Override
protected void parse() throws ProtocolException {
includeMempool = readBytes(1)[0] == 1;
long numOutpoints = readVarInt();
ImmutableList.Builder<TransactionOutPoint> list = ImmutableList.builder();
for (int i = 0; i < numOutpoints; i++) {
TransactionOutPoint outPoint = new TransactionOutPoint(params, payload, cursor);
list.add(outPoint);
cursor += outPoint.getMessageSize();
}
outPoints = list.build();
length = cursor;
}
public boolean getIncludeMempool() {
return includeMempool;
}
public ImmutableList<TransactionOutPoint> getOutPoints() {
return outPoints;
}
@Override
protected void parseLite() throws ProtocolException {
// Not needed.
}
@Override
void bitcoinSerializeToStream(OutputStream stream) throws IOException {
stream.write(new byte[]{1}); // include mempool.
stream.write(new VarInt(outPoints.size()).encode());
for (TransactionOutPoint outPoint : outPoints) {
outPoint.bitcoinSerializeToStream(stream);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GetUTXOsMessage that = (GetUTXOsMessage) o;
if (includeMempool != that.includeMempool) return false;
if (!outPoints.equals(that.outPoints)) return false;
return true;
}
@Override
public int hashCode() {
int result = (includeMempool ? 1 : 0);
result = 31 * result + outPoints.hashCode();
return result;
}
}

View File

@ -1,130 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* A protocol message that contains a repeated series of block headers, sent in response to the "getheaders" command.
* This is useful when you want to traverse the chain but know you don't care about the block contents, for example,
* because you have a freshly created wallet with no keys.
*/
public class HeadersMessage extends Message {
private static final Logger log = LoggerFactory.getLogger(HeadersMessage.class);
// The main client will never send us more than this number of headers.
public static final int MAX_HEADERS = 2000;
private List<Block> blockHeaders;
public HeadersMessage(NetworkParameters params, byte[] payload) throws ProtocolException {
super(params, payload, 0);
}
public HeadersMessage(NetworkParameters params, Block... headers) throws ProtocolException {
super(params);
blockHeaders = Arrays.asList(headers);
}
public HeadersMessage(NetworkParameters params, List<Block> headers) throws ProtocolException {
super(params);
blockHeaders = headers;
}
@Override
public void bitcoinSerializeToStream(OutputStream stream) throws IOException {
stream.write(new VarInt(blockHeaders.size()).encode());
for (Block header : blockHeaders) {
if (header.transactions == null)
header.bitcoinSerializeToStream(stream);
else
header.cloneAsHeader().bitcoinSerializeToStream(stream);
stream.write(0);
}
}
@Override
protected void parseLite() throws ProtocolException {
if (length == UNKNOWN_LENGTH) {
int saveCursor = cursor;
long numHeaders = readVarInt();
cursor = saveCursor;
// Each header has 80 bytes and one more byte for transactions number which is 00.
length = 81 * (int)numHeaders;
}
}
@Override
void parse() throws ProtocolException {
long numHeaders = readVarInt();
if (numHeaders > MAX_HEADERS)
throw new ProtocolException("Too many headers: got " + numHeaders + " which is larger than " +
MAX_HEADERS);
blockHeaders = new ArrayList<Block>();
for (int i = 0; i < numHeaders; ++i) {
// Read the block version. If it's not an aux block all is fine, else throw out the aux stuff
long blockVersion = Utils.readUint32(payload, cursor);
byte[] blockHeader;
Block newBlockHeader;
if (blockVersion == Block.BLOCK_VERSION_AUXPOW_AUXBLOCK) {
blockHeader = readBytes(80);
byte[] tmp = new byte[81];
System.arraycopy(blockHeader, 0, tmp, 0, blockHeader.length);
tmp[80] = 0;
blockHeader = tmp;
AuxPoWMessage auxPoWMessage = new AuxPoWMessage(payload, cursor);
auxPoWMessage.parse();
this.cursor = auxPoWMessage.cursor;
if (readBytes(1)[0] != 0)
throw new ProtocolException("Block header does not end with a null byte");
newBlockHeader = new Block(this.params, blockHeader, true, true, 81, new Block(params, auxPoWMessage.constructParentHeader()));
} else {
// Read 80 bytes of the header and one more byte for the transaction list, which is always a 00 because the
// transaction list is empty.
blockHeader = readBytes(81);
newBlockHeader = new Block(this.params, blockHeader, true, true, 81);
}
if (blockHeader[80] != 0)
throw new ProtocolException("Block header does not end with a null byte");
blockHeaders.add(newBlockHeader);
}
if (log.isDebugEnabled()) {
for (int i = 0; i < numHeaders; ++i) {
log.debug(this.blockHeaders.get(i).toString());
}
}
}
public List<Block> getBlockHeaders() {
return blockHeaders;
}
}

View File

@ -1,43 +0,0 @@
/*
* Copyright 2013 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Thrown to indicate that you don't have enough money available to perform the requested operation.
*/
public class InsufficientMoneyException extends Exception {
/** Contains the number of satoshis that would have been required to complete the operation. */
@Nullable
public final Coin missing;
protected InsufficientMoneyException() {
this.missing = null;
}
public InsufficientMoneyException(Coin missing) {
this(missing, "Insufficient money, missing " + missing + " satoshis");
}
public InsufficientMoneyException(Coin missing, String message) {
super(message);
this.missing = checkNotNull(missing);
}
}

View File

@ -1,60 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
public class InventoryItem {
/**
* 4 byte uint32 type field + 32 byte hash
*/
static final int MESSAGE_LENGTH = 36;
public enum Type {
Error,
Transaction,
Block,
FilteredBlock
}
public final Type type;
public final Sha256Hash hash;
public InventoryItem(Type type, Sha256Hash hash) {
this.type = type;
this.hash = hash;
}
@Override
public String toString() {
return type.toString() + ": " + hash;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
InventoryItem other = (InventoryItem) o;
return type == other.type &&
hash.equals(other.hash);
}
@Override
public int hashCode() {
return hash.hashCode() + type.ordinal();
}
}

View File

@ -1,74 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import static com.google.common.base.Preconditions.checkArgument;
/**
* <p>Represents the "inv" P2P network message. An inv contains a list of hashes of either blocks or transactions. It's
* a bandwidth optimization - on receiving some data, a (fully validating) peer sends every connected peer an inv
* containing the hash of what it saw. It'll only transmit the full thing if a peer asks for it with a
* {@link GetDataMessage}.</p>
*/
public class InventoryMessage extends ListMessage {
private static final long serialVersionUID = -7050246551646107066L;
/** A hard coded constant in the protocol. */
public static final int MAX_INV_SIZE = 50000;
public InventoryMessage(NetworkParameters params, byte[] bytes) throws ProtocolException {
super(params, bytes);
}
/**
* Deserializes an 'inv' message.
* @param params NetworkParameters object.
* @param payload Bitcoin protocol formatted byte array containing message content.
* @param parseLazy Whether to perform a full parse immediately or delay until a read is requested.
* @param parseRetain Whether to retain the backing byte array for quick reserialization.
* If true and the backing byte array is invalidated due to modification of a field then
* the cached bytes may be repopulated and retained if the message is serialized again in the future.
* @param length The length of message if known. Usually this is provided when deserializing of the wire
* as the length will be provided as part of the header. If unknown then set to Message.UNKNOWN_LENGTH
* @throws ProtocolException
*/
public InventoryMessage(NetworkParameters params, byte[] payload, boolean parseLazy, boolean parseRetain, int length)
throws ProtocolException {
super(params, payload, parseLazy, parseRetain, length);
}
public InventoryMessage(NetworkParameters params) {
super(params);
}
public void addBlock(Block block) {
addItem(new InventoryItem(InventoryItem.Type.Block, block.getHash()));
}
public void addTransaction(Transaction tx) {
addItem(new InventoryItem(InventoryItem.Type.Transaction, tx.getHash()));
}
/** Creates a new inv message for the given transactions. */
public static InventoryMessage with(Transaction... txns) {
checkArgument(txns.length > 0);
InventoryMessage result = new InventoryMessage(txns[0].getParams());
for (Transaction tx : txns)
result.addTransaction(tx);
return result;
}
}

View File

@ -1,135 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Abstract superclass of classes with list based payload, ie InventoryMessage and GetDataMessage.
*/
public abstract class ListMessage extends Message {
private static final long serialVersionUID = -4275896329391143643L;
private long arrayLen;
// For some reason the compiler complains if this is inside InventoryItem
protected List<InventoryItem> items;
public static final long MAX_INVENTORY_ITEMS = 50000;
public ListMessage(NetworkParameters params, byte[] bytes) throws ProtocolException {
super(params, bytes, 0);
}
public ListMessage(NetworkParameters params, byte[] payload, boolean parseLazy, boolean parseRetain, int length)
throws ProtocolException {
super(params, payload, 0, parseLazy, parseRetain, length);
}
public ListMessage(NetworkParameters params) {
super(params);
items = new ArrayList<InventoryItem>();
length = 1; //length of 0 varint;
}
public List<InventoryItem> getItems() {
maybeParse();
return Collections.unmodifiableList(items);
}
public void addItem(InventoryItem item) {
unCache();
length -= VarInt.sizeOf(items.size());
items.add(item);
length += VarInt.sizeOf(items.size()) + InventoryItem.MESSAGE_LENGTH;
}
public void removeItem(int index) {
unCache();
length -= VarInt.sizeOf(items.size());
items.remove(index);
length += VarInt.sizeOf(items.size()) - InventoryItem.MESSAGE_LENGTH;
}
@Override
protected void parseLite() throws ProtocolException {
arrayLen = readVarInt();
if (arrayLen > MAX_INVENTORY_ITEMS)
throw new ProtocolException("Too many items in INV message: " + arrayLen);
length = (int) (cursor - offset + (arrayLen * InventoryItem.MESSAGE_LENGTH));
}
@Override
public void parse() throws ProtocolException {
// An inv is vector<CInv> where CInv is int+hash. The int is either 1 or 2 for tx or block.
items = new ArrayList<InventoryItem>((int) arrayLen);
for (int i = 0; i < arrayLen; i++) {
if (cursor + InventoryItem.MESSAGE_LENGTH > payload.length) {
throw new ProtocolException("Ran off the end of the INV");
}
int typeCode = (int) readUint32();
InventoryItem.Type type;
// See ppszTypeName in net.h
switch (typeCode) {
case 0:
type = InventoryItem.Type.Error;
break;
case 1:
type = InventoryItem.Type.Transaction;
break;
case 2:
type = InventoryItem.Type.Block;
break;
case 3:
type = InventoryItem.Type.FilteredBlock;
break;
default:
throw new ProtocolException("Unknown CInv type: " + typeCode);
}
InventoryItem item = new InventoryItem(type, readHash());
items.add(item);
}
payload = null;
}
@Override
public void bitcoinSerializeToStream(OutputStream stream) throws IOException {
stream.write(new VarInt(items.size()).encode());
for (InventoryItem i : items) {
// Write out the type code.
Utils.uint32ToByteStreamLE(i.type.ordinal(), stream);
// And now the hash.
stream.write(Utils.reverseBytes(i.hash.getBytes()));
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ListMessage other = (ListMessage) o;
return items.equals(other.items);
}
@Override
public int hashCode() {
return items.hashCode();
}
}

View File

@ -1,318 +0,0 @@
/*
* Copyright 2012 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import com.dogecoin.dogecoinj.utils.Threading;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
/**
* <p>Tracks transactions that are being announced across the network. Typically one is created for you by a
* {@link PeerGroup} and then given to each Peer to update. The current purpose is to let Peers update the confidence
* (number of peers broadcasting). It helps address an attack scenario in which a malicious remote peer (or several)
* feeds you invalid transactions, eg, ones that spend coins which don't exist. If you don't see most of the peers
* announce the transaction within a reasonable time, it may be that the TX is not valid. Alternatively, an attacker
* may control your entire internet connection: in this scenario counting broadcasting peers does not help you.</p>
*
* <p>It is <b>not</b> at this time directly equivalent to the Satoshi clients memory pool, which tracks
* all transactions not currently included in the best chain - it's simply a cache.</p>
*/
public class MemoryPool {
private static final Logger log = LoggerFactory.getLogger(MemoryPool.class);
protected ReentrantLock lock = Threading.lock("mempool");
// For each transaction we may have seen:
// - only its hash in an inv packet
// - the full transaction itself, if we asked for it to be sent to us (or a peer sent it regardless), or if we
// sent it.
//
// Before we see the full transaction, we need to track how many peers advertised it, so we can estimate its
// confidence pre-chain inclusion assuming an un-tampered with network connection. After we see the full transaction
// we need to switch from tracking that data in the Entry to tracking it in the TransactionConfidence object itself.
private static class WeakTransactionReference extends WeakReference<Transaction> {
public Sha256Hash hash;
public WeakTransactionReference(Transaction tx, ReferenceQueue<Transaction> queue) {
super(tx, queue);
hash = tx.getHash();
}
}
private static class Entry {
// Invariants: one of the two fields must be null, to indicate which is used.
Set<PeerAddress> addresses;
// We keep a weak reference to the transaction. This means that if no other bit of code finds the transaction
// worth keeping around it will drop out of memory and we will, at some point, forget about it, which means
// both addresses and tx.get() will be null. When this happens the WeakTransactionReference appears in the queue
// allowing us to delete the associated entry (the tx itself has already gone away).
WeakTransactionReference tx;
}
private LinkedHashMap<Sha256Hash, Entry> memoryPool;
// This ReferenceQueue gets entries added to it when they are only weakly reachable, ie, the MemoryPool is the
// only thing that is tracking the transaction anymore. We check it from time to time and delete memoryPool entries
// corresponding to expired transactions. In this way memory usage of the system is in line with however many
// transactions you actually care to track the confidence of. We can still end up with lots of hashes being stored
// if our peers flood us with invs but the MAX_SIZE param caps this.
private ReferenceQueue<Transaction> referenceQueue;
/** The max size of a memory pool created with the no-args constructor. */
public static final int MAX_SIZE = 1000;
/**
* Creates a memory pool that will track at most the given number of transactions (allowing you to bound memory
* usage).
* @param size Max number of transactions to track. The pool will fill up to this size then stop growing.
*/
public MemoryPool(final int size) {
memoryPool = new LinkedHashMap<Sha256Hash, Entry>() {
@Override
protected boolean removeEldestEntry(Map.Entry<Sha256Hash, Entry> entry) {
// An arbitrary choice to stop the memory used by tracked transactions getting too huge in the event
// of some kind of DoS attack.
return size() > size;
}
};
referenceQueue = new ReferenceQueue<Transaction>();
}
/**
* Creates a memory pool that will track at most {@link MemoryPool#MAX_SIZE} entries. You should normally use
* this constructor.
*/
public MemoryPool() {
this(MAX_SIZE);
}
/**
* If any transactions have expired due to being only weakly reachable through us, go ahead and delete their
* memoryPool entries - it means we downloaded the transaction and sent it to various event listeners, none of
* which bothered to keep a reference. Typically, this is because the transaction does not involve any keys that
* are relevant to any of our wallets.
*/
private void cleanPool() {
lock.lock();
try {
Reference<? extends Transaction> ref;
while ((ref = referenceQueue.poll()) != null) {
// Find which transaction got deleted by the GC.
WeakTransactionReference txRef = (WeakTransactionReference) ref;
// And remove the associated map entry so the other bits of memory can also be reclaimed.
memoryPool.remove(txRef.hash);
}
} finally {
lock.unlock();
}
}
/**
* Returns the number of peers that have seen the given hash recently.
*/
public int numBroadcastPeers(Sha256Hash txHash) {
lock.lock();
try {
cleanPool();
Entry entry = memoryPool.get(txHash);
if (entry == null) {
// No such TX known.
return 0;
} else if (entry.tx == null) {
// We've seen at least one peer announce with an inv.
checkNotNull(entry.addresses);
return entry.addresses.size();
} else {
final Transaction tx = entry.tx.get();
if (tx == null) {
// We previously downloaded this transaction, but nothing cared about it so the garbage collector threw
// it away. We also deleted the set that tracked which peers had seen it. Treat this case as a zero and
// just delete it from the map.
memoryPool.remove(txHash);
return 0;
} else {
checkState(entry.addresses == null);
return tx.getConfidence().numBroadcastPeers();
}
}
} finally {
lock.unlock();
}
}
/**
* Puts the tx into the table and returns either it, or a different Transaction object that has the same hash.
* Unlike seen and the other methods, this one does not imply that a tx has been announced by a peer and does
* not mark it as such.
*/
public Transaction intern(Transaction tx) {
lock.lock();
try {
cleanPool();
Entry entry = memoryPool.get(tx.getHash());
if (entry != null) {
// This TX or its hash have been previously interned.
if (entry.tx != null) {
// We already interned it (but may have thrown it away).
checkState(entry.addresses == null);
// We only want one canonical object instance for a transaction no matter how many times it is
// deserialized.
Transaction transaction = entry.tx.get();
if (transaction != null) {
// We saw it before and kept it around. Hand back the canonical copy.
tx = transaction;
}
return tx;
} else {
// We received a transaction that we have previously seen announced but not downloaded until now.
checkNotNull(entry.addresses);
entry.tx = new WeakTransactionReference(tx, referenceQueue);
Set<PeerAddress> addrs = entry.addresses;
entry.addresses = null;
TransactionConfidence confidence = tx.getConfidence();
log.debug("Adding tx [{}] {} to the memory pool",
confidence.numBroadcastPeers(), tx.getHashAsString());
for (PeerAddress a : addrs) {
markBroadcast(a, tx);
}
return tx;
}
} else {
// This often happens when we are downloading a Bloom filtered chain, or recursively downloading
// dependencies of a relevant transaction (see Peer.downloadDependencies).
log.debug("Provided with a downloaded transaction we didn't see announced yet: {}", tx.getHashAsString());
entry = new Entry();
entry.tx = new WeakTransactionReference(tx, referenceQueue);
memoryPool.put(tx.getHash(), entry);
return tx;
}
} finally {
lock.unlock();
}
}
/**
* Called by peers when they receive a "tx" message containing a valid serialized transaction.
* @param tx The TX deserialized from the wire.
* @param byPeer The Peer that received it.
* @return An object that is semantically the same TX but may be a different object instance.
*/
public Transaction seen(Transaction tx, PeerAddress byPeer) {
lock.lock();
try {
final Transaction interned = intern(tx);
markBroadcast(byPeer, interned);
return interned;
} finally {
lock.unlock();
}
}
/**
* Called by peers when they see a transaction advertised in an "inv" message. It either will increase the
* confidence of the pre-existing transaction or will just keep a record of the address for future usage.
*/
public void seen(Sha256Hash hash, PeerAddress byPeer) {
lock.lock();
try {
cleanPool();
Entry entry = memoryPool.get(hash);
if (entry != null) {
// This TX or its hash have been previously announced.
if (entry.tx != null) {
checkState(entry.addresses == null);
Transaction tx = entry.tx.get();
if (tx != null) {
markBroadcast(byPeer, tx);
log.debug("{}: Peer announced transaction we have seen before [{}] {}",
byPeer, tx.getConfidence().numBroadcastPeers(), tx.getHashAsString());
} else {
// The inv is telling us about a transaction that we previously downloaded, and threw away
// because nothing found it interesting enough to keep around. So do nothing.
}
} else {
checkNotNull(entry.addresses);
entry.addresses.add(byPeer);
log.debug("{}: Peer announced transaction we have seen announced before [{}] {}",
byPeer, entry.addresses.size(), hash);
}
} else {
// This TX has never been seen before.
entry = new Entry();
// TODO: Using hashsets here is inefficient compared to just having an array.
entry.addresses = new HashSet<PeerAddress>();
entry.addresses.add(byPeer);
memoryPool.put(hash, entry);
log.info("{}: Peer announced new transaction [1] {}", byPeer, hash);
}
} finally {
lock.unlock();
}
}
private void markBroadcast(PeerAddress byPeer, Transaction tx) {
checkState(lock.isHeldByCurrentThread());
final TransactionConfidence confidence = tx.getConfidence();
if (confidence.markBroadcastBy(byPeer))
confidence.queueListeners(TransactionConfidence.Listener.ChangeReason.SEEN_PEERS);
}
/**
* Returns the {@link Transaction} for the given hash if we have downloaded it, or null if that hash is unknown or
* we only saw advertisements for it yet or it has been downloaded but garbage collected due to nowhere else
* holding a reference to it.
*/
@Nullable
public Transaction get(Sha256Hash hash) {
lock.lock();
try {
Entry entry = memoryPool.get(hash);
if (entry == null) return null; // Unknown.
if (entry.tx == null) return null; // Seen but only in advertisements.
if (entry.tx.get() == null) return null; // Was downloaded but garbage collected.
Transaction tx = entry.tx.get();
checkNotNull(tx);
return tx;
} finally {
lock.unlock();
}
}
/**
* Returns true if the TX identified by hash has been seen before (ie, in an inv). Note that a transaction that
* was broadcast, downloaded and nothing kept a reference to it will eventually be cleared out by the garbage
* collector and wasSeen() will return false - it does not keep a permanent record of every hash ever broadcast.
*/
public boolean maybeWasSeen(Sha256Hash hash) {
lock.lock();
try {
Entry entry = memoryPool.get(hash);
return entry != null;
} finally {
lock.unlock();
}
}
}

View File

@ -1,38 +0,0 @@
/*
* Copyright 2012 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import java.io.IOException;
import java.io.OutputStream;
/**
* The "mempool" message asks a remote peer to announce all transactions in its memory pool, possibly restricted by
* any Bloom filter set on the connection. The list of transaction hashes comes back in an inv message. Note that
* this is different to the {@link TxConfidenceTable} object which doesn't try to keep track of all pending transactions,
* it's just a holding area for transactions that a part of the app may find interesting. The mempool message has
* no fields.
*/
public class MemoryPoolMessage extends Message {
@Override
void parse() throws ProtocolException {}
@Override
protected void parseLite() throws ProtocolException {}
@Override
void bitcoinSerializeToStream(OutputStream stream) throws IOException {}
}

View File

@ -1,527 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* 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 com.dogecoin.dogecoinj.core;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.math.BigInteger;
import java.util.Arrays;
import static com.google.common.base.Preconditions.checkState;
/**
* <p>A Message is a data structure that can be serialized/deserialized using both the Bitcoin proprietary serialization
* format and built-in Java object serialization. Specific types of messages that are used both in the block chain,
* and on the wire, are derived from this class.</p>
*/
public abstract class Message implements Serializable {
private static final Logger log = LoggerFactory.getLogger(Message.class);
private static final long serialVersionUID = -3561053461717079135L;
public static final int MAX_SIZE = 0x02000000; // 32MB
public static final int UNKNOWN_LENGTH = Integer.MIN_VALUE;
// Useful to ensure serialize/deserialize are consistent with each other.
private static final boolean SELF_CHECK = false;
// The offset is how many bytes into the provided byte array this message payload starts at.
protected transient int offset;
// The cursor keeps track of where we are in the byte array as we parse it.
// Note that it's relative to the start of the array NOT the start of the message payload.
protected transient int cursor;
protected transient int length = UNKNOWN_LENGTH;
// The raw message payload bytes themselves.
protected transient byte[] payload;
protected transient boolean parsed = false;
protected transient boolean recached = false;
protected transient final boolean parseLazy;
protected transient final boolean parseRetain;
protected transient int protocolVersion;
protected transient byte[] checksum;
// This will be saved by subclasses that implement Serializable.
protected NetworkParameters params;
/**
* This exists for the Java serialization framework to use only.
*/
protected Message() {
parsed = true;
parseLazy = false;
parseRetain = false;
}
Message(NetworkParameters params) {
this.params = params;
parsed = true;
parseLazy = false;
parseRetain = false;
}
Message(NetworkParameters params, byte[] payload, int offset, int protocolVersion) throws ProtocolException {
this(params, payload, offset, protocolVersion, false, false, UNKNOWN_LENGTH);
}
/**
*
* @param params NetworkParameters object.
* @param payload Bitcoin protocol formatted byte array containing message content.
* @param offset The location of the first payload byte within the array.
* @param protocolVersion Bitcoin protocol version.
* @param parseLazy Whether to perform a full parse immediately or delay until a read is requested.
* @param parseRetain Whether to retain the backing byte array for quick reserialization.
* If true and the backing byte array is invalidated due to modification of a field then
* the cached bytes may be repopulated and retained if the message is serialized again in the future.
* @param length The length of message payload if known. Usually this is provided when deserializing of the wire
* as the length will be provided as part of the header. If unknown then set to Message.UNKNOWN_LENGTH
* @throws ProtocolException
*/
Message(NetworkParameters params, byte[] payload, int offset, int protocolVersion, boolean parseLazy, boolean parseRetain, int length) throws ProtocolException {
this.parseLazy = parseLazy;
this.parseRetain = parseRetain;
this.protocolVersion = protocolVersion;
this.params = params;
this.payload = payload;
this.cursor = this.offset = offset;
this.length = length;
if (parseLazy) {
parseLite();
} else {
parseLite();
parse();
parsed = true;
}
if (this.length == UNKNOWN_LENGTH)
checkState(false, "Length field has not been set in constructor for %s after %s parse. " +
"Refer to Message.parseLite() for detail of required Length field contract.",
getClass().getSimpleName(), parseLazy ? "lite" : "full");
if (SELF_CHECK) {
selfCheck(payload, offset);
}
if (parseRetain || !parsed)
return;
this.payload = null;
}
private void selfCheck(byte[] payload, int offset) {
if (!(this instanceof VersionMessage)) {
maybeParse();
byte[] payloadBytes = new byte[cursor - offset];
System.arraycopy(payload, offset, payloadBytes, 0, cursor - offset);
byte[] reserialized = bitcoinSerialize();
if (!Arrays.equals(reserialized, payloadBytes))
throw new RuntimeException("Serialization is wrong: \n" +
Utils.HEX.encode(reserialized) + " vs \n" +
Utils.HEX.encode(payloadBytes));
}
}
Message(NetworkParameters params, byte[] payload, int offset) throws ProtocolException {
this(params, payload, offset, NetworkParameters.PROTOCOL_VERSION, false, false, UNKNOWN_LENGTH);
}
Message(NetworkParameters params, byte[] payload, int offset, boolean parseLazy, boolean parseRetain, int length) throws ProtocolException {
this(params, payload, offset, NetworkParameters.PROTOCOL_VERSION, parseLazy, parseRetain, length);
}
// These methods handle the serialization/deserialization using the custom Bitcoin protocol.
// It's somewhat painful to work with in Java, so some of these objects support a second
// serialization mechanism - the standard Java serialization system. This is used when things
// are serialized to the wallet.
abstract void parse() throws ProtocolException;
/**
* Perform the most minimal parse possible to calculate the length of the message payload.
* This is only required for subclasses of ChildMessage as root level messages will have their length passed
* into the constructor.
* <p/>
* Implementations should adhere to the following contract: If parseLazy = true the 'length'
* field must be set before returning. If parseLazy = false the length field must be set either
* within the parseLite() method OR the parse() method. The overriding requirement is that length
* must be set to non UNKNOWN_MESSAGE value by the time the constructor exits.
*
* @return
* @throws ProtocolException
*/
protected abstract void parseLite() throws ProtocolException;
/**
* Ensure the object is parsed if needed. This should be called in every getter before returning a value.
* If the lazy parse flag is not set this is a method returns immediately.
*/
protected synchronized void maybeParse() {
if (parsed || payload == null)
return;
try {
parse();
parsed = true;
if (!parseRetain)
payload = null;
} catch (ProtocolException e) {
throw new LazyParseException("ProtocolException caught during lazy parse. For safe access to fields call ensureParsed before attempting read or write access", e);
}
}
/**
* In lazy parsing mode access to getters and setters may throw an unchecked LazyParseException. If guaranteed safe access is required
* this method will force parsing to occur immediately thus ensuring LazyParseExeption will never be thrown from this Message.
* If the Message contains child messages (e.g. a Block containing Transaction messages) this will not force child messages to parse.
* <p/>
* This could be overidden for Transaction and it's child classes to ensure the entire tree of Message objects is parsed.
*
* @throws ProtocolException
*/
public void ensureParsed() throws ProtocolException {
try {
maybeParse();
} catch (LazyParseException e) {
if (e.getCause() instanceof ProtocolException)
throw (ProtocolException) e.getCause();
throw new ProtocolException(e);
}
}
/**
* To be called before any change of internal values including any setters. This ensures any cached byte array is
* removed after performing a lazy parse if necessary to ensure the object is fully populated.
* <p/>
* Child messages of this object(e.g. Transactions belonging to a Block) will not have their internal byte caches
* invalidated unless they are also modified internally.
*/
protected void unCache() {
maybeParse();
checksum = null;
payload = null;
recached = false;
}
protected void adjustLength(int newArraySize, int adjustment) {
if (length == UNKNOWN_LENGTH)
return;
// Our own length is now unknown if we have an unknown length adjustment.
if (adjustment == UNKNOWN_LENGTH) {
length = UNKNOWN_LENGTH;
return;
}
length += adjustment;
// Check if we will need more bytes to encode the length prefix.
if (newArraySize == 1)
length++; // The assumption here is we never call adjustLength with the same arraySize as before.
else if (newArraySize != 0)
length += VarInt.sizeOf(newArraySize) - VarInt.sizeOf(newArraySize - 1);
}
/**
* used for unit testing
*/
public boolean isParsed() {
return parsed;
}
/**
* used for unit testing
*/
public boolean isCached() {
return payload != null;
}
public boolean isRecached() {
return recached;
}
/**
* Should only used by BitcoinSerializer for cached checksum
*
* @return the checksum
*/
byte[] getChecksum() {
return checksum;
}
/**
* Should only used by BitcoinSerializer for caching checksum
*
* @param checksum the checksum to set
*/
void setChecksum(byte[] checksum) {
if (checksum.length != 4)
throw new IllegalArgumentException("Checksum length must be 4 bytes, actual length: " + checksum.length);
this.checksum = checksum;
}
/**
* Returns a copy of the array returned by {@link Message#unsafeBitcoinSerialize()}, which is safe to mutate.
* If you need extra performance and can guarantee you won't write to the array, you can use the unsafe version.
*
* @return a freshly allocated serialized byte array
*/
public byte[] bitcoinSerialize() {
byte[] bytes = unsafeBitcoinSerialize();
byte[] copy = new byte[bytes.length];
System.arraycopy(bytes, 0, copy, 0, bytes.length);
return copy;
}
/**
* Serialize this message to a byte array that conforms to the bitcoin wire protocol.
* <br/>
* This method may return the original byte array used to construct this message if the
* following conditions are met:
* <ol>
* <li>1) The message was parsed from a byte array with parseRetain = true</li>
* <li>2) The message has not been modified</li>
* <li>3) The array had an offset of 0 and no surplus bytes</li>
* </ol>
*
* If condition 3 is not met then an copy of the relevant portion of the array will be returned.
* Otherwise a full serialize will occur. For this reason you should only use this API if you can guarantee you
* will treat the resulting array as read only.
*
* @return a byte array owned by this object, do NOT mutate it.
*/
public byte[] unsafeBitcoinSerialize() {
// 1st attempt to use a cached array.
if (payload != null) {
if (offset == 0 && length == payload.length) {
// Cached byte array is the entire message with no extras so we can return as is and avoid an array
// copy.
return payload;
}
byte[] buf = new byte[length];
System.arraycopy(payload, offset, buf, 0, length);
return buf;
}
// No cached array available so serialize parts by stream.
ByteArrayOutputStream stream = new UnsafeByteArrayOutputStream(length < 32 ? 32 : length + 32);
try {
bitcoinSerializeToStream(stream);
} catch (IOException e) {
// Cannot happen, we are serializing to a memory stream.
}
if (parseRetain) {
// A free set of steak knives!
// If there happens to be a call to this method we gain an opportunity to recache
// the byte array and in this case it contains no bytes from parent messages.
// This give a dual benefit. Releasing references to the larger byte array so that it
// it is more likely to be GC'd. And preventing double serializations. E.g. calculating
// merkle root calls this method. It is will frequently happen prior to serializing the block
// which means another call to bitcoinSerialize is coming. If we didn't recache then internal
// serialization would occur a 2nd time and every subsequent time the message is serialized.
payload = stream.toByteArray();
cursor = cursor - offset;
offset = 0;
recached = true;
length = payload.length;
return payload;
}
// Record length. If this Message wasn't parsed from a byte stream it won't have length field
// set (except for static length message types). Setting it makes future streaming more efficient
// because we can preallocate the ByteArrayOutputStream buffer and avoid resizing.
byte[] buf = stream.toByteArray();
length = buf.length;
return buf;
}
/**
* Serialize this message to the provided OutputStream using the bitcoin wire format.
*
* @param stream
* @throws IOException
*/
final public void bitcoinSerialize(OutputStream stream) throws IOException {
// 1st check for cached bytes.
if (payload != null && length != UNKNOWN_LENGTH) {
stream.write(payload, offset, length);
return;
}
bitcoinSerializeToStream(stream);
}
/**
* Serializes this message to the provided stream. If you just want the raw bytes use bitcoinSerialize().
*/
void bitcoinSerializeToStream(OutputStream stream) throws IOException {
log.error("Error: {} class has not implemented bitcoinSerializeToStream method. Generating message with no payload", getClass());
}
/**
* This method is a NOP for all classes except Block and Transaction. It is only declared in Message
* so BitcoinSerializer can avoid 2 instanceof checks + a casting.
*/
public Sha256Hash getHash() {
throw new UnsupportedOperationException();
}
/**
* This should be overridden to extract correct message size in the case of lazy parsing. Until this method is
* implemented in a subclass of ChildMessage lazy parsing may have no effect.
*
* This default implementation is a safe fall back that will ensure it returns a correct value by parsing the message.
*/
public int getMessageSize() {
if (length != UNKNOWN_LENGTH)
return length;
maybeParse();
if (length == UNKNOWN_LENGTH)
checkState(false, "Length field has not been set in %s after full parse.", getClass().getSimpleName());
return length;
}
long readUint32() throws ProtocolException {
try {
long u = Utils.readUint32(payload, cursor);
cursor += 4;
return u;
} catch (ArrayIndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
}
Sha256Hash readHash() throws ProtocolException {
try {
byte[] hash = new byte[32];
System.arraycopy(payload, cursor, hash, 0, 32);
// We have to flip it around, as it's been read off the wire in little endian.
// Not the most efficient way to do this but the clearest.
hash = Utils.reverseBytes(hash);
cursor += 32;
return new Sha256Hash(hash);
} catch (IndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
}
long readInt64() throws ProtocolException {
try {
long u = Utils.readInt64(payload, cursor);
cursor += 8;
return u;
} catch (ArrayIndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
}
BigInteger readUint64() throws ProtocolException {
try {
// Java does not have an unsigned 64 bit type. So scrape it off the wire then flip.
byte[] valbytes = new byte[8];
System.arraycopy(payload, cursor, valbytes, 0, 8);
valbytes = Utils.reverseBytes(valbytes);
cursor += valbytes.length;
return new BigInteger(valbytes);
} catch (IndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
}
long readVarInt() throws ProtocolException {
return readVarInt(0);
}
long readVarInt(int offset) throws ProtocolException {
try {
VarInt varint = new VarInt(payload, cursor + offset);
cursor += offset + varint.getOriginalSizeInBytes();
return varint.value;
} catch (ArrayIndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
}
byte[] readBytes(int length) throws ProtocolException {
if (length > MAX_SIZE) {
throw new ProtocolException("Claimed byte array length too large: " + length);
}
try {
byte[] b = new byte[length];
System.arraycopy(payload, cursor, b, 0, length);
cursor += length;
return b;
} catch (IndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
}
byte[] readByteArray() throws ProtocolException {
long len = readVarInt();
return readBytes((int)len);
}
String readStr() throws ProtocolException {
try {
VarInt varInt = new VarInt(payload, cursor);
if (varInt.value == 0) {
cursor += 1;
return "";
}
cursor += varInt.getOriginalSizeInBytes();
if (varInt.value > MAX_SIZE) {
throw new ProtocolException("Claimed var_str length too large: " + varInt.value);
}
byte[] characters = new byte[(int) varInt.value];
System.arraycopy(payload, cursor, characters, 0, characters.length);
cursor += characters.length;
try {
return new String(characters, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e); // Cannot happen, UTF-8 is always supported.
}
} catch (ArrayIndexOutOfBoundsException e) {
throw new ProtocolException(e);
} catch (IndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
}
boolean hasMoreBytes() {
return cursor < payload.length;
}
/** Network parameters this message was created with. */
public NetworkParameters getParams() {
return params;
}
public static class LazyParseException extends RuntimeException {
private static final long serialVersionUID = 6971943053112975594L;
public LazyParseException(String message, Throwable cause) {
super(message, cause);
}
public LazyParseException(String message) {
super(message);
}
}
}

View File

@ -1,38 +0,0 @@
/**
* Copyright 2014 Andreas Schildbach
*
* 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 com.dogecoin.dogecoinj.core;
import java.io.Serializable;
/**
* Classes implementing this interface represent a monetary value, such as a Bitcoin or fiat amount.
*/
public interface Monetary extends Serializable {
/**
* Returns the absolute value of exponent of the value of a "smallest unit" in scientific notation. For Bitcoin, a
* satoshi is worth 1E-8 so this would be 8.
*/
int smallestUnitExponent();
/**
* Returns the number of "smallest units" of this monetary value. For Bitcoin, this would be the number of satoshis.
*/
long getValue();
int signum();
}

View File

@ -1,394 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* 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 com.dogecoin.dogecoinj.core;
import com.dogecoin.dogecoinj.params.*;
import com.dogecoin.dogecoinj.script.Script;
import com.dogecoin.dogecoinj.script.ScriptOpCodes;
import com.google.common.base.Objects;
import com.google.common.math.LongMath;
import org.spongycastle.util.encoders.Hex;
import javax.annotation.Nullable;
import java.io.ByteArrayOutputStream;
import java.io.Serializable;
import java.math.BigInteger;
import java.util.*;
import static com.dogecoin.dogecoinj.core.Coin.*;
/**
* <p>NetworkParameters contains the data needed for working with an instantiation of a Bitcoin chain.</p>
*
* <p>This is an abstract class, concrete instantiations can be found in the params package. There are four:
* one for the main network ({@link MainNetParams}), one for the public test network, and two others that are
* intended for unit testing and local app development purposes. Although this class contains some aliases for
* them, you are encouraged to call the static get() methods on each specific params class directly.</p>
*/
public abstract class NetworkParameters implements Serializable {
/**
* The protocol version this library implements.
*/
public static final int PROTOCOL_VERSION = 70003;
/**
* The alert signing key originally owned by Satoshi, and now passed on to Gavin along with a few others.
*/
public static final byte[] SATOSHI_KEY = Hex.decode("04d4da7a5dae4db797d9b0644d57a5cd50e05a70f36091cd62e2fc41c98ded06340be5a43a35e185690cd9cde5d72da8f6d065b499b06f51dcfba14aad859f443a");
/** The string returned by getId() for the main, production network where people trade things. */
public static final String ID_MAINNET = "org.dogecoin.production";
/** The string returned by getId() for the testnet. */
public static final String ID_TESTNET = "org.dogecoin.test";
/** The string returned by getId() for regtest mode. */
public static final String ID_REGTEST = "org.dogecoin.regtest";
/** Unit test network. */
public static final String ID_UNITTESTNET = "org.dogecoinj.unittest";
/** The string used by the payment protocol to represent the main net. */
public static final String PAYMENT_PROTOCOL_ID_MAINNET = "main";
/** The string used by the payment protocol to represent the test net. */
public static final String PAYMENT_PROTOCOL_ID_TESTNET = "test";
/** The string used by the payment protocol to represent unit testing (note that this is non-standard). */
public static final String PAYMENT_PROTOCOL_ID_UNIT_TESTS = "unittest";
public static final String PAYMENT_PROTOCOL_ID_REGTEST = "regtest";
// TODO: Seed nodes should be here as well.
protected Block genesisBlock;
protected BigInteger maxTarget;
protected int port;
protected long packetMagic; // Indicates message origin network and is used to seek to the next message when stream state is unknown.
protected int addressHeader;
protected int p2shHeader;
protected int dumpedPrivateKeyHeader;
protected int interval;
protected int newInterval;
protected int targetTimespan;
protected int newTargetTimespan;
protected int diffChangeTarget;
protected byte[] alertSigningKey;
protected int bip32HeaderPub;
protected int bip32HeaderPriv;
/**
* See getId(). This may be null for old deserialized wallets. In that case we derive it heuristically
* by looking at the port number.
*/
protected String id;
/**
* The depth of blocks required for a coinbase transaction to be spendable.
*/
protected int spendableCoinbaseDepth;
protected int subsidyDecreaseBlockCount;
protected int[] acceptableAddressCodes;
protected String[] dnsSeeds;
protected Map<Integer, Sha256Hash> checkpoints = new HashMap<Integer, Sha256Hash>();
protected NetworkParameters() {
alertSigningKey = SATOSHI_KEY;
genesisBlock = createGenesis(this);
}
private static Block createGenesis(NetworkParameters n) {
Block genesisBlock = new Block(n);
Transaction t = new Transaction(n);
try {
// A script containing the difficulty bits and the following message:
//
// "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"
byte[] bytes = Utils.HEX.decode
("04ffff001d0104084e696e746f6e646f");
t.addInput(new TransactionInput(n, t, bytes));
ByteArrayOutputStream scriptPubKeyBytes = new ByteArrayOutputStream();
Script.writeBytes(scriptPubKeyBytes, Utils.HEX.decode
("040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9"));
scriptPubKeyBytes.write(ScriptOpCodes.OP_CHECKSIG);
t.addOutput(new TransactionOutput(n, t, COIN.multiply(88), scriptPubKeyBytes.toByteArray()));
} catch (Exception e) {
// Cannot happen.
throw new RuntimeException(e);
}
genesisBlock.addTransaction(t);
return genesisBlock;
}
public static final int TARGET_TIMESPAN = 4 * 60 * 60; // 2 weeks per difficulty cycle, on average.
public static final int TARGET_TIMESPAN_NEW = 60; // 60s per difficulty cycle, on average. Kicks in after block 145k.
public static final int TARGET_SPACING = 1 * 60; // 10 minutes per block.
public static final int INTERVAL = TARGET_TIMESPAN / TARGET_SPACING;
public static final int INTERVAL_NEW = TARGET_TIMESPAN_NEW / TARGET_SPACING;
/**
* Blocks with a timestamp after this should enforce BIP 16, aka "Pay to script hash". This BIP changed the
* network rules in a soft-forking manner, that is, blocks that don't follow the rules are accepted but not
* mined upon and thus will be quickly re-orged out as long as the majority are enforcing the rule.
*/
public static final int BIP16_ENFORCE_TIME = 1333238400;
/**
* The maximum number of coins to be generated
* This is 92bn! We don't expect single transactions or blocks with that value.
* Therefore we can assume this will suffice.
*/
public static final long MAX_COINS = Long.MAX_VALUE / LongMath.pow(10, Coin.SMALLEST_UNIT_EXPONENT);
/**
* The maximum money to be generated
*/
public static final Coin MAX_MONEY = Coin.valueOf(Long.MAX_VALUE);
/** Alias for TestNet3Params.get(), use that instead. */
@Deprecated
public static NetworkParameters testNet() {
return TestNet3Params.get();
}
/** Alias for TestNet2Params.get(), use that instead. */
@Deprecated
public static NetworkParameters testNet2() {
return TestNet2Params.get();
}
/** Alias for TestNet3Params.get(), use that instead. */
@Deprecated
public static NetworkParameters testNet3() {
return TestNet3Params.get();
}
/** Alias for MainNetParams.get(), use that instead */
@Deprecated
public static NetworkParameters prodNet() {
return MainNetParams.get();
}
/** Returns a testnet params modified to allow any difficulty target. */
@Deprecated
public static NetworkParameters unitTests() {
return UnitTestParams.get();
}
/** Returns a standard regression test params (similar to unitTests) */
@Deprecated
public static NetworkParameters regTests() {
return RegTestParams.get();
}
/**
* A Java package style string acting as unique ID for these parameters
*/
public String getId() {
return id;
}
public abstract String getPaymentProtocolId();
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
NetworkParameters other = (NetworkParameters) o;
return getId().equals(other.getId());
}
@Override
public int hashCode() {
return Objects.hashCode(getId());
}
/** Returns the network parameters for the given string ID or NULL if not recognized. */
@Nullable
public static NetworkParameters fromID(String id) {
if (id.equals(ID_MAINNET)) {
return MainNetParams.get();
} else if (id.equals(ID_TESTNET)) {
return TestNet3Params.get();
} else if (id.equals(ID_UNITTESTNET)) {
return UnitTestParams.get();
} else if (id.equals(ID_REGTEST)) {
return RegTestParams.get();
} else {
return null;
}
}
/** Returns the network parameters for the given string paymentProtocolID or NULL if not recognized. */
@Nullable
public static NetworkParameters fromPmtProtocolID(String pmtProtocolId) {
if (pmtProtocolId.equals(PAYMENT_PROTOCOL_ID_MAINNET)) {
return MainNetParams.get();
} else if (pmtProtocolId.equals(PAYMENT_PROTOCOL_ID_TESTNET)) {
return TestNet3Params.get();
} else if (pmtProtocolId.equals(PAYMENT_PROTOCOL_ID_UNIT_TESTS)) {
return UnitTestParams.get();
} else if (pmtProtocolId.equals(PAYMENT_PROTOCOL_ID_REGTEST)) {
return RegTestParams.get();
} else {
return null;
}
}
public int getSpendableCoinbaseDepth() {
return spendableCoinbaseDepth;
}
/**
* Returns true if the block height is either not a checkpoint, or is a checkpoint and the hash matches.
*/
public boolean passesCheckpoint(int height, Sha256Hash hash) {
Sha256Hash checkpointHash = checkpoints.get(height);
return checkpointHash == null || checkpointHash.equals(hash);
}
/**
* Returns true if the given height has a recorded checkpoint.
*/
public boolean isCheckpoint(int height) {
Sha256Hash checkpointHash = checkpoints.get(height);
return checkpointHash != null;
}
public int getSubsidyDecreaseBlockCount() {
return subsidyDecreaseBlockCount;
}
/** Returns DNS names that when resolved, give IP addresses of active peers. */
public String[] getDnsSeeds() {
return dnsSeeds;
}
/**
* <p>Genesis block for this chain.</p>
*
* <p>The first block in every chain is a well known constant shared between all Bitcoin implemenetations. For a
* block to be valid, it must be eventually possible to work backwards to the genesis block by following the
* prevBlockHash pointers in the block headers.</p>
*
* <p>The genesis blocks for both test and main networks contain the timestamp of when they were created,
* and a message in the coinbase transaction. It says, <i>"The Times 03/Jan/2009 Chancellor on brink of second
* bailout for banks"</i>.</p>
*/
public Block getGenesisBlock() {
return genesisBlock;
}
/** Default TCP port on which to connect to nodes. */
public int getPort() {
return port;
}
/** The header bytes that identify the start of a packet on this network. */
public long getPacketMagic() {
return packetMagic;
}
/**
* First byte of a base58 encoded address. See {@link com.dogecoin.dogecoinj.core.Address}. This is the same as acceptableAddressCodes[0] and
* is the one used for "normal" addresses. Other types of address may be encountered with version codes found in
* the acceptableAddressCodes array.
*/
public int getAddressHeader() {
return addressHeader;
}
/**
* First byte of a base58 encoded P2SH address. P2SH addresses are defined as part of BIP0013.
*/
public int getP2SHHeader() {
return p2shHeader;
}
/** First byte of a base58 encoded dumped private key. See {@link com.dogecoin.dogecoinj.core.DumpedPrivateKey}. */
public int getDumpedPrivateKeyHeader() {
return dumpedPrivateKeyHeader;
}
/**
* How much time in seconds is supposed to pass between "interval" blocks. If the actual elapsed time is
* significantly different from this value, the network difficulty formula will produce a different value.
* Dogecoin before block 145k used 4 hours.
*/
public int getTargetTimespan() {
return targetTimespan;
}
/**
* How much time in seconds is supposed to pass between "interval" blocks. If the actual elapsed time is
* significantly different from this value, the network difficulty formula will produce a different value.
* Dogecoin after block 145k uses 60 seconds.
*/
public int getNewTargetTimespan() {
return newTargetTimespan;
}
/**
* The version codes that prefix addresses which are acceptable on this network. Although Satoshi intended these to
* be used for "versioning", in fact they are today used to discriminate what kind of data is contained in the
* address and to prevent accidentally sending coins across chains which would destroy them.
*/
public int[] getAcceptableAddressCodes() {
return acceptableAddressCodes;
}
/**
* If we are running in testnet-in-a-box mode, we allow connections to nodes with 0 non-genesis blocks.
*/
public boolean allowEmptyPeerChain() {
return true;
}
/** How many blocks pass between difficulty adjustment periods. Bitcoin standardises this to be 2015. */
public int getInterval() {
return interval;
}
/** How many blocks pass between difficulty adjustment periods. After new diff algo. */
public int getNewInterval() {
return newInterval;
}
/** Target for switch to new diff algo */
public int getDiffChangeTarget() {
return diffChangeTarget;
}
/** Maximum target represents the easiest allowable proof of work. */
public BigInteger getMaxTarget() {
return maxTarget;
}
/**
* The key used to sign {@link com.dogecoin.dogecoinj.core.AlertMessage}s. You can use {@link com.dogecoin.dogecoinj.core.ECKey#verify(byte[], byte[], byte[])} to verify
* signatures using it.
*/
public byte[] getAlertSigningKey() {
return alertSigningKey;
}
/** Returns the 4 byte header for BIP32 (HD) wallet - public key part. */
public int getBip32HeaderPub() {
return bip32HeaderPub;
}
/** Returns the 4 byte header for BIP32 (HD) wallet - private key part. */
public int getBip32HeaderPriv() {
return bip32HeaderPriv;
}
}

View File

@ -1,41 +0,0 @@
/*
* Copyright 2012 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import java.util.ArrayList;
import java.util.List;
/**
* Sent by a peer when a getdata request doesn't find the requested data in the mempool. It has the same format
* as an inventory message and lists the hashes of the missing items.
*/
public class NotFoundMessage extends InventoryMessage {
public static int MIN_PROTOCOL_VERSION = 70001;
public NotFoundMessage(NetworkParameters params) {
super(params);
}
public NotFoundMessage(NetworkParameters params, byte[] payloadBytes) throws ProtocolException {
super(params, payloadBytes);
}
public NotFoundMessage(NetworkParameters params, List<InventoryItem> items) {
super(params);
this.items = new ArrayList<InventoryItem>(items);
}
}

View File

@ -1,298 +0,0 @@
/**
* Copyright 2012 The Bitcoin Developers
* Copyright 2012 Matt Corallo
*
* 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 com.dogecoin.dogecoinj.core;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.dogecoin.dogecoinj.core.Utils.*;
/**
* <p>A data structure that contains proofs of block inclusion for one or more transactions, in an efficient manner.</p>
*
* <p>The encoding works as follows: we traverse the tree in depth-first order, storing a bit for each traversed node,
* signifying whether the node is the parent of at least one matched leaf txid (or a matched txid itself). In case we
* are at the leaf level, or this bit is 0, its merkle node hash is stored, and its children are not explored further.
* Otherwise, no hash is stored, but we recurse into both (or the only) child branch. During decoding, the same
* depth-first traversal is performed, consuming bits and hashes as they were written during encoding.</p>
*
* <p>The serialization is fixed and provides a hard guarantee about the encoded size,
* <tt>SIZE <= 10 + ceil(32.25*N)</tt> where N represents the number of leaf nodes of the partial tree. N itself
* is bounded by:</p>
*
* <p>
* N <= total_transactions<br>
* N <= 1 + matched_transactions*tree_height
* </p>
*
* <p><pre>The serialization format:
* - uint32 total_transactions (4 bytes)
* - varint number of hashes (1-3 bytes)
* - uint256[] hashes in depth-first order (<= 32*N bytes)
* - varint number of bytes of flag bits (1-3 bytes)
* - byte[] flag bits, packed per 8 in a byte, least significant bit first (<= 2*N-1 bits)
* The size constraints follow from this.</pre></p>
*/
public class PartialMerkleTree extends Message {
// the total number of transactions in the block
private int transactionCount;
// node-is-parent-of-matched-txid bits
private byte[] matchedChildBits;
// txids and internal hashes
private List<Sha256Hash> hashes;
public PartialMerkleTree(NetworkParameters params, byte[] payloadBytes, int offset) throws ProtocolException {
super(params, payloadBytes, offset);
}
/**
* Constructs a new PMT with the given bit set (little endian) and the raw list of hashes including internal hashes,
* taking ownership of the list.
*/
public PartialMerkleTree(NetworkParameters params, byte[] bits, List<Sha256Hash> hashes, int origTxCount) {
super(params);
this.matchedChildBits = bits;
this.hashes = hashes;
this.transactionCount = origTxCount;
}
/**
* Calculates a PMT given the list of leaf hashes and which leaves need to be included. The relevant interior hashes
* are calculated and a new PMT returned.
*/
public static PartialMerkleTree buildFromLeaves(NetworkParameters params, byte[] includeBits, List<Sha256Hash> allLeafHashes) {
// Calculate height of the tree.
int height = 0;
while (getTreeWidth(allLeafHashes.size(), height) > 1)
height++;
List<Boolean> bitList = new ArrayList<Boolean>();
List<Sha256Hash> hashes = new ArrayList<Sha256Hash>();
traverseAndBuild(height, 0, allLeafHashes, includeBits, bitList, hashes);
byte[] bits = new byte[(int)Math.ceil(bitList.size() / 8.0)];
for (int i = 0; i < bitList.size(); i++)
if (bitList.get(i))
Utils.setBitLE(bits, i);
return new PartialMerkleTree(params, bits, hashes, allLeafHashes.size());
}
@Override
public void bitcoinSerializeToStream(OutputStream stream) throws IOException {
uint32ToByteStreamLE(transactionCount, stream);
stream.write(new VarInt(hashes.size()).encode());
for (Sha256Hash hash : hashes)
stream.write(reverseBytes(hash.getBytes()));
stream.write(new VarInt(matchedChildBits.length).encode());
stream.write(matchedChildBits);
}
@Override
void parse() throws ProtocolException {
transactionCount = (int)readUint32();
int nHashes = (int) readVarInt();
hashes = new ArrayList<Sha256Hash>(nHashes);
for (int i = 0; i < nHashes; i++)
hashes.add(readHash());
int nFlagBytes = (int) readVarInt();
matchedChildBits = readBytes(nFlagBytes);
length = cursor - offset;
}
// Based on CPartialMerkleTree::TraverseAndBuild in Bitcoin Core.
private static void traverseAndBuild(int height, int pos, List<Sha256Hash> allLeafHashes, byte[] includeBits,
List<Boolean> matchedChildBits, List<Sha256Hash> resultHashes) {
boolean parentOfMatch = false;
// Is this node a parent of at least one matched hash?
for (int p = pos << height; p < (pos+1) << height && p < allLeafHashes.size(); p++) {
if (Utils.checkBitLE(includeBits, p)) {
parentOfMatch = true;
break;
}
}
// Store as a flag bit.
matchedChildBits.add(parentOfMatch);
if (height == 0 || !parentOfMatch) {
// If at height 0, or nothing interesting below, store hash and stop.
resultHashes.add(calcHash(height, pos, allLeafHashes));
} else {
// Otherwise descend into the subtrees.
int h = height - 1;
int p = pos * 2;
traverseAndBuild(h, p, allLeafHashes, includeBits, matchedChildBits, resultHashes);
if (p + 1 < getTreeWidth(allLeafHashes.size(), h))
traverseAndBuild(h, p + 1, allLeafHashes, includeBits, matchedChildBits, resultHashes);
}
}
private static Sha256Hash calcHash(int height, int pos, List<Sha256Hash> hashes) {
if (height == 0) {
// Hash at height 0 is just the regular tx hash itself.
return hashes.get(pos);
}
int h = height - 1;
int p = pos * 2;
Sha256Hash left = calcHash(h, p, hashes);
// Calculate right hash if not beyond the end of the array - copy left hash otherwise.
Sha256Hash right;
if (p + 1 < getTreeWidth(hashes.size(), h)) {
right = calcHash(h, p + 1, hashes);
} else {
right = left;
}
return combineLeftRight(left.getBytes(), right.getBytes());
}
@Override
protected void parseLite() {
}
// helper function to efficiently calculate the number of nodes at given height in the merkle tree
private static int getTreeWidth(int transactionCount, int height) {
return (transactionCount + (1 << height) - 1) >> height;
}
private static class ValuesUsed {
public int bitsUsed = 0, hashesUsed = 0;
}
// recursive function that traverses tree nodes, consuming the bits and hashes produced by TraverseAndBuild.
// it returns the hash of the respective node.
private Sha256Hash recursiveExtractHashes(int height, int pos, ValuesUsed used, List<Sha256Hash> matchedHashes) throws VerificationException {
if (used.bitsUsed >= matchedChildBits.length*8) {
// overflowed the bits array - failure
throw new VerificationException("PartialMerkleTree overflowed its bits array");
}
boolean parentOfMatch = checkBitLE(matchedChildBits, used.bitsUsed++);
if (height == 0 || !parentOfMatch) {
// if at height 0, or nothing interesting below, use stored hash and do not descend
if (used.hashesUsed >= hashes.size()) {
// overflowed the hash array - failure
throw new VerificationException("PartialMerkleTree overflowed its hash array");
}
Sha256Hash hash = hashes.get(used.hashesUsed++);
if (height == 0 && parentOfMatch) // in case of height 0, we have a matched txid
matchedHashes.add(hash);
return hash;
} else {
// otherwise, descend into the subtrees to extract matched txids and hashes
byte[] left = recursiveExtractHashes(height - 1, pos * 2, used, matchedHashes).getBytes(), right;
if (pos * 2 + 1 < getTreeWidth(transactionCount, height-1)) {
right = recursiveExtractHashes(height - 1, pos * 2 + 1, used, matchedHashes).getBytes();
if (Arrays.equals(right, left))
throw new VerificationException("Invalid merkle tree with duplicated left/right branches");
} else {
right = left;
}
// and combine them before returning
return combineLeftRight(left, right);
}
}
private static Sha256Hash combineLeftRight(byte[] left, byte[] right) {
return new Sha256Hash(reverseBytes(doubleDigestTwoBuffers(
reverseBytes(left), 0, 32,
reverseBytes(right), 0, 32)));
}
/**
* Extracts tx hashes that are in this merkle tree
* and returns the merkle root of this tree.
*
* The returned root should be checked against the
* merkle root contained in the block header for security.
*
* @param matchedHashesOut A list which will contain the matched txn (will be cleared).
* @return the merkle root of this merkle tree
* @throws ProtocolException if this partial merkle tree is invalid
*/
public Sha256Hash getTxnHashAndMerkleRoot(List<Sha256Hash> matchedHashesOut) throws VerificationException {
matchedHashesOut.clear();
// An empty set will not work
if (transactionCount == 0)
throw new VerificationException("Got a CPartialMerkleTree with 0 transactions");
// check for excessively high numbers of transactions
if (transactionCount > Block.MAX_BLOCK_SIZE / 60) // 60 is the lower bound for the size of a serialized CTransaction
throw new VerificationException("Got a CPartialMerkleTree with more transactions than is possible");
// there can never be more hashes provided than one for every txid
if (hashes.size() > transactionCount)
throw new VerificationException("Got a CPartialMerkleTree with more hashes than transactions");
// there must be at least one bit per node in the partial tree, and at least one node per hash
if (matchedChildBits.length*8 < hashes.size())
throw new VerificationException("Got a CPartialMerkleTree with fewer matched bits than hashes");
// calculate height of tree
int height = 0;
while (getTreeWidth(transactionCount, height) > 1)
height++;
// traverse the partial tree
ValuesUsed used = new ValuesUsed();
Sha256Hash merkleRoot = recursiveExtractHashes(height, 0, used, matchedHashesOut);
// verify that all bits were consumed (except for the padding caused by serializing it as a byte sequence)
if ((used.bitsUsed+7)/8 != matchedChildBits.length ||
// verify that all hashes were consumed
used.hashesUsed != hashes.size())
throw new VerificationException("Got a CPartialMerkleTree that didn't need all the data it provided");
return merkleRoot;
}
public int getTransactionCount() {
return transactionCount;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PartialMerkleTree tree = (PartialMerkleTree) o;
if (transactionCount != tree.transactionCount) return false;
if (!hashes.equals(tree.hashes)) return false;
if (!Arrays.equals(matchedChildBits, tree.matchedChildBits)) return false;
return true;
}
@Override
public int hashCode() {
int result = transactionCount;
result = 31 * result + Arrays.hashCode(matchedChildBits);
result = 31 * result + hashes.hashCode();
return result;
}
@Override
public String toString() {
return "PartialMerkleTree{" +
"transactionCount=" + transactionCount +
", matchedChildBits=" + Arrays.toString(matchedChildBits) +
", hashes=" + hashes +
'}';
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,241 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import com.dogecoin.dogecoinj.params.MainNetParams;
import com.google.common.net.InetAddresses;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import static com.dogecoin.dogecoinj.core.Utils.uint32ToByteStreamLE;
import static com.dogecoin.dogecoinj.core.Utils.uint64ToByteStreamLE;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* A PeerAddress holds an IP address and port number representing the network location of
* a peer in the Bitcoin P2P network. It exists primarily for serialization purposes.
*/
public class PeerAddress extends ChildMessage {
private static final long serialVersionUID = 7501293709324197411L;
static final int MESSAGE_SIZE = 30;
private InetAddress addr;
private int port;
private BigInteger services;
private long time;
/**
* Construct a peer address from a serialized payload.
*/
public PeerAddress(NetworkParameters params, byte[] payload, int offset, int protocolVersion) throws ProtocolException {
super(params, payload, offset, protocolVersion);
}
/**
* Construct a peer address from a serialized payload.
* @param params NetworkParameters object.
* @param payload Bitcoin protocol formatted byte array containing message content.
* @param offset The location of the first payload byte within the array.
* @param protocolVersion Bitcoin protocol version.
* @param parseLazy Whether to perform a full parse immediately or delay until a read is requested.
* @param parseRetain Whether to retain the backing byte array for quick reserialization.
* If true and the backing byte array is invalidated due to modification of a field then
* the cached bytes may be repopulated and retained if the message is serialized again in the future.
* @throws ProtocolException
*/
public PeerAddress(NetworkParameters params, byte[] payload, int offset, int protocolVersion, Message parent, boolean parseLazy,
boolean parseRetain) throws ProtocolException {
super(params, payload, offset, protocolVersion, parent, parseLazy, parseRetain, UNKNOWN_LENGTH);
// Message length is calculated in parseLite which is guaranteed to be called before it is ever read.
// Even though message length is static for a PeerAddress it is safer to leave it there
// as it will be set regardless of which constructor was used.
}
/**
* Construct a peer address from a memorized or hardcoded address.
*/
public PeerAddress(InetAddress addr, int port, int protocolVersion) {
this.addr = checkNotNull(addr);
this.port = port;
this.protocolVersion = protocolVersion;
this.services = BigInteger.ZERO;
length = protocolVersion > 31402 ? MESSAGE_SIZE : MESSAGE_SIZE - 4;
}
/**
* Constructs a peer address from the given IP address and port. Protocol version is the default.
*/
public PeerAddress(InetAddress addr, int port) {
this(addr, port, NetworkParameters.PROTOCOL_VERSION);
}
/**
* Constructs a peer address from the given IP address. Port and protocol version are default for the mainnet.
*/
public PeerAddress(InetAddress addr) {
this(addr, MainNetParams.get().getPort());
}
public PeerAddress(InetSocketAddress addr) {
this(addr.getAddress(), addr.getPort());
}
public static PeerAddress localhost(NetworkParameters params) {
return new PeerAddress(InetAddresses.forString("127.0.0.1"), params.getPort());
}
@Override
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
if (protocolVersion >= 31402) {
//TODO this appears to be dynamic because the client only ever sends out it's own address
//so assumes itself to be up. For a fuller implementation this needs to be dynamic only if
//the address refers to this client.
int secs = (int) (Utils.currentTimeSeconds());
uint32ToByteStreamLE(secs, stream);
}
uint64ToByteStreamLE(services, stream); // nServices.
// Java does not provide any utility to map an IPv4 address into IPv6 space, so we have to do it by hand.
byte[] ipBytes = addr.getAddress();
if (ipBytes.length == 4) {
byte[] v6addr = new byte[16];
System.arraycopy(ipBytes, 0, v6addr, 12, 4);
v6addr[10] = (byte) 0xFF;
v6addr[11] = (byte) 0xFF;
ipBytes = v6addr;
}
stream.write(ipBytes);
// And write out the port. Unlike the rest of the protocol, address and port is in big endian byte order.
stream.write((byte) (0xFF & port >> 8));
stream.write((byte) (0xFF & port));
}
@Override
protected void parseLite() {
length = protocolVersion > 31402 ? MESSAGE_SIZE : MESSAGE_SIZE - 4;
}
@Override
protected void parse() throws ProtocolException {
// Format of a serialized address:
// uint32 timestamp
// uint64 services (flags determining what the node can do)
// 16 bytes ip address
// 2 bytes port num
if (protocolVersion > 31402)
time = readUint32();
else
time = -1;
services = readUint64();
byte[] addrBytes = readBytes(16);
try {
addr = InetAddress.getByAddress(addrBytes);
} catch (UnknownHostException e) {
throw new RuntimeException(e); // Cannot happen.
}
port = ((0xFF & payload[cursor++]) << 8) | (0xFF & payload[cursor++]);
}
@Override
public int getMessageSize() {
// The 4 byte difference is the uint32 timestamp that was introduced in version 31402
length = protocolVersion > 31402 ? MESSAGE_SIZE : MESSAGE_SIZE - 4;
return length;
}
public InetAddress getAddr() {
maybeParse();
return addr;
}
public InetSocketAddress getSocketAddress() {
return new InetSocketAddress(getAddr(), getPort());
}
public void setAddr(InetAddress addr) {
unCache();
this.addr = addr;
}
public int getPort() {
maybeParse();
return port;
}
public void setPort(int port) {
unCache();
this.port = port;
}
public BigInteger getServices() {
maybeParse();
return services;
}
public void setServices(BigInteger services) {
unCache();
this.services = services;
}
public long getTime() {
maybeParse();
return time;
}
public void setTime(long time) {
unCache();
this.time = time;
}
@Override
public String toString() {
return "[" + addr.getHostAddress() + "]:" + port;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PeerAddress other = (PeerAddress) o;
return other.addr.equals(addr) &&
other.port == port &&
other.services.equals(services) &&
other.time == time;
//TODO: including services and time could cause same peer to be added multiple times in collections
}
@Override
public int hashCode() {
return addr.hashCode() ^ port ^ (int) time ^ services.hashCode();
}
public InetSocketAddress toSocketAddress() {
return new InetSocketAddress(addr, port);
}
}

View File

@ -1,101 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Set;
/**
* <p>Implementors can listen to events like blocks being downloaded/transactions being broadcast/connect/disconnects,
* they can pre-filter messages before they are procesesed by a {@link Peer} or {@link PeerGroup}, and they can
* provide transactions to remote peers when they ask for them.</p>
*/
public interface PeerEventListener {
/**
* <p>Called when peers are discovered, this happens at startup of {@link PeerGroup} or if we run out of
* suitable {@link Peer}s to connect to.</p>
*
* @param peerAddresses the set of discovered {@link PeerAddress}es
*/
public void onPeersDiscovered(Set<PeerAddress> peerAddresses);
/**
* Called on a Peer thread when a block is received.<p>
*
* The block may have transactions or may be a header only once getheaders is implemented.
*
* @param peer the peer receiving the block
* @param block the downloaded block
* @param blocksLeft the number of blocks left to download
*/
public void onBlocksDownloaded(Peer peer, Block block, int blocksLeft);
/**
* Called when a download is started with the initial number of blocks to be downloaded.
*
* @param peer the peer receiving the block
* @param blocksLeft the number of blocks left to download
*/
public void onChainDownloadStarted(Peer peer, int blocksLeft);
/**
* Called when a peer is connected. If this listener is registered to a {@link Peer} instead of a {@link PeerGroup},
* peerCount will always be 1.
*
* @param peer
* @param peerCount the total number of connected peers
*/
public void onPeerConnected(Peer peer, int peerCount);
/**
* Called when a peer is disconnected. Note that this won't be called if the listener is registered on a
* {@link PeerGroup} and the group is in the process of shutting down. If this listener is registered to a
* {@link Peer} instead of a {@link PeerGroup}, peerCount will always be 0. This handler can be called without
* a corresponding invocation of onPeerConnected if the initial connection is never successful.
*
* @param peer
* @param peerCount the total number of connected peers
*/
public void onPeerDisconnected(Peer peer, int peerCount);
/**
* <p>Called when a message is received by a peer, before the message is processed. The returned message is
* processed instead. Returning null will cause the message to be ignored by the Peer returning the same message
* object allows you to see the messages received but not change them. The result from one event listeners
* callback is passed as "m" to the next, forming a chain.</p>
*
* <p>Note that this will never be called if registered with any executor other than
* {@link com.dogecoin.dogecoinj.utils.Threading#SAME_THREAD}</p>
*/
public Message onPreMessageReceived(Peer peer, Message m);
/**
* Called when a new transaction is broadcast over the network.
*/
public void onTransaction(Peer peer, Transaction t);
/**
* <p>Called when a peer receives a getdata message, usually in response to an "inv" being broadcast. Return as many
* items as possible which appear in the {@link GetDataMessage}, or null if you're not interested in responding.</p>
*
* <p>Note that this will never be called if registered with any executor other than
* {@link com.dogecoin.dogecoinj.utils.Threading#SAME_THREAD}</p>
*/
@Nullable
public List<Message> getData(Peer peer, GetDataMessage m);
}

View File

@ -1,36 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
/**
* Thrown when a problem occurs in communicating with a peer, and we should
* retry.
*/
@SuppressWarnings("serial")
public class PeerException extends Exception {
public PeerException(String msg) {
super(msg);
}
public PeerException(Exception e) {
super(e);
}
public PeerException(String msg, Exception e) {
super(msg, e);
}
}

View File

@ -1,60 +0,0 @@
/*
* Copyright 2013 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import java.util.concurrent.locks.Lock;
/**
* An interface which provides the information required to properly filter data downloaded from Peers.
* Note that an implementer is responsible for calling {@link PeerGroup#recalculateFastCatchupAndFilter(com.dogecoin.dogecoinj.core.PeerGroup.FilterRecalculateMode)}
* whenever a change occurs which effects the data provided via this interface.
*/
public interface PeerFilterProvider {
/**
* Returns the earliest timestamp (seconds since epoch) for which full/bloom-filtered blocks must be downloaded.
* Blocks with timestamps before this time will only have headers downloaded. 0 requires that all blocks be
* downloaded, and thus this should default to {@link System#currentTimeMillis()}/1000.
*/
public long getEarliestKeyCreationTime();
/**
* Called on all registered filter providers before getBloomFilterElementCount and getBloomFilter are called.
* Once called, the provider should ensure that the items it will want to insert into the filter don't change.
* The reason is that all providers will have their element counts queried, and then a filter big enough for
* all of them will be specified. So the provider must use consistent state. There is guaranteed to be a matching
* call to endBloomFilterCalculation that can be used to e.g. unlock a lock.
*/
public void beginBloomFilterCalculation();
/**
* Gets the number of elements that will be added to a bloom filter returned by
* {@link PeerFilterProvider#getBloomFilter(int, double, long)}
*/
public int getBloomFilterElementCount();
/**
* Gets a bloom filter that contains all the necessary elements for the listener to receive relevant transactions.
* Default value should be an empty bloom filter with the given size, falsePositiveRate, and nTweak.
*/
public BloomFilter getBloomFilter(int size, double falsePositiveRate, long nTweak);
/** Whether this filter provider depends on the server updating the filter on all matches */
public boolean isRequiringUpdateAllBloomFilter();
public void endBloomFilterCalculation();
}

File diff suppressed because it is too large Load Diff

View File

@ -1,235 +0,0 @@
/*
* Copyright 2013 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import com.dogecoin.dogecoinj.net.AbstractTimeoutHandler;
import com.dogecoin.dogecoinj.net.MessageWriteTarget;
import com.dogecoin.dogecoinj.net.StreamParser;
import com.dogecoin.dogecoinj.utils.Threading;
import com.google.common.annotations.VisibleForTesting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.channels.NotYetConnectedException;
import java.util.concurrent.locks.Lock;
import static com.google.common.base.Preconditions.*;
/**
* Handles high-level message (de)serialization for peers, acting as the bridge between the
* {@link com.dogecoin.dogecoinj.net} classes and {@link Peer}.
*/
public abstract class PeerSocketHandler extends AbstractTimeoutHandler implements StreamParser {
private static final Logger log = LoggerFactory.getLogger(PeerSocketHandler.class);
private final BitcoinSerializer serializer;
protected PeerAddress peerAddress;
// If we close() before we know our writeTarget, set this to true to call writeTarget.closeConnection() right away.
private boolean closePending = false;
// writeTarget will be thread-safe, and may call into PeerGroup, which calls us, so we should call it unlocked
@VisibleForTesting protected MessageWriteTarget writeTarget = null;
// The ByteBuffers passed to us from the writeTarget are static in size, and usually smaller than some messages we
// will receive. For SPV clients, this should be rare (ie we're mostly dealing with small transactions), but for
// messages which are larger than the read buffer, we have to keep a temporary buffer with its bytes.
private byte[] largeReadBuffer;
private int largeReadBufferPos;
private BitcoinSerializer.BitcoinPacketHeader header;
private Lock lock = Threading.lock("PeerSocketHandler");
public PeerSocketHandler(NetworkParameters params, InetSocketAddress remoteIp) {
serializer = new BitcoinSerializer(checkNotNull(params));
this.peerAddress = new PeerAddress(remoteIp);
}
public PeerSocketHandler(NetworkParameters params, PeerAddress peerAddress) {
serializer = new BitcoinSerializer(checkNotNull(params));
this.peerAddress = checkNotNull(peerAddress);
}
/**
* Sends the given message to the peer. Due to the asynchronousness of network programming, there is no guarantee
* the peer will have received it. Throws NotYetConnectedException if we are not yet connected to the remote peer.
* TODO: Maybe use something other than the unchecked NotYetConnectedException here
*/
public void sendMessage(Message message) throws NotYetConnectedException {
lock.lock();
try {
if (writeTarget == null)
throw new NotYetConnectedException();
} finally {
lock.unlock();
}
// TODO: Some round-tripping could be avoided here
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
serializer.serialize(message, out);
writeTarget.writeBytes(out.toByteArray());
} catch (IOException e) {
exceptionCaught(e);
}
}
/**
* Closes the connection to the peer if one exists, or immediately closes the connection as soon as it opens
*/
public void close() {
lock.lock();
try {
if (writeTarget == null) {
closePending = true;
return;
}
} finally {
lock.unlock();
}
writeTarget.closeConnection();
}
@Override
protected void timeoutOccurred() {
log.info("{}: Timed out", getAddress());
close();
}
/**
* Called every time a message is received from the network
*/
protected abstract void processMessage(Message m) throws Exception;
@Override
public int receiveBytes(ByteBuffer buff) {
checkArgument(buff.position() == 0 &&
buff.capacity() >= BitcoinSerializer.BitcoinPacketHeader.HEADER_LENGTH + 4);
try {
// Repeatedly try to deserialize messages until we hit a BufferUnderflowException
for (int i = 0; true; i++) {
// If we are in the middle of reading a message, try to fill that one first, before we expect another
if (largeReadBuffer != null) {
// This can only happen in the first iteration
checkState(i == 0);
// Read new bytes into the largeReadBuffer
int bytesToGet = Math.min(buff.remaining(), largeReadBuffer.length - largeReadBufferPos);
buff.get(largeReadBuffer, largeReadBufferPos, bytesToGet);
largeReadBufferPos += bytesToGet;
// Check the largeReadBuffer's status
if (largeReadBufferPos == largeReadBuffer.length) {
// ...processing a message if one is available
processMessage(serializer.deserializePayload(header, ByteBuffer.wrap(largeReadBuffer)));
largeReadBuffer = null;
header = null;
} else // ...or just returning if we don't have enough bytes yet
return buff.position();
}
// Now try to deserialize any messages left in buff
Message message;
int preSerializePosition = buff.position();
try {
message = serializer.deserialize(buff);
} catch (BufferUnderflowException e) {
// If we went through the whole buffer without a full message, we need to use the largeReadBuffer
if (i == 0 && buff.limit() == buff.capacity()) {
// ...so reposition the buffer to 0 and read the next message header
buff.position(0);
try {
serializer.seekPastMagicBytes(buff);
header = serializer.deserializeHeader(buff);
// Initialize the largeReadBuffer with the next message's size and fill it with any bytes
// left in buff
largeReadBuffer = new byte[header.size];
largeReadBufferPos = buff.remaining();
buff.get(largeReadBuffer, 0, largeReadBufferPos);
} catch (BufferUnderflowException e1) {
// If we went through a whole buffer's worth of bytes without getting a header, give up
// In cases where the buff is just really small, we could create a second largeReadBuffer
// that we use to deserialize the magic+header, but that is rather complicated when the buff
// should probably be at least that big anyway (for efficiency)
throw new ProtocolException("No magic bytes+header after reading " + buff.capacity() + " bytes");
}
} else {
// Reposition the buffer to its original position, which saves us from skipping messages by
// seeking past part of the magic bytes before all of them are in the buffer
buff.position(preSerializePosition);
}
return buff.position();
}
// Process our freshly deserialized message
processMessage(message);
}
} catch (Exception e) {
exceptionCaught(e);
return -1; // Returning -1 also throws an IllegalStateException upstream and kills the connection
}
}
/**
* Sets the {@link MessageWriteTarget} used to write messages to the peer. This should almost never be called, it is
* called automatically by {@link com.dogecoin.dogecoinj.net.NioClient} or
* {@link com.dogecoin.dogecoinj.net.NioClientManager} once the socket finishes initialization.
*/
@Override
public void setWriteTarget(MessageWriteTarget writeTarget) {
checkArgument(writeTarget != null);
lock.lock();
boolean closeNow = false;
try {
checkArgument(this.writeTarget == null);
closeNow = closePending;
this.writeTarget = writeTarget;
} finally {
lock.unlock();
}
if (closeNow)
writeTarget.closeConnection();
}
@Override
public int getMaxMessageSize() {
return Message.MAX_SIZE;
}
/**
* @return the IP address and port of peer.
*/
public PeerAddress getAddress() {
return peerAddress;
}
/** Catch any exceptions, logging them and then closing the channel. */
private void exceptionCaught(Exception e) {
PeerAddress addr = getAddress();
String s = addr == null ? "?" : addr.toString();
if (e instanceof ConnectException || e instanceof IOException) {
// Short message for network errors
log.info(s + " - " + e.getMessage());
} else {
log.warn(s + " - ", e);
Thread.UncaughtExceptionHandler handler = Threading.uncaughtExceptionHandler;
if (handler != null)
handler.uncaughtException(Thread.currentThread(), e);
}
close();
}
}

View File

@ -1,76 +0,0 @@
/**
* Copyright 2011 Noa Resare
*
* 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 com.dogecoin.dogecoinj.core;
import java.io.IOException;
import java.io.OutputStream;
public class Ping extends Message {
private long nonce;
private boolean hasNonce;
public Ping(NetworkParameters params, byte[] payloadBytes) throws ProtocolException {
super(params, payloadBytes, 0);
}
/**
* Create a Ping with a nonce value.
* Only use this if the remote node has a protocol version > 60000
*/
public Ping(long nonce) {
this.nonce = nonce;
this.hasNonce = true;
}
/**
* Create a Ping without a nonce value.
* Only use this if the remote node has a protocol version <= 60000
*/
public Ping() {
this.hasNonce = false;
}
@Override
public void bitcoinSerializeToStream(OutputStream stream) throws IOException {
if (hasNonce)
Utils.int64ToByteStreamLE(nonce, stream);
}
@Override
void parse() throws ProtocolException {
try {
nonce = readInt64();
hasNonce = true;
} catch(ProtocolException e) {
hasNonce = false;
}
length = hasNonce ? 8 : 0;
}
@Override
protected void parseLite() {
}
public boolean hasNonce() {
return hasNonce;
}
public long getNonce() {
return nonce;
}
}

View File

@ -1,59 +0,0 @@
/**
* Copyright 2012 Matt Corallo
*
* 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 com.dogecoin.dogecoinj.core;
import java.io.IOException;
import java.io.OutputStream;
public class Pong extends Message {
/** The smallest protocol version that supports the pong response (BIP 31). Anything beyond version 60000. */
public static final int MIN_PROTOCOL_VERSION = 60003;
private long nonce;
public Pong(NetworkParameters params, byte[] payloadBytes) throws ProtocolException {
super(params, payloadBytes, 0);
}
/**
* Create a Pong with a nonce value.
* Only use this if the remote node has a protocol version > 60000
*/
public Pong(long nonce) {
this.nonce = nonce;
}
@Override
void parse() throws ProtocolException {
nonce = readInt64();
length = 8;
}
@Override
public void bitcoinSerializeToStream(OutputStream stream) throws IOException {
Utils.int64ToByteStreamLE(nonce, stream);
}
@Override
protected void parseLite() {
}
/** Returns the nonce sent by the remote peer. */
public long getNonce() {
return nonce;
}
}

View File

@ -1,33 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
@SuppressWarnings("serial")
public class ProtocolException extends VerificationException {
public ProtocolException(String msg) {
super(msg);
}
public ProtocolException(Exception e) {
super(e);
}
public ProtocolException(String msg, Exception e) {
super(msg, e);
}
}

View File

@ -1,37 +0,0 @@
/*
* Copyright 2012 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
// TODO: Rename PrunedException to something like RequiredDataWasPrunedException
/**
* PrunedException is thrown in cases where a fully verifying node has deleted (pruned) old block data that turned
* out to be necessary for handling a re-org. Normally this should never happen unless you're playing with the testnet
* as the pruning parameters should be set very conservatively, such that an absolutely enormous re-org would be
* required to trigger it.
*/
@SuppressWarnings("serial")
public class PrunedException extends Exception {
private Sha256Hash hash;
public PrunedException(Sha256Hash hash) {
super(hash.toString());
this.hash = hash;
}
public Sha256Hash getHash() {
return hash;
}
}

View File

@ -1,182 +0,0 @@
/**
* Copyright 2013 Matt Corallo
*
* 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 com.dogecoin.dogecoinj.core;
import java.io.IOException;
import java.io.OutputStream;
/**
* A message sent by nodes when a message we sent was rejected (ie a transaction had too little fee/was invalid/etc)
*/
public class RejectMessage extends Message {
private static final long serialVersionUID = -5246995579800334336L;
private String message, reason;
public static enum RejectCode {
/** The message was not able to be parsed */
MALFORMED((byte) 0x01),
/** The message described an invalid object */
INVALID((byte) 0x10),
/** The message was obsolete or described an object which is obsolete (eg unsupported, old version, v1 block) */
OBSOLETE((byte) 0x11),
/**
* The message was relayed multiple times or described an object which is in conflict with another.
* This message can describe errors in protocol implementation or the presence of an attempt to DOUBLE SPEND.
*/
DUPLICATE((byte) 0x12),
/**
* The message described an object was not standard and was thus not accepted.
* The reference client has a concept of standard transaction forms, which describe scripts and encodings which
* it is willing to relay further. Other transactions are neither relayed nor mined, though they are considered
* valid if they appear in a block.
*/
NONSTANDARD((byte) 0x40),
/**
* This refers to a specific form of NONSTANDARD transactions, which have an output smaller than some constant
* defining them as dust (this is no longer used).
*/
DUST((byte) 0x41),
/** The messages described an object which did not have sufficient fee to be relayed further. */
INSUFFICIENTFEE((byte) 0x42),
/** The message described a block which was invalid according to hard-coded checkpoint blocks. */
CHECKPOINT((byte) 0x43),
OTHER((byte) 0xff);
byte code;
RejectCode(byte code) { this.code = code; }
static RejectCode fromCode(byte code) {
for (RejectCode rejectCode : RejectCode.values())
if (rejectCode.code == code)
return rejectCode;
return OTHER;
}
}
private RejectCode code;
private Sha256Hash messageHash;
public RejectMessage(NetworkParameters params, byte[] payload) throws ProtocolException {
super(params, payload, 0);
}
/** Constructs a reject message that fingers the object with the given hash as rejected for the given reason. */
public RejectMessage(NetworkParameters params, RejectCode code, Sha256Hash hash, String message, String reason) throws ProtocolException {
super(params);
this.code = code;
this.messageHash = hash;
this.message = message;
this.reason = reason;
}
@Override
protected void parseLite() throws ProtocolException {
message = readStr();
code = RejectCode.fromCode(readBytes(1)[0]);
reason = readStr();
if (message.equals("block") || message.equals("tx"))
messageHash = readHash();
length = cursor - offset;
}
@Override
public void parse() throws ProtocolException {
if (length == UNKNOWN_LENGTH)
parseLite();
}
@Override
public void bitcoinSerializeToStream(OutputStream stream) throws IOException {
byte[] messageBytes = message.getBytes("UTF-8");
stream.write(new VarInt(messageBytes.length).encode());
stream.write(messageBytes);
stream.write(code.code);
byte[] reasonBytes = reason.getBytes("UTF-8");
stream.write(new VarInt(reasonBytes.length).encode());
stream.write(reasonBytes);
if (message.equals("block") || message.equals("tx"))
stream.write(Utils.reverseBytes(messageHash.getBytes()));
}
/**
* Provides the type of message which was rejected by the peer.
* Note that this is ENTIRELY UNTRUSTED and should be sanity-checked before it is printed or processed.
*/
public String getRejectedMessage() {
ensureParsed();
return message;
}
/**
* Provides the hash of the rejected object (if getRejectedMessage() is either "tx" or "block"), otherwise null.
*/
public Sha256Hash getRejectedObjectHash() {
ensureParsed();
return messageHash;
}
/**
* The reason code given for why the peer rejected the message.
*/
public RejectCode getReasonCode() {
return code;
}
/**
* The reason message given for rejection.
* Note that this is ENTIRELY UNTRUSTED and should be sanity-checked before it is printed or processed.
*/
public String getReasonString() {
return reason;
}
/**
* A String representation of the relevant details of this reject message.
* Be aware that the value returned by this method includes the value returned by
* {@link #getReasonString() getReasonString}, which is taken from the reject message unchecked.
* Through malice or otherwise, it might contain control characters or other harmful content.
*/
@Override
public String toString() {
Sha256Hash hash = getRejectedObjectHash();
if (hash != null)
return String.format("Reject: %s %s for reason '%s' (%d)", getRejectedMessage(), getRejectedObjectHash(),
getReasonString(), getReasonCode().code);
else
return String.format("Reject: %s for reason '%s' (%d)", getRejectedMessage(),
getReasonString(), getReasonCode().code);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RejectMessage other = (RejectMessage) o;
return message.equals(other.message) &&
code.equals(other.code) &&
reason.equals(other.reason) &&
messageHash.equals(other.messageHash);
}
@Override
public int hashCode() {
int result = message.hashCode();
result = 31 * result + reason.hashCode();
result = 31 * result + code.hashCode();
result = 31 * result + messageHash.hashCode();
return result;
}
}

View File

@ -1,40 +0,0 @@
/*
* Copyright 2014 Adam Mackler
*
* 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 com.dogecoin.dogecoinj.core;
/**
* This exception is used by the TransactionBroadcast class to indicate that a broadcast
* Transaction has been rejected by the network, for example because it violates a
* protocol rule. Note that not all invalid transactions generate a reject message, and
* some peers may never do so.
*/
public class RejectedTransactionException extends Exception {
private Transaction tx;
private RejectMessage rejectMessage;
public RejectedTransactionException(Transaction tx, RejectMessage rejectMessage) {
super(rejectMessage.toString());
this.tx = tx;
this.rejectMessage = rejectMessage;
}
/** Return the original Transaction object whose broadcast was rejected. */
public Transaction getTransaction() { return tx; }
/** Return the RejectMessage object representing the broadcast rejection. */
public RejectMessage getRejectMessage() { return rejectMessage; }
}

View File

@ -1,29 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
@SuppressWarnings("serial")
public class ScriptException extends VerificationException {
public ScriptException(String msg) {
super(msg);
}
public ScriptException(String msg, Exception e) {
super(msg, e);
}
}

View File

@ -1,135 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* 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 com.dogecoin.dogecoinj.core;
import com.google.common.io.ByteStreams;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import static com.google.common.base.Preconditions.checkArgument;
/**
* A Sha256Hash just wraps a byte[] so that equals and hashcode work correctly, allowing it to be used as keys in a
* map. It also checks that the length is correct and provides a bit more type safety.
*/
public class Sha256Hash implements Serializable, Comparable<Sha256Hash> {
private byte[] bytes;
public static final Sha256Hash ZERO_HASH = new Sha256Hash(new byte[32]);
/**
* Creates a Sha256Hash by wrapping the given byte array. It must be 32 bytes long. Takes ownership!
*/
public Sha256Hash(byte[] rawHashBytes) {
checkArgument(rawHashBytes.length == 32);
this.bytes = rawHashBytes;
}
/**
* Creates a Sha256Hash by decoding the given hex string. It must be 64 characters long.
*/
public Sha256Hash(String hexString) {
checkArgument(hexString.length() == 64);
this.bytes = Utils.HEX.decode(hexString);
}
/**
* Calculates the (one-time) hash of contents and returns it as a new wrapped hash.
*/
public static Sha256Hash create(byte[] contents) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
return new Sha256Hash(digest.digest(contents));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e); // Cannot happen.
}
}
/**
* Calculates the hash of the hash of the contents. This is a standard operation in Bitcoin.
*/
public static Sha256Hash createDouble(byte[] contents) {
return new Sha256Hash(Utils.doubleDigest(contents));
}
/**
* Returns a hash of the given files contents. Reads the file fully into memory before hashing so only use with
* small files.
* @throws IOException
*/
public static Sha256Hash hashFileContents(File f) throws IOException {
FileInputStream in = new FileInputStream(f);
try {
return create(ByteStreams.toByteArray(in));
} finally {
in.close();
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Sha256Hash other = (Sha256Hash) o;
return Arrays.equals(bytes, other.bytes);
}
/**
* Hash code of the byte array as calculated by {@link Arrays#hashCode()}. Note the difference between a SHA256
* secure bytes and the type of quick/dirty bytes used by the Java hashCode method which is designed for use in
* bytes tables.
*/
@Override
public int hashCode() {
// Use the last 4 bytes, not the first 4 which are often zeros in Bitcoin.
return (bytes[31] & 0xFF) | ((bytes[30] & 0xFF) << 8) | ((bytes[29] & 0xFF) << 16) | ((bytes[28] & 0xFF) << 24);
}
@Override
public String toString() {
return Utils.HEX.encode(bytes);
}
/**
* Returns the bytes interpreted as a positive integer.
*/
public BigInteger toBigInteger() {
return new BigInteger(1, bytes);
}
public byte[] getBytes() {
return bytes;
}
public Sha256Hash duplicate() {
return new Sha256Hash(bytes);
}
@Override
public int compareTo(Sha256Hash o) {
int thisCode = this.hashCode();
int oCode = ((Sha256Hash)o).hashCode();
return thisCode > oCode ? 1 : (thisCode == oCode ? 0 : -1);
}
}

View File

@ -1,153 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import com.dogecoin.dogecoinj.store.BlockStore;
import com.dogecoin.dogecoinj.store.BlockStoreException;
import java.io.*;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import static com.google.common.base.Preconditions.checkState;
/**
* Wraps a {@link Block} object with extra data that can be derived from the block chain but is slow or inconvenient to
* calculate. By storing it alongside the block header we reduce the amount of work required significantly.
* Recalculation is slow because the fields are cumulative - to find the chainWork you have to iterate over every
* block in the chain back to the genesis block, which involves lots of seeking/loading etc. So we just keep a
* running total: it's a disk space vs cpu/io tradeoff.<p>
*
* StoredBlocks are put inside a {@link BlockStore} which saves them to memory or disk.
*/
public class StoredBlock implements Serializable {
private static final long serialVersionUID = -6097565241243701771L;
// A BigInteger representing the total amount of work done so far on this chain. As of May 2011 it takes 8
// bytes to represent this field, so 12 bytes should be plenty for now.
public static final int CHAIN_WORK_BYTES = 12;
public static final byte[] EMPTY_BYTES = new byte[CHAIN_WORK_BYTES];
public static final int COMPACT_SERIALIZED_SIZE = Block.HEADER_SIZE + CHAIN_WORK_BYTES + 4; // for height
private Block header;
private BigInteger chainWork;
private int height;
public StoredBlock(Block header, BigInteger chainWork, int height) {
this.header = header;
this.chainWork = chainWork;
this.height = height;
}
/**
* The block header this object wraps. The referenced block object must not have any transactions in it.
*/
public Block getHeader() {
return header;
}
/**
* The total sum of work done in this block, and all the blocks below it in the chain. Work is a measure of how
* many tries are needed to solve a block. If the target is set to cover 10% of the total hash value space,
* then the work represented by a block is 10.
*/
public BigInteger getChainWork() {
return chainWork;
}
/**
* Position in the chain for this block. The genesis block has a height of zero.
*/
public int getHeight() {
return height;
}
/** Returns true if this objects chainWork is higher than the others. */
public boolean moreWorkThan(StoredBlock other) {
return chainWork.compareTo(other.chainWork) > 0;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StoredBlock other = (StoredBlock) o;
return header.equals(other.header) &&
chainWork.equals(other.chainWork) &&
height == other.height;
}
@Override
public int hashCode() {
// A better hashCode is possible, but this works for now.
return header.hashCode() ^ chainWork.hashCode() ^ height;
}
/**
* Creates a new StoredBlock, calculating the additional fields by adding to the values in this block.
*/
public StoredBlock build(Block block) throws VerificationException {
// Stored blocks track total work done in this chain, because the canonical chain is the one that represents
// the largest amount of work done not the tallest.
BigInteger chainWork = this.chainWork.add(block.getWork());
int height = this.height + 1;
return new StoredBlock(block, chainWork, height);
}
/**
* Given a block store, looks up the previous block in this chain. Convenience method for doing
* <tt>store.get(this.getHeader().getPrevBlockHash())</tt>.
*
* @return the previous block in the chain or null if it was not found in the store.
*/
public StoredBlock getPrev(BlockStore store) throws BlockStoreException {
return store.get(getHeader().getPrevBlockHash());
}
/** Serializes the stored block to a custom packed format. Used by {@link CheckpointManager}. */
public void serializeCompact(ByteBuffer buffer) {
byte[] chainWorkBytes = getChainWork().toByteArray();
checkState(chainWorkBytes.length <= CHAIN_WORK_BYTES, "Ran out of space to store chain work!");
if (chainWorkBytes.length < CHAIN_WORK_BYTES) {
// Pad to the right size.
buffer.put(EMPTY_BYTES, 0, CHAIN_WORK_BYTES - chainWorkBytes.length);
}
buffer.put(chainWorkBytes);
buffer.putInt(getHeight());
// Using unsafeBitcoinSerialize here can give us direct access to the same bytes we read off the wire,
// avoiding serialization round-trips.
byte[] bytes = getHeader().unsafeBitcoinSerialize();
buffer.put(bytes, 0, Block.HEADER_SIZE); // Trim the trailing 00 byte (zero transactions).
}
/** De-serializes the stored block from a custom packed format. Used by {@link CheckpointManager}. */
public static StoredBlock deserializeCompact(NetworkParameters params, ByteBuffer buffer) throws ProtocolException {
byte[] chainWorkBytes = new byte[StoredBlock.CHAIN_WORK_BYTES];
buffer.get(chainWorkBytes);
BigInteger chainWork = new BigInteger(1, chainWorkBytes);
int height = buffer.getInt(); // +4 bytes
byte[] header = new byte[Block.HEADER_SIZE + 1]; // Extra byte for the 00 transactions length.
buffer.get(header, 0, Block.HEADER_SIZE);
return new StoredBlock(new Block(params, header), chainWork, height);
}
@Override
public String toString() {
return String.format("Block %s at height %d: %s",
getHeader().getHashAsString(), getHeight(), getHeader().toString());
}
}

View File

@ -1,177 +0,0 @@
/**
* Copyright 2012 Matt Corallo.
*
* 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 com.dogecoin.dogecoinj.core;
import java.io.*;
import java.math.BigInteger;
/**
* A StoredTransactionOutput message contains the information necessary to check a spending transaction.
* It avoids having to store the entire parentTransaction just to get the hash and index.
* Its only really useful for MemoryFullPrunedBlockStore, and should probably be moved there
*/
public class StoredTransactionOutput implements Serializable {
private static final long serialVersionUID = -8744924157056340509L;
/**
* A transaction output has some value and a script used for authenticating that the redeemer is allowed to spend
* this output.
*/
private Coin value;
private byte[] scriptBytes;
/** Hash of the transaction to which we refer. */
private Sha256Hash hash;
/** Which output of that transaction we are talking about. */
private long index;
/** arbitrary value lower than -{@link NetworkParameters#spendableCoinbaseDepth}
* (not too low to get overflows when we do blockHeight - NONCOINBASE_HEIGHT, though) */
private static final int NONCOINBASE_HEIGHT = -200;
/** The height of the creating block (for coinbases, NONCOINBASE_HEIGHT otherwise) */
private int height;
/**
* Creates a stored transaction output
* @param hash the hash of the containing transaction
* @param index the outpoint
* @param value the value available
* @param height the height this output was created in
* @param scriptBytes
*/
public StoredTransactionOutput(Sha256Hash hash, long index, Coin value, int height, boolean isCoinbase, byte[] scriptBytes) {
this.hash = hash;
this.index = index;
this.value = value;
this.height = isCoinbase ? height : NONCOINBASE_HEIGHT;
this.scriptBytes = scriptBytes;
}
public StoredTransactionOutput(Sha256Hash hash, TransactionOutput out, int height, boolean isCoinbase) {
this.hash = hash;
this.index = out.getIndex();
this.value = out.getValue();
this.height = isCoinbase ? height : NONCOINBASE_HEIGHT;
this.scriptBytes = out.getScriptBytes();
}
public StoredTransactionOutput(InputStream in) throws IOException {
byte[] valueBytes = new byte[8];
if (in.read(valueBytes, 0, 8) != 8)
throw new EOFException();
value = Coin.valueOf(Utils.readInt64(valueBytes, 0));
int scriptBytesLength = ((in.read() & 0xFF) << 0) |
((in.read() & 0xFF) << 8) |
((in.read() & 0xFF) << 16) |
((in.read() & 0xFF) << 24);
scriptBytes = new byte[scriptBytesLength];
if (in.read(scriptBytes) != scriptBytesLength)
throw new EOFException();
byte[] hashBytes = new byte[32];
if (in.read(hashBytes) != 32)
throw new EOFException();
hash = new Sha256Hash(hashBytes);
byte[] indexBytes = new byte[4];
if (in.read(indexBytes) != 4)
throw new EOFException();
index = Utils.readUint32(indexBytes, 0);
height = ((in.read() & 0xFF) << 0) |
((in.read() & 0xFF) << 8) |
((in.read() & 0xFF) << 16) |
((in.read() & 0xFF) << 24);
}
/**
* The value which this Transaction output holds
* @return the value
*/
public Coin getValue() {
return value;
}
/**
* The backing script bytes which can be turned into a Script object.
* @return the scriptBytes
*/
public byte[] getScriptBytes() {
return scriptBytes;
}
/**
* The hash of the transaction which holds this output
* @return the hash
*/
public Sha256Hash getHash() {
return hash;
}
/**
* The index of this output in the transaction which holds it
* @return the index
*/
public long getIndex() {
return index;
}
/**
* Gets the height of the block that created this output (or -1 if this output was not created by a coinbase)
*/
public int getHeight() {
return height;
}
@Override
public String toString() {
return String.format("Stored TxOut of %s (%s:%d)", value.toFriendlyString(), hash.toString(), index);
}
@Override
public int hashCode() {
return hash.hashCode() + (int)index;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StoredTransactionOutput other = (StoredTransactionOutput) o;
return getHash().equals(other.getHash()) &&
getIndex() == other.getIndex();
}
public void serializeToStream(OutputStream bos) throws IOException {
Utils.uint64ToByteStreamLE(BigInteger.valueOf(value.value), bos);
bos.write(0xFF & scriptBytes.length >> 0);
bos.write(0xFF & scriptBytes.length >> 8);
bos.write(0xFF & (scriptBytes.length >> 16));
bos.write(0xFF & (scriptBytes.length >> 24));
bos.write(scriptBytes);
bos.write(hash.getBytes());
Utils.uint32ToByteStreamLE(index, bos);
bos.write(0xFF & (height >> 0));
bos.write(0xFF & (height >> 8));
bos.write(0xFF & (height >> 16));
bos.write(0xFF & (height >> 24));
}
}

View File

@ -1,91 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2012 Matt Corallo.
*
* 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 com.dogecoin.dogecoinj.core;
import java.io.Serializable;
import java.util.List;
/**
* Contains minimal data neccessary to disconnect/connect the transactions
* in the stored block at will. Can either store the full set of
* transactions (if the inputs for the block have not been tested to work)
* or the set of transaction outputs created/destroyed when the block is
* connected.
*/
public class StoredUndoableBlock implements Serializable {
private static final long serialVersionUID = 5127353027086786117L;
Sha256Hash blockHash;
// Only one of either txOutChanges or transactions will be set
private TransactionOutputChanges txOutChanges;
private List<Transaction> transactions;
public StoredUndoableBlock(Sha256Hash hash, TransactionOutputChanges txOutChanges) {
this.blockHash = hash;
this.transactions = null;
this.txOutChanges = txOutChanges;
}
public StoredUndoableBlock(Sha256Hash hash, List<Transaction> transactions) {
this.blockHash = hash;
this.txOutChanges = null;
this.transactions = transactions;
}
/**
* Get the transaction output changes if they have been calculated, otherwise null.
* Only one of this and getTransactions() will return a non-null value.
*/
public TransactionOutputChanges getTxOutChanges() {
return txOutChanges;
}
/**
* Get the full list of transactions if it is stored, otherwise null.
* Only one of this and getTxOutChanges() will return a non-null value.
*/
public List<Transaction> getTransactions() {
return transactions;
}
/**
* Get the hash of the represented block
*/
public Sha256Hash getHash() {
return blockHash;
}
@Override
public int hashCode() {
return blockHash.hashCode();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StoredUndoableBlock other = (StoredUndoableBlock) o;
return getHash().equals(other.getHash());
}
@Override
public String toString() {
return "Undoable Block " + blockHash.toString();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,42 +0,0 @@
/**
* Copyright 2014 Giannis Dzegoutanis
*
* 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 com.dogecoin.dogecoinj.core;
import com.dogecoin.dogecoinj.script.Script;
import com.dogecoin.dogecoinj.wallet.WalletTransaction;
import java.util.Map;
/**
* This interface is used to abstract the {@link com.dogecoin.dogecoinj.core.Wallet} and the {@link com.dogecoin.dogecoinj.core.Transaction}
*/
public interface TransactionBag {
/** Returns true if this wallet contains a public key which hashes to the given hash. */
public boolean isPubKeyHashMine(byte[] pubkeyHash);
/** Returns true if this wallet is watching transactions for outputs with the script. */
public boolean isWatchedScript(Script script);
/** Returns true if this wallet contains a keypair with the given public key. */
public boolean isPubKeyMine(byte[] pubkey);
/** Returns true if this wallet knows the script corresponding to the given hash. */
public boolean isPayToScriptHashMine(byte[] payToScriptHash);
/** Returns transactions from a specific pool. */
public Map<Sha256Hash, Transaction> getTransactionPool(WalletTransaction.Pool pool);
}

View File

@ -1,181 +0,0 @@
/**
* Copyright 2013 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import com.google.common.annotations.*;
import com.google.common.base.*;
import com.google.common.util.concurrent.*;
import com.dogecoin.dogecoinj.utils.*;
import org.slf4j.*;
import javax.annotation.*;
import java.util.*;
/**
* Represents a single transaction broadcast that we are performing. A broadcast occurs after a new transaction is created
* (typically by a {@link Wallet} and needs to be sent to the network. A broadcast can succeed or fail. A success is
* defined as seeing the transaction be announced by peers via inv messages, thus indicating their acceptance. A failure
* is defined as not reaching acceptance within a timeout period, or getting an explicit reject message from a peer
* indicating that the transaction was not acceptable.
*/
public class TransactionBroadcast {
private static final Logger log = LoggerFactory.getLogger(TransactionBroadcast.class);
private final SettableFuture<Transaction> future = SettableFuture.create();
private final PeerGroup peerGroup;
private final Transaction tx;
@Nullable private final Context context;
private int minConnections;
private int numWaitingFor;
/** Used for shuffling the peers before broadcast: unit tests can replace this to make themselves deterministic. */
@VisibleForTesting
public static Random random = new Random();
private Transaction pinnedTx;
// Tracks which nodes sent us a reject message about this broadcast, if any. Useful for debugging.
private Map<Peer, RejectMessage> rejects = Collections.synchronizedMap(new HashMap<Peer, RejectMessage>());
// TODO: Context being owned by BlockChain isn't right w.r.t future intentions so it shouldn't really be optional here.
TransactionBroadcast(PeerGroup peerGroup, @Nullable Context context, Transaction tx) {
this.peerGroup = peerGroup;
this.context = context;
this.tx = tx;
this.minConnections = Math.max(1, peerGroup.getMinBroadcastConnections());
}
public ListenableFuture<Transaction> future() {
return future;
}
public void setMinConnections(int minConnections) {
this.minConnections = minConnections;
}
private PeerEventListener rejectionListener = new AbstractPeerEventListener() {
@Override
public Message onPreMessageReceived(Peer peer, Message m) {
if (m instanceof RejectMessage) {
RejectMessage rejectMessage = (RejectMessage)m;
if (tx.getHash().equals(rejectMessage.getRejectedObjectHash())) {
rejects.put(peer, rejectMessage);
int size = rejects.size();
long threshold = Math.round(numWaitingFor / 2.0);
if (size > threshold) {
log.warn("Threshold for considering broadcast rejected has been reached ({}/{})", size, threshold);
future.setException(new RejectedTransactionException(tx, rejectMessage));
peerGroup.removeEventListener(this);
}
}
}
return m;
}
};
public ListenableFuture<Transaction> broadcast() {
peerGroup.addEventListener(rejectionListener, Threading.SAME_THREAD);
log.info("Waiting for {} peers required for broadcast, we have {} ...", minConnections, peerGroup.getConnectedPeers().size());
peerGroup.waitForPeers(minConnections).addListener(new EnoughAvailablePeers(), Threading.SAME_THREAD);
return future;
}
private class EnoughAvailablePeers implements Runnable {
@Override
public void run() {
// We now have enough connected peers to send the transaction.
// This can be called immediately if we already have enough. Otherwise it'll be called from a peer
// thread.
// We will send the tx simultaneously to half the connected peers and wait to hear back from at least half
// of the other half, i.e., with 4 peers connected we will send the tx to 2 randomly chosen peers, and then
// wait for it to show up on one of the other two. This will be taken as sign of network acceptance. As can
// be seen, 4 peers is probably too little - it doesn't taken many broken peers for tx propagation to have
// a big effect.
List<Peer> peers = peerGroup.getConnectedPeers(); // snapshots
// We intern the tx here so we are using a canonical version of the object (as it's unfortunately mutable).
// TODO: Once confidence state is moved out of Transaction we can kill off this step.
pinnedTx = context != null ? context.getConfidenceTable().intern(tx) : tx;
// Prepare to send the transaction by adding a listener that'll be called when confidence changes.
// Only bother with this if we might actually hear back:
if (minConnections > 1)
pinnedTx.getConfidence().addEventListener(new ConfidenceChange());
// Satoshis code sends an inv in this case and then lets the peer request the tx data. We just
// blast out the TX here for a couple of reasons. Firstly it's simpler: in the case where we have
// just a single connection we don't have to wait for getdata to be received and handled before
// completing the future in the code immediately below. Secondly, it's faster. The reason the
// Satoshi client sends an inv is privacy - it means you can't tell if the peer originated the
// transaction or not. However, we are not a fully validating node and this is advertised in
// our version message, as SPV nodes cannot relay it doesn't give away any additional information
// to skip the inv here - we wouldn't send invs anyway.
int numConnected = peers.size();
int numToBroadcastTo = (int) Math.max(1, Math.round(Math.ceil(peers.size() / 2.0)));
numWaitingFor = (int) Math.ceil((peers.size() - numToBroadcastTo) / 2.0);
Collections.shuffle(peers, random);
peers = peers.subList(0, numToBroadcastTo);
log.info("broadcastTransaction: We have {} peers, adding {} to the memory pool and sending to {} peers, will wait for {}, sending to: {}",
numConnected, tx.getHashAsString(), numToBroadcastTo, numWaitingFor, Joiner.on(",").join(peers));
for (Peer peer : peers) {
try {
peer.sendMessage(pinnedTx);
// We don't record the peer as having seen the tx in the memory pool because we want to track only
// how many peers announced to us.
} catch (Exception e) {
log.error("Caught exception sending to {}", peer, e);
}
}
// If we've been limited to talk to only one peer, we can't wait to hear back because the
// remote peer won't tell us about transactions we just announced to it for obvious reasons.
// So we just have to assume we're done, at that point. This happens when we're not given
// any peer discovery source and the user just calls connectTo() once.
if (minConnections == 1) {
peerGroup.removeEventListener(rejectionListener);
future.set(pinnedTx);
}
}
}
private class ConfidenceChange implements TransactionConfidence.Listener {
@Override
public void onConfidenceChanged(TransactionConfidence conf, ChangeReason reason) {
// The number of peers that announced this tx has gone up.
int numSeenPeers = conf.numBroadcastPeers() + rejects.size();
boolean mined = tx.getAppearsInHashes() != null;
log.info("broadcastTransaction: {}: TX {} seen by {} peers{}", reason, pinnedTx.getHashAsString(),
numSeenPeers, mined ? " and mined" : "");
if (numSeenPeers >= numWaitingFor || mined) {
// We've seen the min required number of peers announce the transaction, or it was included
// in a block. Normally we'd expect to see it fully propagate before it gets mined, but
// it can be that a block is solved very soon after broadcast, and it's also possible that
// due to version skew and changes in the relay rules our transaction is not going to
// fully propagate yet can get mined anyway.
//
// Note that we can't wait for the current number of connected peers right now because we
// could have added more peers after the broadcast took place, which means they won't
// have seen the transaction. In future when peers sync up their memory pools after they
// connect we could come back and change this.
//
// We're done! It's important that the PeerGroup lock is not held (by this thread) at this
// point to avoid triggering inversions when the Future completes.
log.info("broadcastTransaction: {} complete", pinnedTx.getHashAsString());
peerGroup.removeEventListener(rejectionListener);
conf.removeEventListener(this);
future.set(pinnedTx); // RE-ENTRANCY POINT
}
}
}
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2013 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import com.google.common.util.concurrent.ListenableFuture;
/**
* A general interface which declares the ability to broadcast transactions. This is implemented
* by {@link com.dogecoin.dogecoinj.core.PeerGroup}.
*/
public interface TransactionBroadcaster {
/** Broadcast the given transaction on the network */
public ListenableFuture<Transaction> broadcastTransaction(final Transaction tx);
}

View File

@ -1,461 +0,0 @@
/*
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* 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 com.dogecoin.dogecoinj.core;
import com.google.common.collect.Sets;
import com.dogecoin.dogecoinj.utils.ListenerRegistration;
import com.dogecoin.dogecoinj.utils.Threading;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import javax.annotation.Nullable;
import java.io.Serializable;
import java.util.ListIterator;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import static com.google.common.base.Preconditions.*;
/**
* <p>A TransactionConfidence object tracks data you can use to make a confidence decision about a transaction.
* It also contains some pre-canned rules for common scenarios: if you aren't really sure what level of confidence
* you need, these should prove useful. You can get a confidence object using {@link Transaction#getConfidence()}.
* They cannot be constructed directly.</p>
*
* <p>Confidence in a transaction can come in multiple ways:</p>
*
* <ul>
* <li>Because you created it yourself and only you have the necessary keys.</li>
* <li>Receiving it from a fully validating peer you know is trustworthy, for instance, because it's run by yourself.</li>
* <li>Receiving it from a peer on the network you randomly chose. If your network connection is not being
* intercepted, you have a pretty good chance of connecting to a node that is following the rules.</li>
* <li>Receiving it from multiple peers on the network. If your network connection is not being intercepted,
* hearing about a transaction from multiple peers indicates the network has accepted the transaction and
* thus miners likely have too (miners have the final say in whether a transaction becomes valid or not).</li>
* <li>Seeing the transaction appear appear in a block on the main chain. Your confidence increases as the transaction
* becomes further buried under work. Work can be measured either in blocks (roughly, units of time), or
* amount of work done.</li>
* </ul>
*
* <p>Alternatively, you may know that the transaction is "dead", that is, one or more of its inputs have
* been double spent and will never confirm unless there is another re-org.</p>
*
* <p>TransactionConfidence is updated via the {@link com.dogecoin.dogecoinj.core.TransactionConfidence#incrementDepthInBlocks()}
* method to ensure the block depth is up to date.</p>
* To make a copy that won't be changed, use {@link com.dogecoin.dogecoinj.core.TransactionConfidence#duplicate()}.
*/
public class TransactionConfidence implements Serializable {
private static final long serialVersionUID = 4577920141400556444L;
/**
* The peers that have announced the transaction to us. Network nodes don't have stable identities, so we use
* IP address as an approximation. It's obviously vulnerable to being gamed if we allow arbitrary people to connect
* to us, so only peers we explicitly connected to should go here.
*/
private CopyOnWriteArrayList<PeerAddress> broadcastBy;
/** The Transaction that this confidence object is associated with. */
private final Sha256Hash hash;
// Lazily created listeners array.
private transient CopyOnWriteArrayList<ListenerRegistration<Listener>> listeners;
// The depth of the transaction on the best chain in blocks. An unconfirmed block has depth 0.
private int depth;
/** Describes the state of the transaction in general terms. Properties can be read to learn specifics. */
public enum ConfidenceType {
/** If BUILDING, then the transaction is included in the best chain and your confidence in it is increasing. */
BUILDING(1),
/**
* If PENDING, then the transaction is unconfirmed and should be included shortly, as long as it is being
* announced and is considered valid by the network. A pending transaction will be announced if the containing
* wallet has been attached to a live {@link PeerGroup} using {@link PeerGroup#addWallet(Wallet)}.
* You can estimate how likely the transaction is to be included by connecting to a bunch of nodes then measuring
* how many announce it, using {@link com.dogecoin.dogecoinj.core.TransactionConfidence#numBroadcastPeers()}.
* Or if you saw it from a trusted peer, you can assume it's valid and will get mined sooner or later as well.
*/
PENDING(2),
/**
* If DEAD, then it means the transaction won't confirm unless there is another re-org,
* because some other transaction is spending one of its inputs. Such transactions should be alerted to the user
* so they can take action, eg, suspending shipment of goods if they are a merchant.
* It can also mean that a coinbase transaction has been made dead from it being moved onto a side chain.
*/
DEAD(4),
/**
* If a transaction hasn't been broadcast yet, or there's no record of it, its confidence is UNKNOWN.
*/
UNKNOWN(0);
private int value;
ConfidenceType(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
private ConfidenceType confidenceType = ConfidenceType.UNKNOWN;
private int appearedAtChainHeight = -1;
// The transaction that double spent this one, if any.
private Transaction overridingTransaction;
/**
* Information about where the transaction was first seen (network, sent direct from peer, created by ourselves).
* Useful for risk analyzing pending transactions. Probably not that useful after a tx is included in the chain,
* unless re-org double spends start happening frequently.
*/
public enum Source {
/** We don't know where the transaction came from. */
UNKNOWN,
/** We got this transaction from a network peer. */
NETWORK,
/** This transaction was created by our own wallet, so we know it's not a double spend. */
SELF
}
private Source source = Source.UNKNOWN;
public TransactionConfidence(Sha256Hash hash) {
// Assume a default number of peers for our set.
broadcastBy = new CopyOnWriteArrayList<PeerAddress>();
listeners = new CopyOnWriteArrayList<ListenerRegistration<Listener>>();
this.hash = hash;
}
/**
* <p>A confidence listener is informed when the level of {@link TransactionConfidence} is updated by something, like
* for example a {@link Wallet}. You can add listeners to update your user interface or manage your order tracking
* system when confidence levels pass a certain threshold. <b>Note that confidence can go down as well as up.</b>
* For example, this can happen if somebody is doing a double-spend attack against you. Whilst it's unlikely, your
* code should be able to handle that in order to be correct.</p>
*
* <p>During listener execution, it's safe to remove the current listener but not others.</p>
*/
public interface Listener {
/** An enum that describes why a transaction confidence listener is being invoked (i.e. the class of change). */
public enum ChangeReason {
/**
* Occurs when the type returned by {@link com.dogecoin.dogecoinj.core.TransactionConfidence#getConfidenceType()}
* has changed. For example, if a PENDING transaction changes to BUILDING or DEAD, then this reason will
* be given. It's a high level summary.
*/
TYPE,
/**
* Occurs when a transaction that is in the best known block chain gets buried by another block. If you're
* waiting for a certain number of confirmations, this is the reason to watch out for.
*/
DEPTH,
/**
* Occurs when a pending transaction (not in the chain) was announced by another connected peers. By
* watching the number of peers that announced a transaction go up, you can see whether it's being
* accepted by the network or not. If all your peers announce, it's a pretty good bet the transaction
* is considered relayable and has thus reached the miners.
*/
SEEN_PEERS,
}
public void onConfidenceChanged(TransactionConfidence confidence, ChangeReason reason);
}
/**
* <p>Adds an event listener that will be run when this confidence object is updated. The listener will be locked and
* is likely to be invoked on a peer thread.</p>
*
* <p>Note that this is NOT called when every block arrives. Instead it is called when the transaction
* transitions between confidence states, ie, from not being seen in the chain to being seen (not necessarily in
* the best chain). If you want to know when the transaction gets buried under another block, consider using
* a future from {@link #getDepthFuture(int)}.</p>
*/
public void addEventListener(Listener listener, Executor executor) {
checkNotNull(listener);
listeners.addIfAbsent(new ListenerRegistration<Listener>(listener, executor));
}
/**
* <p>Adds an event listener that will be run when this confidence object is updated. The listener will be locked and
* is likely to be invoked on a peer thread.</p>
*
* <p>Note that this is NOT called when every block arrives. Instead it is called when the transaction
* transitions between confidence states, ie, from not being seen in the chain to being seen (not necessarily in
* the best chain). If you want to know when the transaction gets buried under another block, implement a
* {@link BlockChainListener}, attach it to a {@link BlockChain} and then use the getters on the
* confidence object to determine the new depth.</p>
*/
public void addEventListener(Listener listener) {
addEventListener(listener, Threading.USER_THREAD);
}
public boolean removeEventListener(Listener listener) {
checkNotNull(listener);
return ListenerRegistration.removeFromList(listener, listeners);
}
/**
* Returns the chain height at which the transaction appeared if confidence type is BUILDING.
* @throws IllegalStateException if the confidence type is not BUILDING.
*/
public synchronized int getAppearedAtChainHeight() {
if (getConfidenceType() != ConfidenceType.BUILDING)
throw new IllegalStateException("Confidence type is " + getConfidenceType() + ", not BUILDING");
return appearedAtChainHeight;
}
/**
* The chain height at which the transaction appeared, if it has been seen in the best chain. Automatically sets
* the current type to {@link ConfidenceType#BUILDING} and depth to one.
*/
public synchronized void setAppearedAtChainHeight(int appearedAtChainHeight) {
if (appearedAtChainHeight < 0)
throw new IllegalArgumentException("appearedAtChainHeight out of range");
this.appearedAtChainHeight = appearedAtChainHeight;
this.depth = 1;
setConfidenceType(ConfidenceType.BUILDING);
}
/**
* Returns a general statement of the level of confidence you can have in this transaction.
*/
public synchronized ConfidenceType getConfidenceType() {
return confidenceType;
}
/**
* Called by other objects in the system, like a {@link Wallet}, when new information about the confidence of a
* transaction becomes available.
*/
public synchronized void setConfidenceType(ConfidenceType confidenceType) {
if (confidenceType == this.confidenceType)
return;
this.confidenceType = confidenceType;
if (confidenceType != ConfidenceType.DEAD) {
overridingTransaction = null;
}
if (confidenceType == ConfidenceType.PENDING) {
depth = 0;
appearedAtChainHeight = -1;
}
}
/**
* Called by a {@link Peer} when a transaction is pending and announced by a peer. The more peers announce the
* transaction, the more peers have validated it (assuming your internet connection is not being intercepted).
* If confidence is currently unknown, sets it to {@link ConfidenceType#PENDING}. Listeners will be
* invoked in this case.
*
* @param address IP address of the peer, used as a proxy for identity.
*/
public synchronized boolean markBroadcastBy(PeerAddress address) {
if (!broadcastBy.addIfAbsent(address))
return false; // Duplicate.
if (getConfidenceType() == ConfidenceType.UNKNOWN) {
this.confidenceType = ConfidenceType.PENDING;
}
return true;
}
/**
* Returns how many peers have been passed to {@link TransactionConfidence#markBroadcastBy}.
*/
public int numBroadcastPeers() {
return broadcastBy.size();
}
/**
* Returns a snapshot of {@link PeerAddress}es that announced the transaction.
*/
public Set<PeerAddress> getBroadcastBy() {
ListIterator<PeerAddress> iterator = broadcastBy.listIterator();
return Sets.newHashSet(iterator);
}
/** Returns true if the given address has been seen via markBroadcastBy() */
public boolean wasBroadcastBy(PeerAddress address) {
return broadcastBy.contains(address);
}
@Override
public synchronized String toString() {
StringBuilder builder = new StringBuilder();
int peers = numBroadcastPeers();
if (peers > 0) {
builder.append("Seen by ");
builder.append(peers);
if (peers > 1)
builder.append(" peers. ");
else
builder.append(" peer. ");
}
switch (getConfidenceType()) {
case UNKNOWN:
builder.append("Unknown confidence level.");
break;
case DEAD:
builder.append("Dead: overridden by double spend and will not confirm.");
break;
case PENDING:
builder.append("Pending/unconfirmed.");
break;
case BUILDING:
builder.append(String.format("Appeared in best chain at height %d, depth %d.",
getAppearedAtChainHeight(), getDepthInBlocks()));
break;
}
return builder.toString();
}
/**
* Called by the wallet when the tx appears on the best chain and a new block is added to the top. Updates the
* internal counter that tracks how deeply buried the block is.
*/
public synchronized void incrementDepthInBlocks() {
this.depth++;
}
/**
* <p>Depth in the chain is an approximation of how much time has elapsed since the transaction has been confirmed.
* On average there is supposed to be a new block every 10 minutes, but the actual rate may vary. The reference
* (Satoshi) implementation considers a transaction impractical to reverse after 6 blocks, but as of EOY 2011 network
* security is high enough that often only one block is considered enough even for high value transactions. For low
* value transactions like songs, or other cheap items, no blocks at all may be necessary.</p>
*
* <p>If the transaction appears in the top block, the depth is one. If it's anything else (pending, dead, unknown)
* the depth is zero.</p>
*/
public synchronized int getDepthInBlocks() {
return depth;
}
/*
* Set the depth in blocks. Having one block confirmation is a depth of one.
*/
public synchronized void setDepthInBlocks(int depth) {
this.depth = depth;
}
/**
* If this transaction has been overridden by a double spend (is dead), this call returns the overriding transaction.
* Note that this call <b>can return null</b> if you have migrated an old wallet, as pre-Jan 2012 wallets did not
* store this information.
*
* @return the transaction that double spent this one
* @throws IllegalStateException if confidence type is not OVERRIDDEN_BY_DOUBLE_SPEND.
*/
public synchronized Transaction getOverridingTransaction() {
if (getConfidenceType() != ConfidenceType.DEAD)
throw new IllegalStateException("Confidence type is " + getConfidenceType() +
", not OVERRIDDEN_BY_DOUBLE_SPEND");
return overridingTransaction;
}
/**
* Called when the transaction becomes newly dead, that is, we learn that one of its inputs has already been spent
* in such a way that the double-spending transaction takes precedence over this one. It will not become valid now
* unless there is a re-org. Automatically sets the confidence type to DEAD. The overriding transaction may not
* directly double spend this one, but could also have double spent a dependency of this tx.
*/
public synchronized void setOverridingTransaction(@Nullable Transaction overridingTransaction) {
this.overridingTransaction = overridingTransaction;
setConfidenceType(ConfidenceType.DEAD);
}
/** Returns a copy of this object. Event listeners are not duplicated. */
public synchronized TransactionConfidence duplicate() {
TransactionConfidence c = new TransactionConfidence(hash);
// There is no point in this sync block, it's just to help FindBugs.
synchronized (c) {
c.broadcastBy.addAll(broadcastBy);
c.confidenceType = confidenceType;
c.overridingTransaction = overridingTransaction;
c.appearedAtChainHeight = appearedAtChainHeight;
return c;
}
}
/**
* Call this after adjusting the confidence, for cases where listeners should be notified. This has to be done
* explicitly rather than being done automatically because sometimes complex changes to transaction states can
* result in a series of confidence changes that are not really useful to see separately. By invoking listeners
* explicitly, more precise control is available. Note that this will run the listeners on the user code thread.
*/
public void queueListeners(final Listener.ChangeReason reason) {
for (final ListenerRegistration<Listener> registration : listeners) {
registration.executor.execute(new Runnable() {
@Override
public void run() {
registration.listener.onConfidenceChanged(TransactionConfidence.this, reason);
}
});
}
}
/**
* The source of a transaction tries to identify where it came from originally. For instance, did we download it
* from the peer to peer network, or make it ourselves, or receive it via Bluetooth, or import it from another app,
* and so on. This information is useful for {@link com.dogecoin.dogecoinj.wallet.CoinSelector} implementations to risk analyze
* transactions and decide when to spend them.
*/
public synchronized Source getSource() {
return source;
}
/**
* The source of a transaction tries to identify where it came from originally. For instance, did we download it
* from the peer to peer network, or make it ourselves, or receive it via Bluetooth, or import it from another app,
* and so on. This information is useful for {@link com.dogecoin.dogecoinj.wallet.CoinSelector} implementations to risk analyze
* transactions and decide when to spend them.
*/
public synchronized void setSource(Source source) {
this.source = source;
}
/**
* Returns a future that completes when the transaction has been confirmed by "depth" blocks. For instance setting
* depth to one will wait until it appears in a block on the best chain, and zero will wait until it has been seen
* on the network.
*/
public synchronized ListenableFuture<TransactionConfidence> getDepthFuture(final int depth, Executor executor) {
final SettableFuture<TransactionConfidence> result = SettableFuture.create();
if (getDepthInBlocks() >= depth) {
result.set(this);
}
addEventListener(new Listener() {
@Override public void onConfidenceChanged(TransactionConfidence confidence, ChangeReason reason) {
if (getDepthInBlocks() >= depth) {
removeEventListener(this);
result.set(confidence);
}
}
}, executor);
return result;
}
public synchronized ListenableFuture<TransactionConfidence> getDepthFuture(final int depth) {
return getDepthFuture(depth, Threading.USER_THREAD);
}
public Sha256Hash getTransactionHash() {
return hash;
}
}

View File

@ -1,499 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* 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 com.dogecoin.dogecoinj.core;
import com.dogecoin.dogecoinj.script.Script;
import com.dogecoin.dogecoinj.wallet.DefaultRiskAnalysis;
import com.dogecoin.dogecoinj.wallet.KeyBag;
import com.dogecoin.dogecoinj.wallet.RedeemData;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Map;
import static com.google.common.base.Preconditions.checkElementIndex;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* A transfer of coins from one address to another creates a transaction in which the outputs
* can be claimed by the recipient in the input of another transaction. You can imagine a
* transaction as being a module which is wired up to others, the inputs of one have to be wired
* to the outputs of another. The exceptions are coinbase transactions, which create new coins.
*/
public class TransactionInput extends ChildMessage implements Serializable {
public static final long NO_SEQUENCE = 0xFFFFFFFFL;
private static final long serialVersionUID = 2;
public static final byte[] EMPTY_ARRAY = new byte[0];
// Allows for altering transactions after they were broadcast. Tx replacement is currently disabled in the C++
// client so this is always the UINT_MAX.
// TODO: Document this in more detail and build features that use it.
private long sequence;
// Data needed to connect to the output of the transaction we're gathering coins from.
private TransactionOutPoint outpoint;
// The "script bytes" might not actually be a script. In coinbase transactions where new coins are minted there
// is no input transaction, so instead the scriptBytes contains some extra stuff (like a rollover nonce) that we
// don't care about much. The bytes are turned into a Script object (cached below) on demand via a getter.
private byte[] scriptBytes;
// The Script object obtained from parsing scriptBytes. Only filled in on demand and if the transaction is not
// coinbase.
transient private WeakReference<Script> scriptSig;
/** Value of the output connected to the input, if known. This field does not participate in equals()/hashCode(). */
@Nullable
private Coin value;
/**
* Creates an input that connects to nothing - used only in creation of coinbase transactions.
*/
public TransactionInput(NetworkParameters params, @Nullable Transaction parentTransaction, byte[] scriptBytes) {
this(params, parentTransaction, scriptBytes, new TransactionOutPoint(params, NO_SEQUENCE, (Transaction) null));
}
public TransactionInput(NetworkParameters params, @Nullable Transaction parentTransaction, byte[] scriptBytes,
TransactionOutPoint outpoint) {
this(params, parentTransaction, scriptBytes, outpoint, null);
}
public TransactionInput(NetworkParameters params, @Nullable Transaction parentTransaction, byte[] scriptBytes,
TransactionOutPoint outpoint, @Nullable Coin value) {
super(params);
this.scriptBytes = scriptBytes;
this.outpoint = outpoint;
this.sequence = NO_SEQUENCE;
this.value = value;
setParent(parentTransaction);
length = 40 + (scriptBytes == null ? 1 : VarInt.sizeOf(scriptBytes.length) + scriptBytes.length);
}
/**
* Creates an UNSIGNED input that links to the given output
*/
TransactionInput(NetworkParameters params, Transaction parentTransaction, TransactionOutput output) {
super(params);
long outputIndex = output.getIndex();
if(output.getParentTransaction() != null ) {
outpoint = new TransactionOutPoint(params, outputIndex, output.getParentTransaction());
} else {
outpoint = new TransactionOutPoint(params, output);
}
scriptBytes = EMPTY_ARRAY;
sequence = NO_SEQUENCE;
setParent(parentTransaction);
this.value = output.getValue();
length = 41;
}
/**
* Deserializes an input message. This is usually part of a transaction message.
*/
public TransactionInput(NetworkParameters params, @Nullable Transaction parentTransaction, byte[] payload, int offset) throws ProtocolException {
super(params, payload, offset);
setParent(parentTransaction);
this.value = null;
}
/**
* Deserializes an input message. This is usually part of a transaction message.
* @param params NetworkParameters object.
* @param payload Bitcoin protocol formatted byte array containing message content.
* @param offset The location of the first payload byte within the array.
* @param parseLazy Whether to perform a full parse immediately or delay until a read is requested.
* @param parseRetain Whether to retain the backing byte array for quick reserialization.
* If true and the backing byte array is invalidated due to modification of a field then
* the cached bytes may be repopulated and retained if the message is serialized again in the future.
* as the length will be provided as part of the header. If unknown then set to Message.UNKNOWN_LENGTH
* @throws ProtocolException
*/
public TransactionInput(NetworkParameters params, Transaction parentTransaction, byte[] payload, int offset,
boolean parseLazy, boolean parseRetain)
throws ProtocolException {
super(params, payload, offset, parentTransaction, parseLazy, parseRetain, UNKNOWN_LENGTH);
this.value = null;
}
@Override
protected void parseLite() throws ProtocolException {
int curs = cursor;
int scriptLen = (int) readVarInt(36);
length = cursor - offset + scriptLen + 4;
cursor = curs;
}
@Override
void parse() throws ProtocolException {
outpoint = new TransactionOutPoint(params, payload, cursor, this, parseLazy, parseRetain);
cursor += outpoint.getMessageSize();
int scriptLen = (int) readVarInt();
scriptBytes = readBytes(scriptLen);
sequence = readUint32();
}
@Override
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
outpoint.bitcoinSerialize(stream);
stream.write(new VarInt(scriptBytes.length).encode());
stream.write(scriptBytes);
Utils.uint32ToByteStreamLE(sequence, stream);
}
/**
* Coinbase transactions have special inputs with hashes of zero. If this is such an input, returns true.
*/
public boolean isCoinBase() {
maybeParse();
return outpoint.getHash().equals(Sha256Hash.ZERO_HASH) &&
(outpoint.getIndex() & 0xFFFFFFFFL) == 0xFFFFFFFFL; // -1 but all is serialized to the wire as unsigned int.
}
/**
* Returns the script that is fed to the referenced output (scriptPubKey) script in order to satisfy it: usually
* contains signatures and maybe keys, but can contain arbitrary data if the output script accepts it.
*/
public Script getScriptSig() throws ScriptException {
// Transactions that generate new coins don't actually have a script. Instead this
// parameter is overloaded to be something totally different.
Script script = scriptSig == null ? null : scriptSig.get();
if (script == null) {
maybeParse();
script = new Script(scriptBytes);
scriptSig = new WeakReference<Script>(script);
return script;
}
return script;
}
/** Set the given program as the scriptSig that is supposed to satisfy the connected output script. */
public void setScriptSig(Script scriptSig) {
this.scriptSig = new WeakReference<Script>(checkNotNull(scriptSig));
// TODO: This should all be cleaned up so we have a consistent internal representation.
setScriptBytes(scriptSig.getProgram());
}
/**
* Convenience method that returns the from address of this input by parsing the scriptSig. The concept of a
* "from address" is not well defined in Bitcoin and you should not assume that senders of a transaction can
* actually receive coins on the same address they used to sign (e.g. this is not true for shared wallets).
*/
@Deprecated
public Address getFromAddress() throws ScriptException {
if (isCoinBase()) {
throw new ScriptException(
"This is a coinbase transaction which generates new coins. It does not have a from address.");
}
return getScriptSig().getFromAddress(params);
}
/**
* Sequence numbers allow participants in a multi-party transaction signing protocol to create new versions of the
* transaction independently of each other. Newer versions of a transaction can replace an existing version that's
* in nodes memory pools if the existing version is time locked. See the Contracts page on the Bitcoin wiki for
* examples of how you can use this feature to build contract protocols. Note that as of 2012 the tx replacement
* feature is disabled so sequence numbers are unusable.
*/
public long getSequenceNumber() {
maybeParse();
return sequence;
}
/**
* Sequence numbers allow participants in a multi-party transaction signing protocol to create new versions of the
* transaction independently of each other. Newer versions of a transaction can replace an existing version that's
* in nodes memory pools if the existing version is time locked. See the Contracts page on the Bitcoin wiki for
* examples of how you can use this feature to build contract protocols. Note that as of 2012 the tx replacement
* feature is disabled so sequence numbers are unusable.
*/
public void setSequenceNumber(long sequence) {
unCache();
this.sequence = sequence;
}
/**
* @return The previous output transaction reference, as an OutPoint structure. This contains the
* data needed to connect to the output of the transaction we're gathering coins from.
*/
public TransactionOutPoint getOutpoint() {
maybeParse();
return outpoint;
}
/**
* The "script bytes" might not actually be a script. In coinbase transactions where new coins are minted there
* is no input transaction, so instead the scriptBytes contains some extra stuff (like a rollover nonce) that we
* don't care about much. The bytes are turned into a Script object (cached below) on demand via a getter.
* @return the scriptBytes
*/
public byte[] getScriptBytes() {
maybeParse();
return scriptBytes;
}
/**
* @param scriptBytes the scriptBytes to set
*/
void setScriptBytes(byte[] scriptBytes) {
unCache();
this.scriptSig = null;
int oldLength = length;
this.scriptBytes = scriptBytes;
// 40 = previous_outpoint (36) + sequence (4)
int newLength = 40 + (scriptBytes == null ? 1 : VarInt.sizeOf(scriptBytes.length) + scriptBytes.length);
adjustLength(newLength - oldLength);
}
/**
* @return The Transaction that owns this input.
*/
public Transaction getParentTransaction() {
return (Transaction) parent;
}
/**
* @return Value of the output connected to this input, if known. Null if unknown.
*/
@Nullable
public Coin getValue() {
return value;
}
/**
* Returns a human readable debug string.
*/
@Override
public String toString() {
if (isCoinBase())
return "TxIn: COINBASE";
try {
return "TxIn for [" + outpoint + "]: " + getScriptSig();
} catch (ScriptException e) {
throw new RuntimeException(e);
}
}
public enum ConnectionResult {
NO_SUCH_TX,
ALREADY_SPENT,
SUCCESS
}
// TODO: Clean all this up once TransactionOutPoint disappears.
/**
* Locates the referenced output from the given pool of transactions.
*
* @return The TransactionOutput or null if the transactions map doesn't contain the referenced tx.
*/
@Nullable
TransactionOutput getConnectedOutput(Map<Sha256Hash, Transaction> transactions) {
Transaction tx = transactions.get(outpoint.getHash());
if (tx == null)
return null;
return tx.getOutputs().get((int) outpoint.getIndex());
}
/**
* Alias for getOutpoint().getConnectedRedeemData(keyBag)
* @see TransactionOutPoint#getConnectedRedeemData(com.dogecoin.dogecoinj.wallet.KeyBag)
*/
@Nullable
public RedeemData getConnectedRedeemData(KeyBag keyBag) throws ScriptException {
return getOutpoint().getConnectedRedeemData(keyBag);
}
public enum ConnectMode {
DISCONNECT_ON_CONFLICT,
ABORT_ON_CONFLICT
}
/**
* Connects this input to the relevant output of the referenced transaction if it's in the given map.
* Connecting means updating the internal pointers and spent flags. If the mode is to ABORT_ON_CONFLICT then
* the spent output won't be changed, but the outpoint.fromTx pointer will still be updated.
*
* @param transactions Map of txhash->transaction.
* @param mode Whether to abort if there's a pre-existing connection or not.
* @return NO_SUCH_TX if the prevtx wasn't found, ALREADY_SPENT if there was a conflict, SUCCESS if not.
*/
public ConnectionResult connect(Map<Sha256Hash, Transaction> transactions, ConnectMode mode) {
Transaction tx = transactions.get(outpoint.getHash());
if (tx == null) {
return TransactionInput.ConnectionResult.NO_SUCH_TX;
}
return connect(tx, mode);
}
/**
* Connects this input to the relevant output of the referenced transaction.
* Connecting means updating the internal pointers and spent flags. If the mode is to ABORT_ON_CONFLICT then
* the spent output won't be changed, but the outpoint.fromTx pointer will still be updated.
*
* @param transaction The transaction to try.
* @param mode Whether to abort if there's a pre-existing connection or not.
* @return NO_SUCH_TX if transaction is not the prevtx, ALREADY_SPENT if there was a conflict, SUCCESS if not.
*/
public ConnectionResult connect(Transaction transaction, ConnectMode mode) {
if (!transaction.getHash().equals(outpoint.getHash()))
return ConnectionResult.NO_SUCH_TX;
checkElementIndex((int) outpoint.getIndex(), transaction.getOutputs().size(), "Corrupt transaction");
TransactionOutput out = transaction.getOutput((int) outpoint.getIndex());
if (!out.isAvailableForSpending()) {
if (getParentTransaction().equals(outpoint.fromTx)) {
// Already connected.
return ConnectionResult.SUCCESS;
} else if (mode == ConnectMode.DISCONNECT_ON_CONFLICT) {
out.markAsUnspent();
} else if (mode == ConnectMode.ABORT_ON_CONFLICT) {
outpoint.fromTx = out.getParentTransaction();
return TransactionInput.ConnectionResult.ALREADY_SPENT;
}
}
connect(out);
return TransactionInput.ConnectionResult.SUCCESS;
}
/** Internal use only: connects this TransactionInput to the given output (updates pointers and spent flags) */
public void connect(TransactionOutput out) {
outpoint.fromTx = out.getParentTransaction();
out.markAsSpent(this);
value = out.getValue();
}
/**
* If this input is connected, check the output is connected back to this input and release it if so, making
* it spendable once again.
*
* @return true if the disconnection took place, false if it was not connected.
*/
public boolean disconnect() {
if (outpoint.fromTx == null) return false;
TransactionOutput output = outpoint.fromTx.getOutput((int) outpoint.getIndex());
if (output.getSpentBy() == this) {
output.markAsUnspent();
outpoint.fromTx = null;
return true;
} else {
return false;
}
}
/**
* Ensure object is fully parsed before invoking java serialization. The backing byte array
* is transient so if the object has parseLazy = true and hasn't invoked checkParse yet
* then data will be lost during serialization.
*/
private void writeObject(ObjectOutputStream out) throws IOException {
maybeParse();
out.defaultWriteObject();
}
/**
* @return true if this transaction's sequence number is set (ie it may be a part of a time-locked transaction)
*/
public boolean hasSequence() {
return sequence != NO_SEQUENCE;
}
/**
* For a connected transaction, runs the script against the connected pubkey and verifies they are correct.
* @throws ScriptException if the script did not verify.
* @throws VerificationException If the outpoint doesn't match the given output.
*/
public void verify() throws VerificationException {
final Transaction fromTx = getOutpoint().fromTx;
long spendingIndex = getOutpoint().getIndex();
checkNotNull(fromTx, "Not connected");
final TransactionOutput output = fromTx.getOutput((int) spendingIndex);
verify(output);
}
/**
* Verifies that this input can spend the given output. Note that this input must be a part of a transaction.
* Also note that the consistency of the outpoint will be checked, even if this input has not been connected.
*
* @param output the output that this input is supposed to spend.
* @throws ScriptException If the script doesn't verify.
* @throws VerificationException If the outpoint doesn't match the given output.
*/
public void verify(TransactionOutput output) throws VerificationException {
if (output.parent != null) {
if (!getOutpoint().getHash().equals(output.getParentTransaction().getHash()))
throw new VerificationException("This input does not refer to the tx containing the output.");
if (getOutpoint().getIndex() != output.getIndex())
throw new VerificationException("This input refers to a different output on the given tx.");
}
Script pubKey = output.getScriptPubKey();
int myIndex = getParentTransaction().getInputs().indexOf(this);
getScriptSig().correctlySpends(getParentTransaction(), myIndex, pubKey);
}
/**
* Returns the connected output, assuming the input was connected with
* {@link TransactionInput#connect(TransactionOutput)} or variants at some point. If it wasn't connected, then
* this method returns null.
*/
@Nullable
public TransactionOutput getConnectedOutput() {
return getOutpoint().getConnectedOutput();
}
/** Returns a copy of the input detached from its containing transaction, if need be. */
public TransactionInput duplicateDetached() {
return new TransactionInput(params, null, bitcoinSerialize(), 0);
}
/**
* <p>Returns either RuleViolation.NONE if the input is standard, or which rule makes it non-standard if so.
* The "IsStandard" rules control whether the default Bitcoin Core client blocks relay of a tx / refuses to mine it,
* however, non-standard transactions can still be included in blocks and will be accepted as valid if so.</p>
*
* <p>This method simply calls <tt>DefaultRiskAnalysis.isInputStandard(this)</tt>.</p>
*/
public DefaultRiskAnalysis.RuleViolation isStandard() {
return DefaultRiskAnalysis.isInputStandard(this);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TransactionInput input = (TransactionInput) o;
if (sequence != input.sequence) return false;
if (!outpoint.equals(input.outpoint)) return false;
if (!Arrays.equals(scriptBytes, input.scriptBytes)) return false;
if (scriptSig != null ? !scriptSig.equals(input.scriptSig) : input.scriptSig != null) return false;
if (parent != input.parent) return false;
return true;
}
@Override
public int hashCode() {
int result = (int) (sequence ^ (sequence >>> 32));
result = 31 * result + outpoint.hashCode();
result = 31 * result + (scriptBytes != null ? Arrays.hashCode(scriptBytes) : 0);
result = 31 * result + (scriptSig != null ? scriptSig.hashCode() : 0);
return result;
}
}

View File

@ -1,250 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import com.dogecoin.dogecoinj.script.Script;
import com.dogecoin.dogecoinj.wallet.KeyBag;
import com.dogecoin.dogecoinj.wallet.RedeemData;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
/**
* This message is a reference or pointer to an output of a different transaction.
*/
public class TransactionOutPoint extends ChildMessage implements Serializable {
private static final long serialVersionUID = -6320880638344662579L;
static final int MESSAGE_LENGTH = 36;
/** Hash of the transaction to which we refer. */
private Sha256Hash hash;
/** Which output of that transaction we are talking about. */
private long index;
// This is not part of Bitcoin serialization. It's included in Java serialization.
// It points to the connected transaction.
Transaction fromTx;
// The connected output.
private TransactionOutput connectedOutput;
public TransactionOutPoint(NetworkParameters params, long index, @Nullable Transaction fromTx) {
super(params);
this.index = index;
if (fromTx != null) {
this.hash = fromTx.getHash();
this.fromTx = fromTx;
} else {
// This happens when constructing the genesis block.
hash = Sha256Hash.ZERO_HASH;
}
length = MESSAGE_LENGTH;
}
public TransactionOutPoint(NetworkParameters params, long index, Sha256Hash hash) {
super(params);
this.index = index;
this.hash = hash;
length = MESSAGE_LENGTH;
}
public TransactionOutPoint(NetworkParameters params, TransactionOutput connectedOutput) {
this(params, connectedOutput.getIndex(), connectedOutput.getParentTransactionHash());
this.connectedOutput = connectedOutput;
}
/**
/**
* Deserializes the message. This is usually part of a transaction message.
*/
public TransactionOutPoint(NetworkParameters params, byte[] payload, int offset) throws ProtocolException {
super(params, payload, offset);
}
/**
* Deserializes the message. This is usually part of a transaction message.
* @param params NetworkParameters object.
* @param offset The location of the first payload byte within the array.
* @param parseLazy Whether to perform a full parse immediately or delay until a read is requested.
* @param parseRetain Whether to retain the backing byte array for quick reserialization.
* If true and the backing byte array is invalidated due to modification of a field then
* the cached bytes may be repopulated and retained if the message is serialized again in the future.
* @throws ProtocolException
*/
public TransactionOutPoint(NetworkParameters params, byte[] payload, int offset, Message parent, boolean parseLazy, boolean parseRetain) throws ProtocolException {
super(params, payload, offset, parent, parseLazy, parseRetain, MESSAGE_LENGTH);
}
@Override
protected void parseLite() throws ProtocolException {
length = MESSAGE_LENGTH;
}
@Override
void parse() throws ProtocolException {
hash = readHash();
index = readUint32();
}
/* (non-Javadoc)
* @see Message#getMessageSize()
*/
@Override
public int getMessageSize() {
return MESSAGE_LENGTH;
}
@Override
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
stream.write(Utils.reverseBytes(hash.getBytes()));
Utils.uint32ToByteStreamLE(index, stream);
}
/**
* An outpoint is a part of a transaction input that points to the output of another transaction. If we have both
* sides in memory, and they have been linked together, this returns a pointer to the connected output, or null
* if there is no such connection.
*/
@Nullable
public TransactionOutput getConnectedOutput() {
if (fromTx != null) {
return fromTx.getOutputs().get((int) index);
} else if (connectedOutput != null) {
return connectedOutput;
}
return null;
}
/**
* Returns the pubkey script from the connected output.
* @throws java.lang.NullPointerException if there is no connected output.
*/
public byte[] getConnectedPubKeyScript() {
byte[] result = checkNotNull(getConnectedOutput()).getScriptBytes();
checkState(result.length > 0);
return result;
}
/**
* Returns the ECKey identified in the connected output, for either pay-to-address scripts or pay-to-key scripts.
* For P2SH scripts you can use {@link #getConnectedRedeemData(com.dogecoin.dogecoinj.wallet.KeyBag)} and then get the
* key from RedeemData.
* If the script form cannot be understood, throws ScriptException.
*
* @return an ECKey or null if the connected key cannot be found in the wallet.
*/
@Nullable
public ECKey getConnectedKey(KeyBag keyBag) throws ScriptException {
TransactionOutput connectedOutput = getConnectedOutput();
checkNotNull(connectedOutput, "Input is not connected so cannot retrieve key");
Script connectedScript = connectedOutput.getScriptPubKey();
if (connectedScript.isSentToAddress()) {
byte[] addressBytes = connectedScript.getPubKeyHash();
return keyBag.findKeyFromPubHash(addressBytes);
} else if (connectedScript.isSentToRawPubKey()) {
byte[] pubkeyBytes = connectedScript.getPubKey();
return keyBag.findKeyFromPubKey(pubkeyBytes);
} else {
throw new ScriptException("Could not understand form of connected output script: " + connectedScript);
}
}
/**
* Returns the RedeemData identified in the connected output, for either pay-to-address scripts, pay-to-key
* or P2SH scripts.
* If the script forms cannot be understood, throws ScriptException.
*
* @return a RedeemData or null if the connected data cannot be found in the wallet.
*/
@Nullable
public RedeemData getConnectedRedeemData(KeyBag keyBag) throws ScriptException {
TransactionOutput connectedOutput = getConnectedOutput();
checkNotNull(connectedOutput, "Input is not connected so cannot retrieve key");
Script connectedScript = connectedOutput.getScriptPubKey();
if (connectedScript.isSentToAddress()) {
byte[] addressBytes = connectedScript.getPubKeyHash();
return RedeemData.of(keyBag.findKeyFromPubHash(addressBytes), connectedScript);
} else if (connectedScript.isSentToRawPubKey()) {
byte[] pubkeyBytes = connectedScript.getPubKey();
return RedeemData.of(keyBag.findKeyFromPubKey(pubkeyBytes), connectedScript);
} else if (connectedScript.isPayToScriptHash()) {
byte[] scriptHash = connectedScript.getPubKeyHash();
return keyBag.findRedeemDataFromScriptHash(scriptHash);
} else {
throw new ScriptException("Could not understand form of connected output script: " + connectedScript);
}
}
@Override
public String toString() {
return hash.toString() + ":" + index;
}
/**
* Returns the hash of the transaction this outpoint references/spends/is connected to.
*/
@Override
public Sha256Hash getHash() {
maybeParse();
return hash;
}
void setHash(Sha256Hash hash) {
this.hash = hash;
}
public long getIndex() {
maybeParse();
return index;
}
public void setIndex(long index) {
this.index = index;
}
/**
* Ensure object is fully parsed before invoking java serialization. The backing byte array
* is transient so if the object has parseLazy = true and hasn't invoked checkParse yet
* then data will be lost during serialization.
*/
private void writeObject(ObjectOutputStream out) throws IOException {
maybeParse();
out.defaultWriteObject();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TransactionOutPoint other = (TransactionOutPoint) o;
return getIndex() == other.getIndex() &&
getHash().equals(other.getHash());
}
@Override
public int hashCode() {
return getHash().hashCode();
}
}

View File

@ -1,470 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* 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 com.dogecoin.dogecoinj.core;
import com.dogecoin.dogecoinj.script.Script;
import com.dogecoin.dogecoinj.script.ScriptBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import static com.google.common.base.Preconditions.*;
/**
* A TransactionOutput message contains a scriptPubKey that controls who is able to spend its value. It is a sub-part
* of the Transaction message.
*/
public class TransactionOutput extends ChildMessage implements Serializable {
private static final Logger log = LoggerFactory.getLogger(TransactionOutput.class);
private static final long serialVersionUID = -590332479859256824L;
// The output's value is kept as a native type in order to save class instances.
private long value;
// A transaction output has a script used for authenticating that the redeemer is allowed to spend
// this output.
private byte[] scriptBytes;
// The script bytes are parsed and turned into a Script on demand.
private transient WeakReference<Script> scriptPubKey;
// These fields are Java serialized but not Bitcoin serialized. They are used for tracking purposes in our wallet
// only. If set to true, this output is counted towards our balance. If false and spentBy is null the tx output
// was owned by us and was sent to somebody else. If false and spentBy is set it means this output was owned by
// us and used in one of our own transactions (eg, because it is a change output).
private boolean availableForSpending;
@Nullable private TransactionInput spentBy;
private transient int scriptLen;
/**
* Deserializes a transaction output message. This is usually part of a transaction message.
*/
public TransactionOutput(NetworkParameters params, @Nullable Transaction parent, byte[] payload,
int offset) throws ProtocolException {
super(params, payload, offset);
setParent(parent);
availableForSpending = true;
}
/**
* Deserializes a transaction output message. This is usually part of a transaction message.
*
* @param params NetworkParameters object.
* @param payload Bitcoin protocol formatted byte array containing message content.
* @param offset The location of the first payload byte within the array.
* @param parseLazy Whether to perform a full parse immediately or delay until a read is requested.
* @param parseRetain Whether to retain the backing byte array for quick reserialization.
* If true and the backing byte array is invalidated due to modification of a field then
* the cached bytes may be repopulated and retained if the message is serialized again in the future.
* @throws ProtocolException
*/
public TransactionOutput(NetworkParameters params, @Nullable Transaction parent, byte[] payload, int offset,
boolean parseLazy, boolean parseRetain) throws ProtocolException {
super(params, payload, offset, parent, parseLazy, parseRetain, UNKNOWN_LENGTH);
availableForSpending = true;
}
/**
* Creates an output that sends 'value' to the given address (public key hash). The amount should be created with
* something like {@link Coin#valueOf(int, int)}. Typically you would use
* {@link Transaction#addOutput(Coin, Address)} instead of creating a TransactionOutput directly.
*/
public TransactionOutput(NetworkParameters params, @Nullable Transaction parent, Coin value, Address to) {
this(params, parent, value, ScriptBuilder.createOutputScript(to).getProgram());
}
/**
* Creates an output that sends 'value' to the given public key using a simple CHECKSIG script (no addresses). The
* amount should be created with something like {@link Coin#valueOf(int, int)}. Typically you would use
* {@link Transaction#addOutput(Coin, ECKey)} instead of creating an output directly.
*/
public TransactionOutput(NetworkParameters params, @Nullable Transaction parent, Coin value, ECKey to) {
this(params, parent, value, ScriptBuilder.createOutputScript(to).getProgram());
}
public TransactionOutput(NetworkParameters params, @Nullable Transaction parent, Coin value, byte[] scriptBytes) {
super(params);
// Negative values obviously make no sense, except for -1 which is used as a sentinel value when calculating
// SIGHASH_SINGLE signatures, so unfortunately we have to allow that here.
checkArgument(value.signum() >= 0 || value.equals(Coin.NEGATIVE_SATOSHI), "Negative values not allowed");
checkArgument(value.compareTo(NetworkParameters.MAX_MONEY) < 0, "Values larger than MAX_MONEY not allowed");
this.value = value.value;
this.scriptBytes = scriptBytes;
setParent(parent);
availableForSpending = true;
length = 8 + VarInt.sizeOf(scriptBytes.length) + scriptBytes.length;
}
public Script getScriptPubKey() throws ScriptException {
// Quick hack to try and reduce memory consumption on Androids. SoftReference is the same as WeakReference
// on Dalvik (by design), so this arrangement just means that we can avoid the cost of re-parsing the script
// bytes if getScriptPubKey is called multiple times in quick succession in between garbage collections.
Script script = scriptPubKey == null ? null : scriptPubKey.get();
if (script == null) {
maybeParse();
script = new Script(scriptBytes);
scriptPubKey = new WeakReference<Script>(script);
return script;
}
return script;
}
/**
* <p>If the output script pays to an address as in <a href="https://bitcoin.org/en/developer-guide#term-p2pkh">
* P2PKH</a>, return the address of the receiver, i.e., a base58 encoded hash of the public key in the script. </p>
*
* @param networkParameters needed to specify an address
* @return null, if the output script is not the form <i>OP_DUP OP_HASH160 <PubkeyHash> OP_EQUALVERIFY OP_CHECKSIG</i>,
* i.e., not P2PKH
* @return an address made out of the public key hash
*/
@Nullable
public Address getAddressFromP2PKHScript(NetworkParameters networkParameters) throws ScriptException{
if (getScriptPubKey().isSentToAddress())
return getScriptPubKey().getToAddress(networkParameters);
return null;
}
/**
* <p>If the output script pays to a redeem script, return the address of the redeem script as described by,
* i.e., a base58 encoding of [one-byte version][20-byte hash][4-byte checksum], where the 20-byte hash refers to
* the redeem script.</p>
*
* <p>P2SH is described by <a href="https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki">BIP 16</a> and
* <a href="https://bitcoin.org/en/developer-guide#p2sh-scripts">documented in the Bitcoin Developer Guide</a>.</p>
*
* @param networkParameters needed to specify an address
* @return null if the output script does not pay to a script hash
* @return an address that belongs to the redeem script
*/
@Nullable
public Address getAddressFromP2SH(NetworkParameters networkParameters) throws ScriptException{
if (getScriptPubKey().isPayToScriptHash())
return getScriptPubKey().getToAddress(networkParameters);
return null;
}
@Override
protected void parseLite() throws ProtocolException {
value = readInt64();
scriptLen = (int) readVarInt();
length = cursor - offset + scriptLen;
}
@Override
void parse() throws ProtocolException {
scriptBytes = readBytes(scriptLen);
}
@Override
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
checkNotNull(scriptBytes);
maybeParse();
Utils.int64ToByteStreamLE(value, stream);
// TODO: Move script serialization into the Script class, where it belongs.
stream.write(new VarInt(scriptBytes.length).encode());
stream.write(scriptBytes);
}
/**
* Returns the value of this output. This is the amount of currency that the destination address
* receives.
*/
public Coin getValue() {
maybeParse();
try {
return Coin.valueOf(value);
} catch (IllegalArgumentException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
/**
* Sets the value of this output.
*/
public void setValue(Coin value) {
checkNotNull(value);
unCache();
this.value = value.value;
}
/**
* Gets the index of this output in the parent transaction, or throws if this output is free standing. Iterates
* over the parents list to discover this.
*/
public int getIndex() {
for (int i = 0; i < getParentTransaction().getOutputs().size(); i++) {
if (getParentTransaction().getOutputs().get(i) == this)
return i;
}
throw new IllegalStateException("Output linked to wrong parent transaction?");
}
/**
* <p>Gets the minimum value for a txout of this size to be considered non-dust by a reference client
* (and thus relayed). See: CTxOut::IsDust() in the reference client. The assumption is that any output that would
* consume more than a third of its value in fees is not something the Bitcoin system wants to deal with right now,
* so we call them "dust outputs" and they're made non standard. The choice of one third is somewhat arbitrary and
* may change in future.</p>
*
* <p>You probably should use {@link com.dogecoin.dogecoinj.core.TransactionOutput#getMinNonDustValue()} which uses
* a safe fee-per-kb by default.</p>
*
* @param feePerKbRequired The fee required per kilobyte. Note that this is the same as the reference client's -minrelaytxfee * 3
* If you want a safe default, use {@link Transaction#REFERENCE_DEFAULT_MIN_TX_FEE}*3
*/
public Coin getMinNonDustValue(Coin feePerKbRequired) {
// A typical output is 33 bytes (pubkey hash + opcodes) and requires an input of 148 bytes to spend so we add
// that together to find out the total amount of data used to transfer this amount of value. Note that this
// formula is wrong for anything that's not a pay-to-address output, unfortunately, we must follow the reference
// clients wrongness in order to ensure we're considered standard. A better formula would either estimate the
// size of data needed to satisfy all different script types, or just hard code 33 below.
// DOGE doesn't enforce these rules. Therefore we consider each output as valid.
return Coin.ZERO;
/**final BigInteger size = BigInteger.valueOf(this.bitcoinSerialize().length + 148);
BigInteger[] nonDustAndRemainder = feePerKbRequired.multiply(size).divideAndRemainder(BigInteger.valueOf(1000));
return nonDustAndRemainder[1].equals(BigInteger.ZERO) ? nonDustAndRemainder[0] : nonDustAndRemainder[0].add(BigInteger.ONE);**/
}
/**
* Returns the minimum value for this output to be considered "not dust", i.e. the transaction will be relayable
* and mined by default miners. For normal pay to address outputs, this is 546 satoshis, the same as
* {@link Transaction#MIN_NONDUST_OUTPUT}.
*/
public Coin getMinNonDustValue() {
return getMinNonDustValue(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.multiply(3));
}
/**
* Sets this objects availableForSpending flag to false and the spentBy pointer to the given input.
* If the input is null, it means this output was signed over to somebody else rather than one of our own keys.
* @throws IllegalStateException if the transaction was already marked as spent.
*/
public void markAsSpent(TransactionInput input) {
checkState(availableForSpending);
availableForSpending = false;
spentBy = input;
if (parent != null)
if (log.isDebugEnabled()) log.debug("Marked {}:{} as spent by {}", getParentTransaction().getHash(), getIndex(), input);
else
if (log.isDebugEnabled()) log.debug("Marked floating output as spent by {}", input);
}
/**
* Resets the spent pointer / availableForSpending flag to null.
*/
public void markAsUnspent() {
if (parent != null)
if (log.isDebugEnabled()) log.debug("Un-marked {}:{} as spent by {}", getParentTransaction().getHash(), getIndex(), spentBy);
else
if (log.isDebugEnabled()) log.debug("Un-marked floating output as spent by {}", spentBy);
availableForSpending = true;
spentBy = null;
}
/**
* Returns whether {@link TransactionOutput#markAsSpent(TransactionInput)} has been called on this class. A
* {@link Wallet} will mark a transaction output as spent once it sees a transaction input that is connected to it.
* Note that this flag can be false when an output has in fact been spent according to the rest of the network if
* the spending transaction wasn't downloaded yet, and it can be marked as spent when in reality the rest of the
* network believes it to be unspent if the signature or script connecting to it was not actually valid.
*/
public boolean isAvailableForSpending() {
return availableForSpending;
}
/**
* The backing script bytes which can be turned into a Script object.
* @return the scriptBytes
*/
public byte[] getScriptBytes() {
maybeParse();
return scriptBytes;
}
/**
* Returns true if this output is to a key in the wallet or to an address/script we are watching.
*/
public boolean isMineOrWatched(TransactionBag transactionBag) {
return isMine(transactionBag) || isWatched(transactionBag);
}
/**
* Returns true if this output is to a key, or an address we have the keys for, in the wallet.
*/
public boolean isWatched(TransactionBag transactionBag) {
try {
Script script = getScriptPubKey();
return transactionBag.isWatchedScript(script);
} catch (ScriptException e) {
// Just means we didn't understand the output of this transaction: ignore it.
log.debug("Could not parse tx output script: {}", e.toString());
return false;
}
}
/**
* Returns true if this output is to a key, or an address we have the keys for, in the wallet.
*/
public boolean isMine(TransactionBag transactionBag) {
try {
Script script = getScriptPubKey();
if (script.isSentToRawPubKey()) {
byte[] pubkey = script.getPubKey();
return transactionBag.isPubKeyMine(pubkey);
} if (script.isPayToScriptHash()) {
return transactionBag.isPayToScriptHashMine(script.getPubKeyHash());
} else {
byte[] pubkeyHash = script.getPubKeyHash();
return transactionBag.isPubKeyHashMine(pubkeyHash);
}
} catch (ScriptException e) {
// Just means we didn't understand the output of this transaction: ignore it.
log.debug("Could not parse tx output script: {}", e.toString());
return false;
}
}
/**
* Returns a human readable debug string.
*/
@Override
public String toString() {
try {
Script script = getScriptPubKey();
StringBuilder buf = new StringBuilder("TxOut of ");
buf.append(Coin.valueOf(value).toFriendlyString());
if (script.isSentToAddress() || script.isPayToScriptHash())
buf.append(" to ").append(script.getToAddress(params));
else if (script.isSentToRawPubKey())
buf.append(" to pubkey ").append(Utils.HEX.encode(script.getPubKey()));
else if (script.isSentToMultiSig())
buf.append(" to multisig");
else
buf.append(" (unknown type)");
buf.append(" script:");
buf.append(script);
return buf.toString();
} catch (ScriptException e) {
throw new RuntimeException(e);
}
}
/**
* Returns the connected input.
*/
@Nullable
public TransactionInput getSpentBy() {
return spentBy;
}
/**
* Returns the transaction that owns this output.
*/
@Nullable
public Transaction getParentTransaction() {
if(parent != null) {
return (Transaction) parent;
}
return null;
}
/**
* Returns the transaction hash that owns this output.
*/
@Nullable
public Sha256Hash getParentTransactionHash() {
if (getParentTransaction() != null) {
return getParentTransaction().getHash();
}
return null;
}
/**
* Returns the depth in blocks of the parent tx.
*
* <p>If the transaction appears in the top block, the depth is one. If it's anything else (pending, dead, unknown)
* then -1.</p>
* @return The tx depth or -1.
*/
public int getParentTransactionDepthInBlocks() {
if (getParentTransaction() != null) {
TransactionConfidence confidence = getParentTransaction().getConfidence();
if (confidence.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) {
return confidence.getDepthInBlocks();
}
}
return -1;
}
/**
* Ensure object is fully parsed before invoking java serialization. The backing byte array
* is transient so if the object has parseLazy = true and hasn't invoked checkParse yet
* then data will be lost during serialization.
*/
private void writeObject(ObjectOutputStream out) throws IOException {
maybeParse();
out.defaultWriteObject();
}
/**
* Returns a new {@link TransactionOutPoint}, which is essentially a structure pointing to this output.
* Requires that this output is not detached.
*/
public TransactionOutPoint getOutPointFor() {
return new TransactionOutPoint(params, getIndex(), getParentTransaction());
}
/** Returns a copy of the output detached from its containing transaction, if need be. */
public TransactionOutput duplicateDetached() {
return new TransactionOutput(params, null, Coin.valueOf(value), org.spongycastle.util.Arrays.clone(scriptBytes));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TransactionOutput other = (TransactionOutput) o;
if (!Arrays.equals(scriptBytes, other.scriptBytes)) return false;
if (value != other.value) return false;
if (parent != null && parent != other.parent) return false;
return true;
}
@Override
public int hashCode() {
return 31 * (int) value + (scriptBytes != null ? Arrays.hashCode(scriptBytes) : 0);
}
}

View File

@ -1,77 +0,0 @@
/**
* Copyright 2012 Matt Corallo.
*
* 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 com.dogecoin.dogecoinj.core;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.List;
/**
* <p>TransactionOutputChanges represents a delta to the set of unspent outputs. It used as a return value for
* {@link AbstractBlockChain#connectTransactions(int, Block)}. It contains the full list of transaction outputs created
* and spent in a block. It DOES contain outputs created that were spent later in the block, as those are needed for
* BIP30 (no duplicate txid creation if the previous one was not fully spent prior to this block) verification.</p>
*/
public class TransactionOutputChanges {
public final List<UTXO> txOutsCreated;
public final List<UTXO> txOutsSpent;
public TransactionOutputChanges(List<UTXO> txOutsCreated, List<UTXO> txOutsSpent) {
this.txOutsCreated = txOutsCreated;
this.txOutsSpent = txOutsSpent;
}
public TransactionOutputChanges(InputStream in) throws IOException {
int numOutsCreated = ((in.read() & 0xFF) << 0) |
((in.read() & 0xFF) << 8) |
((in.read() & 0xFF) << 16) |
((in.read() & 0xFF) << 24);
txOutsCreated = new LinkedList<UTXO>();
for (int i = 0; i < numOutsCreated; i++)
txOutsCreated.add(new UTXO(in));
int numOutsSpent = ((in.read() & 0xFF) << 0) |
((in.read() & 0xFF) << 8) |
((in.read() & 0xFF) << 16) |
((in.read() & 0xFF) << 24);
txOutsSpent = new LinkedList<UTXO>();
for (int i = 0; i < numOutsSpent; i++)
txOutsSpent.add(new UTXO(in));
}
public void serializeToStream(OutputStream bos) throws IOException {
int numOutsCreated = txOutsCreated.size();
bos.write(0xFF & (numOutsCreated >> 0));
bos.write(0xFF & (numOutsCreated >> 8));
bos.write(0xFF & (numOutsCreated >> 16));
bos.write(0xFF & (numOutsCreated >> 24));
for (UTXO output : txOutsCreated) {
output.serializeToStream(bos);
}
int numOutsSpent = txOutsSpent.size();
bos.write(0xFF & (numOutsSpent >> 0));
bos.write(0xFF & (numOutsSpent >> 8));
bos.write(0xFF & (numOutsSpent >> 16));
bos.write(0xFF & (numOutsSpent >> 24));
for (UTXO output : txOutsSpent) {
output.serializeToStream(bos);
}
}
}

View File

@ -1,318 +0,0 @@
/*
* Copyright 2012 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import com.dogecoin.dogecoinj.utils.Threading;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
/**
* <p>Tracks transactions that are being announced across the network. Typically one is created for you by a
* {@link PeerGroup} and then given to each Peer to update. The current purpose is to let Peers update the confidence
* (number of peers broadcasting). It helps address an attack scenario in which a malicious remote peer (or several)
* feeds you invalid transactions, eg, ones that spend coins which don't exist. If you don't see most of the peers
* announce the transaction within a reasonable time, it may be that the TX is not valid. Alternatively, an attacker
* may control your entire internet connection: in this scenario counting broadcasting peers does not help you.</p>
*
* <p>It is <b>not</b> at this time directly equivalent to the Satoshi clients memory pool, which tracks
* all transactions not currently included in the best chain - it's simply a cache.</p>
*/
public class TxConfidenceTable {
private static final Logger log = LoggerFactory.getLogger(TxConfidenceTable.class);
protected ReentrantLock lock = Threading.lock("txconfidencetable");
// For each transaction we may have seen:
// - only its hash in an inv packet
// - the full transaction itself, if we asked for it to be sent to us (or a peer sent it regardless), or if we
// sent it.
//
// Before we see the full transaction, we need to track how many peers advertised it, so we can estimate its
// confidence pre-chain inclusion assuming an un-tampered with network connection. After we see the full transaction
// we need to switch from tracking that data in the Entry to tracking it in the TransactionConfidence object itself.
private static class WeakTransactionReference extends WeakReference<Transaction> {
public Sha256Hash hash;
public WeakTransactionReference(Transaction tx, ReferenceQueue<Transaction> queue) {
super(tx, queue);
hash = tx.getHash();
}
}
private static class Entry {
// Invariants: one of the two fields must be null, to indicate which is used.
Set<PeerAddress> addresses;
// We keep a weak reference to the transaction. This means that if no other bit of code finds the transaction
// worth keeping around it will drop out of memory and we will, at some point, forget about it, which means
// both addresses and tx.get() will be null. When this happens the WeakTransactionReference appears in the queue
// allowing us to delete the associated entry (the tx itself has already gone away).
WeakTransactionReference tx;
}
private LinkedHashMap<Sha256Hash, Entry> table;
// This ReferenceQueue gets entries added to it when they are only weakly reachable, ie, the TxConfidenceTable is the
// only thing that is tracking the transaction anymore. We check it from time to time and delete table entries
// corresponding to expired transactions. In this way memory usage of the system is in line with however many
// transactions you actually care to track the confidence of. We can still end up with lots of hashes being stored
// if our peers flood us with invs but the MAX_SIZE param caps this.
private ReferenceQueue<Transaction> referenceQueue;
/** The max size of a table created with the no-args constructor. */
public static final int MAX_SIZE = 1000;
/**
* Creates a table that will track at most the given number of transactions (allowing you to bound memory
* usage).
* @param size Max number of transactions to track. The table will fill up to this size then stop growing.
*/
public TxConfidenceTable(final int size) {
table = new LinkedHashMap<Sha256Hash, Entry>() {
@Override
protected boolean removeEldestEntry(Map.Entry<Sha256Hash, TxConfidenceTable.Entry> entry) {
// An arbitrary choice to stop the memory used by tracked transactions getting too huge in the event
// of some kind of DoS attack.
return size() > size;
}
};
referenceQueue = new ReferenceQueue<Transaction>();
}
/**
* Creates a table that will track at most {@link TxConfidenceTable#MAX_SIZE} entries. You should normally use
* this constructor.
*/
public TxConfidenceTable() {
this(MAX_SIZE);
}
/**
* If any transactions have expired due to being only weakly reachable through us, go ahead and delete their
* table entries - it means we downloaded the transaction and sent it to various event listeners, none of
* which bothered to keep a reference. Typically, this is because the transaction does not involve any keys that
* are relevant to any of our wallets.
*/
private void cleanTable() {
lock.lock();
try {
Reference<? extends Transaction> ref;
while ((ref = referenceQueue.poll()) != null) {
// Find which transaction got deleted by the GC.
WeakTransactionReference txRef = (WeakTransactionReference) ref;
// And remove the associated map entry so the other bits of memory can also be reclaimed.
table.remove(txRef.hash);
}
} finally {
lock.unlock();
}
}
/**
* Returns the number of peers that have seen the given hash recently.
*/
public int numBroadcastPeers(Sha256Hash txHash) {
lock.lock();
try {
cleanTable();
Entry entry = table.get(txHash);
if (entry == null) {
// No such TX known.
return 0;
} else if (entry.tx == null) {
// We've seen at least one peer announce with an inv.
checkNotNull(entry.addresses);
return entry.addresses.size();
} else {
final Transaction tx = entry.tx.get();
if (tx == null) {
// We previously downloaded this transaction, but nothing cared about it so the garbage collector threw
// it away. We also deleted the set that tracked which peers had seen it. Treat this case as a zero and
// just delete it from the map.
table.remove(txHash);
return 0;
} else {
checkState(entry.addresses == null);
return tx.getConfidence().numBroadcastPeers();
}
}
} finally {
lock.unlock();
}
}
/**
* Puts the tx into the table and returns either it, or a different Transaction object that has the same hash.
* Unlike seen and the other methods, this one does not imply that a tx has been announced by a peer and does
* not mark it as such.
*/
public Transaction intern(Transaction tx) {
lock.lock();
try {
cleanTable();
Entry entry = table.get(tx.getHash());
if (entry != null) {
// This TX or its hash have been previously interned.
if (entry.tx != null) {
// We already interned it (but may have thrown it away).
checkState(entry.addresses == null);
// We only want one canonical object instance for a transaction no matter how many times it is
// deserialized.
Transaction transaction = entry.tx.get();
if (transaction != null) {
// We saw it before and kept it around. Hand back the canonical copy.
tx = transaction;
}
return tx;
} else {
// We received a transaction that we have previously seen announced but not downloaded until now.
checkNotNull(entry.addresses);
entry.tx = new WeakTransactionReference(tx, referenceQueue);
Set<PeerAddress> addrs = entry.addresses;
entry.addresses = null;
TransactionConfidence confidence = tx.getConfidence();
log.debug("Adding tx [{}] {} to the confidence table",
confidence.numBroadcastPeers(), tx.getHashAsString());
for (PeerAddress a : addrs) {
markBroadcast(a, tx);
}
return tx;
}
} else {
// This often happens when we are downloading a Bloom filtered chain, or recursively downloading
// dependencies of a relevant transaction (see Peer.downloadDependencies).
log.debug("Provided with a downloaded transaction we didn't see announced yet: {}", tx.getHashAsString());
entry = new Entry();
entry.tx = new WeakTransactionReference(tx, referenceQueue);
table.put(tx.getHash(), entry);
return tx;
}
} finally {
lock.unlock();
}
}
/**
* Called by peers when they receive a "tx" message containing a valid serialized transaction.
* @param tx The TX deserialized from the wire.
* @param byPeer The Peer that received it.
* @return An object that is semantically the same TX but may be a different object instance.
*/
public Transaction seen(Transaction tx, PeerAddress byPeer) {
lock.lock();
try {
final Transaction interned = intern(tx);
markBroadcast(byPeer, interned);
return interned;
} finally {
lock.unlock();
}
}
/**
* Called by peers when they see a transaction advertised in an "inv" message. It either will increase the
* confidence of the pre-existing transaction or will just keep a record of the address for future usage.
*/
public void seen(Sha256Hash hash, PeerAddress byPeer) {
lock.lock();
try {
cleanTable();
Entry entry = table.get(hash);
if (entry != null) {
// This TX or its hash have been previously announced.
if (entry.tx != null) {
checkState(entry.addresses == null);
Transaction tx = entry.tx.get();
if (tx != null) {
markBroadcast(byPeer, tx);
log.debug("{}: Peer announced transaction we have seen before [{}] {}",
byPeer, tx.getConfidence().numBroadcastPeers(), tx.getHashAsString());
} else {
// The inv is telling us about a transaction that we previously downloaded, and threw away
// because nothing found it interesting enough to keep around. So do nothing.
}
} else {
checkNotNull(entry.addresses);
entry.addresses.add(byPeer);
log.debug("{}: Peer announced transaction we have seen announced before [{}] {}",
byPeer, entry.addresses.size(), hash);
}
} else {
// This TX has never been seen before.
entry = new Entry();
// TODO: Using hashsets here is inefficient compared to just having an array.
entry.addresses = new HashSet<PeerAddress>();
entry.addresses.add(byPeer);
table.put(hash, entry);
log.info("{}: Peer announced new transaction [1] {}", byPeer, hash);
}
} finally {
lock.unlock();
}
}
private void markBroadcast(PeerAddress byPeer, Transaction tx) {
checkState(lock.isHeldByCurrentThread());
final TransactionConfidence confidence = tx.getConfidence();
if (confidence.markBroadcastBy(byPeer))
confidence.queueListeners(TransactionConfidence.Listener.ChangeReason.SEEN_PEERS);
}
/**
* Returns the {@link Transaction} for the given hash if we have downloaded it, or null if that hash is unknown or
* we only saw advertisements for it yet or it has been downloaded but garbage collected due to nowhere else
* holding a reference to it.
*/
@Nullable
public Transaction get(Sha256Hash hash) {
lock.lock();
try {
Entry entry = table.get(hash);
if (entry == null) return null; // Unknown.
if (entry.tx == null) return null; // Seen but only in advertisements.
if (entry.tx.get() == null) return null; // Was downloaded but garbage collected.
Transaction tx = entry.tx.get();
checkNotNull(tx);
return tx;
} finally {
lock.unlock();
}
}
/**
* Returns true if the TX identified by hash has been seen before (ie, in an inv). Note that a transaction that
* was broadcast, downloaded and nothing kept a reference to it will eventually be cleared out by the garbage
* collector and wasSeen() will return false - it does not keep a permanent record of every hash ever broadcast.
*/
public boolean maybeWasSeen(Sha256Hash hash) {
lock.lock();
try {
Entry entry = table.get(hash);
return entry != null;
} finally {
lock.unlock();
}
}
}

View File

@ -1,249 +0,0 @@
/**
* Copyright 2012 Matt Corallo.
*
* 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 com.dogecoin.dogecoinj.core;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.math.BigInteger;
/**
* A UTXO message contains the information necessary to check a spending transaction.
* It avoids having to store the entire parentTransaction just to get the hash and index.
* Useful when working with free standing outputs.
*/
public class UTXO implements Serializable {
private static final Logger log = LoggerFactory.getLogger(UTXO.class);
private static final long serialVersionUID = -8744924157056340509L;
/**
* A transaction output has some value and a script used for authenticating that the redeemer is allowed to spend
* this output.
*/
private Coin value;
private byte[] scriptBytes;
/** Hash of the transaction to which we refer. */
private Sha256Hash hash;
/** Which output of that transaction we are talking about. */
private long index;
/** The height of the tx of this output */
private int height;
/** If this output is from a coinbase tx */
private boolean coinbase;
/** The address of this output */
private String address;
/** The type of this address */
private int addressType;
/**
* Creates a stored transaction output.
* @param hash The hash of the containing transaction.
* @param index The outpoint.
* @param value The value available.
* @param height The height this output was created in.
* @param coinbase The coinbase flag.
* @param scriptBytes The script bytes.
*/
public UTXO(Sha256Hash hash,
long index,
Coin value,
int height,
boolean coinbase,
byte[] scriptBytes) {
this.hash = hash;
this.index = index;
this.value = value;
this.height = height;
this.scriptBytes = scriptBytes;
this.coinbase = coinbase;
this.address = "";
this.addressType = 0;
}
/**
* Creates a stored transaction output.
* @param hash The hash of the containing transaction.
* @param index The outpoint.
* @param value The value available.
* @param height The height this output was created in.
* @param coinbase The coinbase flag.
* @param scriptBytes The script bytes.
* @param address The address.
* @param addressType The address type.
*/
public UTXO(Sha256Hash hash,
long index,
Coin value,
int height,
boolean coinbase,
byte[] scriptBytes,
String address,
int addressType) {
this(hash, index, value, height, coinbase, scriptBytes);
this.address = address;
this.addressType = addressType;
}
public UTXO(InputStream in) throws IOException {
byte[] valueBytes = new byte[8];
if (in.read(valueBytes, 0, 8) != 8)
throw new EOFException();
value = Coin.valueOf(Utils.readInt64(valueBytes, 0));
int scriptBytesLength = ((in.read() & 0xFF) << 0) |
((in.read() & 0xFF) << 8) |
((in.read() & 0xFF) << 16) |
((in.read() & 0xFF) << 24);
scriptBytes = new byte[scriptBytesLength];
if (in.read(scriptBytes) != scriptBytesLength)
throw new EOFException();
byte[] hashBytes = new byte[32];
if (in.read(hashBytes) != 32)
throw new EOFException();
hash = new Sha256Hash(hashBytes);
byte[] indexBytes = new byte[4];
if (in.read(indexBytes) != 4)
throw new EOFException();
index = Utils.readUint32(indexBytes, 0);
height = ((in.read() & 0xFF) << 0) |
((in.read() & 0xFF) << 8) |
((in.read() & 0xFF) << 16) |
((in.read() & 0xFF) << 24);
byte[] coinbaseByte = new byte[1];
in.read(coinbaseByte);
if (coinbaseByte[0] == 1) {
coinbase = true;
} else {
coinbase = false;
}
}
/**
* The value which this Transaction output holds.
* @return the value.
*/
public Coin getValue() {
return value;
}
/**
* The backing script bytes which can be turned into a Script object.
* @return the scriptBytes.
*/
public byte[] getScriptBytes() {
return scriptBytes;
}
/**
* The hash of the transaction which holds this output.
* @return the hash.
*/
public Sha256Hash getHash() {
return hash;
}
/**
* The index of this output in the transaction which holds it.
* @return the index.
*/
public long getIndex() {
return index;
}
/**
* Gets the height of the block that created this output.
* @return The height.
*/
public int getHeight() {
return height;
}
/**
* Gets the flag of whether this was created by a coinbase tx.
* @return The coinbase flag.
*/
public boolean isCoinbase() {
return coinbase;
}
/**
* The address of this output.
* @return The address.
*/
public String getAddress() {
return address;
}
/**
* The type of the address.
* @return The address type.
*/
public int getAddressType() {
return addressType;
}
@Override
public String toString() {
return String.format("Stored TxOut of %s (%s:%d)", value.toFriendlyString(), hash.toString(), index);
}
@Override
public int hashCode() {
return hash.hashCode() + (int)index;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UTXO other = (UTXO) o;
return getHash().equals(other.getHash()) &&
getIndex() == other.getIndex();
}
public void serializeToStream(OutputStream bos) throws IOException {
Utils.uint64ToByteStreamLE(BigInteger.valueOf(value.value), bos);
bos.write(0xFF & scriptBytes.length >> 0);
bos.write(0xFF & scriptBytes.length >> 8);
bos.write(0xFF & (scriptBytes.length >> 16));
bos.write(0xFF & (scriptBytes.length >> 24));
bos.write(scriptBytes);
bos.write(hash.getBytes());
Utils.uint32ToByteStreamLE(index, bos);
bos.write(0xFF & (height >> 0));
bos.write(0xFF & (height >> 8));
bos.write(0xFF & (height >> 16));
bos.write(0xFF & (height >> 24));
byte[] coinbaseByte = new byte[1];
if(coinbase) {
coinbaseByte[0] = 1;
} else {
coinbaseByte[0] = 0;
}
bos.write(coinbaseByte);
}
}

View File

@ -1,49 +0,0 @@
/**
* Copyright 2014 Kalpesh Parmar.
*
* 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 com.dogecoin.dogecoinj.core;
import java.util.List;
/**
* A UTXOProvider encapsulates functionality for returning unspent transaction outputs,
* for use by the wallet or other code that crafts spends.
*
* <p>A {@link com.dogecoin.dogecoinj.store.FullPrunedBlockStore} is an internal implementation within bitcoinj.</p>
*/
public interface UTXOProvider {
/**
* // TODO currently the access to outputs is by address. Change to ECKey
* Get the list of {@link UTXO}'s for a given address.
* @param addresses List of address.
* @return The list of transaction outputs.
* @throws UTXOProvider If there is an error.
*/
List<UTXO> getOpenTransactionOutputs(List<Address> addresses) throws UTXOProviderException;
/**
* Get the height of the chain head.
* @return The chain head height.
* @throws UTXOProvider If there is an error.
*/
int getChainHeadHeight() throws UTXOProviderException;
/**
* The {@link NetworkParameters} of this provider.
* @return The network parameters.
*/
NetworkParameters getParams();
}

View File

@ -1,34 +0,0 @@
/**
* Copyright 2014 Kalpesh Parmar.
*
* 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 com.dogecoin.dogecoinj.core;
public class UTXOProviderException extends Exception {
public UTXOProviderException() {
super();
}
public UTXOProviderException(String message) {
super(message);
}
public UTXOProviderException(String message, Throwable cause) {
super(message, cause);
}
public UTXOProviderException(Throwable cause) {
super(cause);
}
}

View File

@ -1,161 +0,0 @@
/*
* Copyright 2014 the bitcoinj authors
*
* 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 com.dogecoin.dogecoinj.core;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/** Message representing a list of unspent transaction outputs, returned in response to sending a GetUTXOsMessage. */
public class UTXOsMessage extends Message {
private long height;
private Sha256Hash chainHead;
private byte[] hits; // little-endian bitset indicating whether an output was found or not.
private List<TransactionOutput> outputs;
private long[] heights;
/** This is a special sentinel value that can appear in the heights field if the given tx is in the mempool. */
public static long MEMPOOL_HEIGHT = 0x7FFFFFFFL;
public UTXOsMessage(NetworkParameters params, byte[] payloadBytes) {
super(params, payloadBytes, 0);
}
/**
* Provide an array of output objects, with nulls indicating that the output was missing. The bitset will
* be calculated from this.
*/
public UTXOsMessage(NetworkParameters params, List<TransactionOutput> outputs, long[] heights, Sha256Hash chainHead, long height) {
super(params);
hits = new byte[(int) Math.ceil(outputs.size() / 8.0)];
for (int i = 0; i < outputs.size(); i++) {
if (outputs.get(i) != null)
Utils.setBitLE(hits, i);
}
this.outputs = new ArrayList<TransactionOutput>(outputs.size());
for (TransactionOutput output : outputs) {
if (output != null) this.outputs.add(output);
}
this.chainHead = chainHead;
this.height = height;
this.heights = Arrays.copyOf(heights, heights.length);
}
@Override
void bitcoinSerializeToStream(OutputStream stream) throws IOException {
Utils.uint32ToByteStreamLE(height, stream);
stream.write(chainHead.getBytes());
stream.write(new VarInt(hits.length).encode());
stream.write(hits);
stream.write(new VarInt(outputs.size()).encode());
for (TransactionOutput output : outputs) {
// TODO: Allow these to be specified, if one day we care about sending this message ourselves
// (currently it's just used for unit testing).
Utils.uint32ToByteStreamLE(0L, stream); // Version
Utils.uint32ToByteStreamLE(0L, stream); // Height
output.bitcoinSerializeToStream(stream);
}
}
@Override
void parse() throws ProtocolException {
// Format is:
// uint32 chainHeight
// uint256 chainHeadHash
// vector<unsigned char> hitsBitmap;
// vector<CCoin> outs;
//
// A CCoin is { int nVersion, int nHeight, CTxOut output }
// The bitmap indicates which of the requested TXOs were found in the UTXO set.
height = readUint32();
chainHead = readHash();
int numBytes = (int) readVarInt();
if (numBytes < 0 || numBytes > InventoryMessage.MAX_INVENTORY_ITEMS / 8)
throw new ProtocolException("hitsBitmap out of range: " + numBytes);
hits = readBytes(numBytes);
int numOuts = (int) readVarInt();
if (numOuts < 0 || numOuts > InventoryMessage.MAX_INVENTORY_ITEMS)
throw new ProtocolException("numOuts out of range: " + numOuts);
outputs = new ArrayList<TransactionOutput>(numOuts);
heights = new long[numOuts];
for (int i = 0; i < numOuts; i++) {
long version = readUint32();
long height = readUint32();
if (version > 1)
throw new ProtocolException("Unknown tx version in getutxo output: " + version);
TransactionOutput output = new TransactionOutput(params, null, payload, cursor);
outputs.add(output);
heights[i] = height;
cursor += output.length;
}
length = cursor;
}
@Override
protected void parseLite() throws ProtocolException {
// Not used.
}
public byte[] getHitMap() {
return Arrays.copyOf(hits, hits.length);
}
public List<TransactionOutput> getOutputs() {
return new ArrayList<TransactionOutput>(outputs);
}
public long[] getHeights() { return Arrays.copyOf(heights, heights.length); }
@Override
public String toString() {
return "UTXOsMessage{" +
"height=" + height +
", chainHead=" + chainHead +
", hitMap=" + Arrays.toString(hits) +
", outputs=" + outputs +
", heights=" + Arrays.toString(heights) +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UTXOsMessage message = (UTXOsMessage) o;
if (height != message.height) return false;
if (!chainHead.equals(message.chainHead)) return false;
if (!Arrays.equals(heights, message.heights)) return false;
if (!Arrays.equals(hits, message.hits)) return false;
if (!outputs.equals(message.outputs)) return false;
return true;
}
@Override
public int hashCode() {
int result = (int) (height ^ (height >>> 32));
result = 31 * result + chainHead.hashCode();
result = 31 * result + Arrays.hashCode(hits);
result = 31 * result + outputs.hashCode();
result = 31 * result + Arrays.hashCode(heights);
return result;
}
}

View File

@ -1,33 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* 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 com.dogecoin.dogecoinj.core;
public class UnknownMessage extends EmptyMessage {
private static final long serialVersionUID = 3614705938207918775L;
private String name;
public UnknownMessage(NetworkParameters params, String name, byte[] payloadBytes) throws ProtocolException {
super(params, payloadBytes, 0);
this.name = name;
}
@Override
public String toString() {
return "Unknown message [" + name + "]: " + (payload == null ? "" : Utils.HEX.encode(payload));
}
}

View File

@ -1,132 +0,0 @@
/**
* Copyright 2011 Steve Coughlan.
*
* 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 com.dogecoin.dogecoinj.core;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* An unsynchronized implementation of ByteArrayOutputStream that will return the backing byte array if its length == size().
* This avoids unneeded array copy where the BOS is simply being used to extract a byte array of known length from a
* 'serialized to stream' method.
* <p/>
* Unless the final length can be accurately predicted the only performance this will yield is due to unsynchronized
* methods.
*
* @author git
*/
public class UnsafeByteArrayOutputStream extends ByteArrayOutputStream {
public UnsafeByteArrayOutputStream() {
super(32);
}
public UnsafeByteArrayOutputStream(int size) {
super(size);
}
/**
* Writes the specified byte to this byte array output stream.
*
* @param b the byte to be written.
*/
@Override
public void write(int b) {
int newcount = count + 1;
if (newcount > buf.length) {
buf = Utils.copyOf(buf, Math.max(buf.length << 1, newcount));
}
buf[count] = (byte) b;
count = newcount;
}
/**
* Writes <code>len</code> bytes from the specified byte array
* starting at offset <code>off</code> to this byte array output stream.
*
* @param b the data.
* @param off the start offset in the data.
* @param len the number of bytes to write.
*/
@Override
public void write(byte b[], int off, int len) {
if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
int newcount = count + len;
if (newcount > buf.length) {
buf = Utils.copyOf(buf, Math.max(buf.length << 1, newcount));
}
System.arraycopy(b, off, buf, count, len);
count = newcount;
}
/**
* Writes the complete contents of this byte array output stream to
* the specified output stream argument, as if by calling the output
* stream's write method using <code>out.write(buf, 0, count)</code>.
*
* @param out the output stream to which to write the data.
* @throws IOException if an I/O error occurs.
*/
@Override
public void writeTo(OutputStream out) throws IOException {
out.write(buf, 0, count);
}
/**
* Resets the <code>count</code> field of this byte array output
* stream to zero, so that all currently accumulated output in the
* output stream is discarded. The output stream can be used again,
* reusing the already allocated buffer space.
*
* @see java.io.ByteArrayInputStream#count
*/
@Override
public void reset() {
count = 0;
}
/**
* Creates a newly allocated byte array. Its size is the current
* size of this output stream and the valid contents of the buffer
* have been copied into it.
*
* @return the current contents of this output stream, as a byte array.
* @see java.io.ByteArrayOutputStream#size()
*/
@Override
public byte toByteArray()[] {
return count == buf.length ? buf : Utils.copyOf(buf, count);
}
/**
* Returns the current size of the buffer.
*
* @return the value of the <code>count</code> field, which is the number
* of valid bytes in this output stream.
* @see java.io.ByteArrayOutputStream#count
*/
@Override
public int size() {
return count;
}
}

View File

@ -1,657 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* 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 com.dogecoin.dogecoinj.core;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
import com.google.common.io.BaseEncoding;
import com.google.common.io.Resources;
import com.google.common.primitives.Ints;
import com.google.common.primitives.UnsignedLongs;
import com.lambdaworks.crypto.SCrypt;
import org.spongycastle.crypto.digests.RIPEMD160Digest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.util.concurrent.Uninterruptibles.sleepUninterruptibly;
/**
* A collection of various utility methods that are helpful for working with the Bitcoin protocol.
* To enable debug logging from the library, run with -Dbitcoinj.logging=true on your command line.
*/
public class Utils {
private static final MessageDigest digest;
static {
try {
digest = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e); // Can't happen.
}
}
/** The string that prefixes all text messages signed using Bitcoin keys. */
public static final String BITCOIN_SIGNED_MESSAGE_HEADER = "Bitcoin Signed Message:\n";
public static final byte[] BITCOIN_SIGNED_MESSAGE_HEADER_BYTES = BITCOIN_SIGNED_MESSAGE_HEADER.getBytes(Charsets.UTF_8);
private static BlockingQueue<Boolean> mockSleepQueue;
/**
* The regular {@link java.math.BigInteger#toByteArray()} method isn't quite what we often need: it appends a
* leading zero to indicate that the number is positive and may need padding.
*
* @param b the integer to format into a byte array
* @param numBytes the desired size of the resulting byte array
* @return numBytes byte long array.
*/
public static byte[] bigIntegerToBytes(BigInteger b, int numBytes) {
if (b == null) {
return null;
}
byte[] bytes = new byte[numBytes];
byte[] biBytes = b.toByteArray();
int start = (biBytes.length == numBytes + 1) ? 1 : 0;
int length = Math.min(biBytes.length, numBytes);
System.arraycopy(biBytes, start, bytes, numBytes - length, length);
return bytes;
}
public static void uint32ToByteArrayBE(long val, byte[] out, int offset) {
out[offset + 0] = (byte) (0xFF & (val >> 24));
out[offset + 1] = (byte) (0xFF & (val >> 16));
out[offset + 2] = (byte) (0xFF & (val >> 8));
out[offset + 3] = (byte) (0xFF & (val >> 0));
}
public static void uint32ToByteArrayLE(long val, byte[] out, int offset) {
out[offset + 0] = (byte) (0xFF & (val >> 0));
out[offset + 1] = (byte) (0xFF & (val >> 8));
out[offset + 2] = (byte) (0xFF & (val >> 16));
out[offset + 3] = (byte) (0xFF & (val >> 24));
}
public static void uint64ToByteArrayLE(long val, byte[] out, int offset) {
out[offset + 0] = (byte) (0xFF & (val >> 0));
out[offset + 1] = (byte) (0xFF & (val >> 8));
out[offset + 2] = (byte) (0xFF & (val >> 16));
out[offset + 3] = (byte) (0xFF & (val >> 24));
out[offset + 4] = (byte) (0xFF & (val >> 32));
out[offset + 5] = (byte) (0xFF & (val >> 40));
out[offset + 6] = (byte) (0xFF & (val >> 48));
out[offset + 7] = (byte) (0xFF & (val >> 56));
}
public static void uint32ToByteStreamLE(long val, OutputStream stream) throws IOException {
stream.write((int) (0xFF & (val >> 0)));
stream.write((int) (0xFF & (val >> 8)));
stream.write((int) (0xFF & (val >> 16)));
stream.write((int) (0xFF & (val >> 24)));
}
public static void int64ToByteStreamLE(long val, OutputStream stream) throws IOException {
stream.write((int) (0xFF & (val >> 0)));
stream.write((int) (0xFF & (val >> 8)));
stream.write((int) (0xFF & (val >> 16)));
stream.write((int) (0xFF & (val >> 24)));
stream.write((int) (0xFF & (val >> 32)));
stream.write((int) (0xFF & (val >> 40)));
stream.write((int) (0xFF & (val >> 48)));
stream.write((int) (0xFF & (val >> 56)));
}
public static void uint64ToByteStreamLE(BigInteger val, OutputStream stream) throws IOException {
byte[] bytes = val.toByteArray();
if (bytes.length > 8) {
throw new RuntimeException("Input too large to encode into a uint64");
}
bytes = reverseBytes(bytes);
stream.write(bytes);
if (bytes.length < 8) {
for (int i = 0; i < 8 - bytes.length; i++)
stream.write(0);
}
}
/**
* See {@link Utils#doubleDigest(byte[], int, int)}.
*/
public static byte[] doubleDigest(byte[] input) {
return doubleDigest(input, 0, input.length);
}
/**
* Calculates the SHA-256 hash of the given byte range, and then hashes the resulting hash again. This is
* standard procedure in Bitcoin. The resulting hash is in big endian form.
*/
public static byte[] doubleDigest(byte[] input, int offset, int length) {
synchronized (digest) {
digest.reset();
digest.update(input, offset, length);
byte[] first = digest.digest();
return digest.digest(first);
}
}
public static byte[] scryptDigest(byte[] input) {
try {
return SCrypt.scrypt(input, input, 1024, 1, 1, 32);
} catch (Exception e) {
return null;
}
}
public static byte[] singleDigest(byte[] input, int offset, int length) {
synchronized (digest) {
digest.reset();
digest.update(input, offset, length);
return digest.digest();
}
}
/**
* Calculates SHA256(SHA256(byte range 1 + byte range 2)).
*/
public static byte[] doubleDigestTwoBuffers(byte[] input1, int offset1, int length1,
byte[] input2, int offset2, int length2) {
synchronized (digest) {
digest.reset();
digest.update(input1, offset1, length1);
digest.update(input2, offset2, length2);
byte[] first = digest.digest();
return digest.digest(first);
}
}
/**
* Work around lack of unsigned types in Java.
*/
public static boolean isLessThanUnsigned(long n1, long n2) {
return UnsignedLongs.compare(n1, n2) < 0;
}
/**
* Work around lack of unsigned types in Java.
*/
public static boolean isLessThanOrEqualToUnsigned(long n1, long n2) {
return UnsignedLongs.compare(n1, n2) <= 0;
}
/**
* Hex encoding used throughout the framework. Use with HEX.encode(byte[]) or HEX.decode(CharSequence).
*/
public static final BaseEncoding HEX = BaseEncoding.base16().lowerCase();
/**
* Returns a copy of the given byte array in reverse order.
*/
public static byte[] reverseBytes(byte[] bytes) {
// We could use the XOR trick here but it's easier to understand if we don't. If we find this is really a
// performance issue the matter can be revisited.
byte[] buf = new byte[bytes.length];
for (int i = 0; i < bytes.length; i++)
buf[i] = bytes[bytes.length - 1 - i];
return buf;
}
/**
* Returns a copy of the given byte array with the bytes of each double-word (4 bytes) reversed.
*
* @param bytes length must be divisible by 4.
* @param trimLength trim output to this length. If positive, must be divisible by 4.
*/
public static byte[] reverseDwordBytes(byte[] bytes, int trimLength) {
checkArgument(bytes.length % 4 == 0);
checkArgument(trimLength < 0 || trimLength % 4 == 0);
byte[] rev = new byte[trimLength >= 0 && bytes.length > trimLength ? trimLength : bytes.length];
for (int i = 0; i < rev.length; i += 4) {
System.arraycopy(bytes, i, rev, i , 4);
for (int j = 0; j < 4; j++) {
rev[i + j] = bytes[i + 3 - j];
}
}
return rev;
}
public static long readUint32(byte[] bytes, int offset) {
return ((bytes[offset++] & 0xFFL) << 0) |
((bytes[offset++] & 0xFFL) << 8) |
((bytes[offset++] & 0xFFL) << 16) |
((bytes[offset] & 0xFFL) << 24);
}
public static long readInt64(byte[] bytes, int offset) {
return ((bytes[offset++] & 0xFFL) << 0) |
((bytes[offset++] & 0xFFL) << 8) |
((bytes[offset++] & 0xFFL) << 16) |
((bytes[offset++] & 0xFFL) << 24) |
((bytes[offset++] & 0xFFL) << 32) |
((bytes[offset++] & 0xFFL) << 40) |
((bytes[offset++] & 0xFFL) << 48) |
((bytes[offset] & 0xFFL) << 56);
}
public static long readUint32BE(byte[] bytes, int offset) {
return ((bytes[offset + 0] & 0xFFL) << 24) |
((bytes[offset + 1] & 0xFFL) << 16) |
((bytes[offset + 2] & 0xFFL) << 8) |
((bytes[offset + 3] & 0xFFL) << 0);
}
public static int readUint16BE(byte[] bytes, int offset) {
return ((bytes[offset] & 0xff) << 8) | bytes[offset + 1] & 0xff;
}
/**
* Calculates RIPEMD160(SHA256(input)). This is used in Address calculations.
*/
public static byte[] sha256hash160(byte[] input) {
try {
byte[] sha256 = MessageDigest.getInstance("SHA-256").digest(input);
RIPEMD160Digest digest = new RIPEMD160Digest();
digest.update(sha256, 0, sha256.length);
byte[] out = new byte[20];
digest.doFinal(out, 0);
return out;
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e); // Cannot happen.
}
}
/**
* MPI encoded numbers are produced by the OpenSSL BN_bn2mpi function. They consist of
* a 4 byte big endian length field, followed by the stated number of bytes representing
* the number in big endian format (with a sign bit).
* @param hasLength can be set to false if the given array is missing the 4 byte length field
*/
public static BigInteger decodeMPI(byte[] mpi, boolean hasLength) {
byte[] buf;
if (hasLength) {
int length = (int) readUint32BE(mpi, 0);
buf = new byte[length];
System.arraycopy(mpi, 4, buf, 0, length);
} else
buf = mpi;
if (buf.length == 0)
return BigInteger.ZERO;
boolean isNegative = (buf[0] & 0x80) == 0x80;
if (isNegative)
buf[0] &= 0x7f;
BigInteger result = new BigInteger(buf);
return isNegative ? result.negate() : result;
}
/**
* MPI encoded numbers are produced by the OpenSSL BN_bn2mpi function. They consist of
* a 4 byte big endian length field, followed by the stated number of bytes representing
* the number in big endian format (with a sign bit).
* @param includeLength indicates whether the 4 byte length field should be included
*/
public static byte[] encodeMPI(BigInteger value, boolean includeLength) {
if (value.equals(BigInteger.ZERO)) {
if (!includeLength)
return new byte[] {};
else
return new byte[] {0x00, 0x00, 0x00, 0x00};
}
boolean isNegative = value.signum() < 0;
if (isNegative)
value = value.negate();
byte[] array = value.toByteArray();
int length = array.length;
if ((array[0] & 0x80) == 0x80)
length++;
if (includeLength) {
byte[] result = new byte[length + 4];
System.arraycopy(array, 0, result, length - array.length + 3, array.length);
uint32ToByteArrayBE(length, result, 0);
if (isNegative)
result[4] |= 0x80;
return result;
} else {
byte[] result;
if (length != array.length) {
result = new byte[length];
System.arraycopy(array, 0, result, 1, array.length);
}else
result = array;
if (isNegative)
result[0] |= 0x80;
return result;
}
}
/**
* <p>The "compact" format is a representation of a whole number N using an unsigned 32 bit number similar to a
* floating point format. The most significant 8 bits are the unsigned exponent of base 256. This exponent can
* be thought of as "number of bytes of N". The lower 23 bits are the mantissa. Bit number 24 (0x800000) represents
* the sign of N. Therefore, N = (-1^sign) * mantissa * 256^(exponent-3).</p>
*
* <p>Satoshi's original implementation used BN_bn2mpi() and BN_mpi2bn(). MPI uses the most significant bit of the
* first byte as sign. Thus 0x1234560000 is compact 0x05123456 and 0xc0de000000 is compact 0x0600c0de. Compact
* 0x05c0de00 would be -0x40de000000.</p>
*
* <p>Bitcoin only uses this "compact" format for encoding difficulty targets, which are unsigned 256bit quantities.
* Thus, all the complexities of the sign bit and using base 256 are probably an implementation accident.</p>
*/
public static BigInteger decodeCompactBits(long compact) {
int size = ((int) (compact >> 24)) & 0xFF;
byte[] bytes = new byte[4 + size];
bytes[3] = (byte) size;
if (size >= 1) bytes[4] = (byte) ((compact >> 16) & 0xFF);
if (size >= 2) bytes[5] = (byte) ((compact >> 8) & 0xFF);
if (size >= 3) bytes[6] = (byte) ((compact >> 0) & 0xFF);
return decodeMPI(bytes, true);
}
/**
* @see Utils#decodeCompactBits(long)
*/
public static long encodeCompactBits(BigInteger value) {
long result;
int size = value.toByteArray().length;
if (size <= 3)
result = value.longValue() << 8 * (3 - size);
else
result = value.shiftRight(8 * (size - 3)).longValue();
// The 0x00800000 bit denotes the sign.
// Thus, if it is already set, divide the mantissa by 256 and increase the exponent.
if ((result & 0x00800000L) != 0) {
result >>= 8;
size++;
}
result |= size << 24;
result |= value.signum() == -1 ? 0x00800000 : 0;
return result;
}
/**
* If non-null, overrides the return value of now().
*/
public static volatile Date mockTime;
/**
* Advances (or rewinds) the mock clock by the given number of seconds.
*/
public static Date rollMockClock(int seconds) {
return rollMockClockMillis(seconds * 1000);
}
/**
* Advances (or rewinds) the mock clock by the given number of milliseconds.
*/
public static Date rollMockClockMillis(long millis) {
if (mockTime == null)
throw new IllegalStateException("You need to use setMockClock() first.");
mockTime = new Date(mockTime.getTime() + millis);
return mockTime;
}
/**
* Sets the mock clock to the current time.
*/
public static void setMockClock() {
mockTime = new Date();
}
/**
* Sets the mock clock to the given time (in seconds).
*/
public static void setMockClock(long mockClockSeconds) {
mockTime = new Date(mockClockSeconds * 1000);
}
/**
* Returns the current time, or a mocked out equivalent.
*/
public static Date now() {
if (mockTime != null)
return mockTime;
else
return new Date();
}
// TODO: Replace usages of this where the result is / 1000 with currentTimeSeconds.
/** Returns the current time in milliseconds since the epoch, or a mocked out equivalent. */
public static long currentTimeMillis() {
if (mockTime != null)
return mockTime.getTime();
else
return System.currentTimeMillis();
}
public static long currentTimeSeconds() {
return currentTimeMillis() / 1000;
}
private static final TimeZone UTC = TimeZone.getTimeZone("UTC");
/**
* Formats a given date+time value to an ISO 8601 string.
* @param dateTime value to format, as a Date
*/
public static String dateTimeFormat(Date dateTime) {
DateFormat iso8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
iso8601.setTimeZone(UTC);
return iso8601.format(dateTime);
}
/**
* Formats a given date+time value to an ISO 8601 string.
* @param dateTime value to format, unix time (ms)
*/
public static String dateTimeFormat(long dateTime) {
DateFormat iso8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
iso8601.setTimeZone(UTC);
return iso8601.format(dateTime);
}
public static byte[] copyOf(byte[] in, int length) {
byte[] out = new byte[length];
System.arraycopy(in, 0, out, 0, Math.min(length, in.length));
return out;
}
/**
* Creates a copy of bytes and appends b to the end of it
*/
public static byte[] appendByte(byte[] bytes, byte b) {
byte[] result = Arrays.copyOf(bytes, bytes.length + 1);
result[result.length - 1] = b;
return result;
}
/**
* Attempts to parse the given string as arbitrary-length hex or base58 and then return the results, or null if
* neither parse was successful.
*/
public static byte[] parseAsHexOrBase58(String data) {
try {
return HEX.decode(data);
} catch (Exception e) {
// Didn't decode as hex, try base58.
try {
return Base58.decodeChecked(data);
} catch (AddressFormatException e1) {
return null;
}
}
}
public static boolean isWindows() {
return System.getProperty("os.name").toLowerCase().contains("win");
}
/**
* <p>Given a textual message, returns a byte buffer formatted as follows:</p>
*
* <tt><p>[24] "Bitcoin Signed Message:\n" [message.length as a varint] message</p></tt>
*/
public static byte[] formatMessageForSigning(String message) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bos.write(BITCOIN_SIGNED_MESSAGE_HEADER_BYTES.length);
bos.write(BITCOIN_SIGNED_MESSAGE_HEADER_BYTES);
byte[] messageBytes = message.getBytes(Charsets.UTF_8);
VarInt size = new VarInt(messageBytes.length);
bos.write(size.encode());
bos.write(messageBytes);
return bos.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e); // Cannot happen.
}
}
// 00000001, 00000010, 00000100, 00001000, ...
private static final int bitMask[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
/** Checks if the given bit is set in data, using little endian (not the same as Java native big endian) */
public static boolean checkBitLE(byte[] data, int index) {
return (data[index >>> 3] & bitMask[7 & index]) != 0;
}
/** Sets the given bit in data to one, using little endian (not the same as Java native big endian) */
public static void setBitLE(byte[] data, int index) {
data[index >>> 3] |= bitMask[7 & index];
}
/** Sleep for a span of time, or mock sleep if enabled */
public static void sleep(long millis) {
if (mockSleepQueue == null) {
sleepUninterruptibly(millis, TimeUnit.MILLISECONDS);
} else {
try {
boolean isMultiPass = mockSleepQueue.take();
rollMockClockMillis(millis);
if (isMultiPass)
mockSleepQueue.offer(true);
} catch (InterruptedException e) {
// Ignored.
}
}
}
/** Enable or disable mock sleep. If enabled, set mock time to current time. */
public static void setMockSleep(boolean isEnable) {
if (isEnable) {
mockSleepQueue = new ArrayBlockingQueue<Boolean>(1);
mockTime = new Date(System.currentTimeMillis());
} else {
mockSleepQueue = null;
}
}
/** Let sleeping thread pass the synchronization point. */
public static void passMockSleep() {
mockSleepQueue.offer(false);
}
/** Let the sleeping thread pass the synchronization point any number of times. */
public static void finishMockSleep() {
if (mockSleepQueue != null) {
mockSleepQueue.offer(true);
}
}
public static boolean isAndroidRuntime() {
final String runtime = System.getProperty("java.runtime.name");
return runtime != null && runtime.equals("Android Runtime");
}
private static class Pair implements Comparable<Pair> {
int item, count;
public Pair(int item, int count) { this.count = count; this.item = item; }
@Override public int compareTo(Pair o) { return -Ints.compare(count, o.count); }
}
public static int maxOfMostFreq(int... items) {
// Java 6 sucks.
ArrayList<Integer> list = new ArrayList<Integer>(items.length);
for (int item : items) list.add(item);
return maxOfMostFreq(list);
}
public static int maxOfMostFreq(List<Integer> items) {
if (items.isEmpty())
return 0;
// This would be much easier in a functional language (or in Java 8).
items = Ordering.natural().reverse().sortedCopy(items);
LinkedList<Pair> pairs = Lists.newLinkedList();
pairs.add(new Pair(items.get(0), 0));
for (int item : items) {
Pair pair = pairs.getLast();
if (pair.item != item)
pairs.add((pair = new Pair(item, 0)));
pair.count++;
}
// pairs now contains a uniqified list of the sorted inputs, with counts for how often that item appeared.
// Now sort by how frequently they occur, and pick the max of the most frequent.
Collections.sort(pairs);
int maxCount = pairs.getFirst().count;
int maxItem = pairs.getFirst().item;
for (Pair pair : pairs) {
if (pair.count != maxCount)
break;
maxItem = Math.max(maxItem, pair.item);
}
return maxItem;
}
/**
* Reads and joins together with LF char (\n) all the lines from given file. It's assumed that file is in UTF-8.
*/
public static String getResourceAsString(URL url) throws IOException {
List<String> lines = Resources.readLines(url, Charsets.UTF_8);
return Joiner.on('\n').join(lines);
}
// Can't use Closeable here because it's Java 7 only and Android devices only got that with KitKat.
public static InputStream closeUnchecked(InputStream stream) {
try {
stream.close();
return stream;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static OutputStream closeUnchecked(OutputStream stream) {
try {
stream.close();
return stream;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -1,114 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import static com.dogecoin.dogecoinj.core.Utils.isLessThanUnsigned;
import static com.dogecoin.dogecoinj.core.Utils.isLessThanOrEqualToUnsigned;
/**
* A variable-length encoded integer using Satoshis encoding.
*/
public class VarInt {
public final long value;
private final int originallyEncodedSize;
public VarInt(long value) {
this.value = value;
originallyEncodedSize = getSizeInBytes();
}
// Bitcoin has its own varint format, known in the C++ source as "compact size".
public VarInt(byte[] buf, int offset) {
int first = 0xFF & buf[offset];
if (first < 253) {
// 8 bits.
this.value = first;
originallyEncodedSize = 1;
} else if (first == 253) {
// 16 bits.
this.value = (0xFF & buf[offset + 1]) | ((0xFF & buf[offset + 2]) << 8);
originallyEncodedSize = 3;
} else if (first == 254) {
// 32 bits.
this.value = Utils.readUint32(buf, offset + 1);
originallyEncodedSize = 5;
} else {
// 64 bits.
this.value = Utils.readUint32(buf, offset + 1) | (Utils.readUint32(buf, offset + 5) << 32);
originallyEncodedSize = 9;
}
}
/**
* Gets the number of bytes used to encode this originally if deserialized from a byte array.
* Otherwise returns the minimum encoded size
*/
public int getOriginalSizeInBytes() {
return originallyEncodedSize;
}
/**
* Gets the minimum encoded size of the value stored in this VarInt
*/
public int getSizeInBytes() {
return sizeOf(value);
}
/**
* Gets the minimum encoded size of the given value.
*/
public static int sizeOf(int value) {
if (value < 253)
return 1;
else if (value < 65536)
return 3; // 1 marker + 2 data bytes
return 5; // 1 marker + 4 data bytes
}
/**
* Gets the minimum encoded size of the given value.
*/
public static int sizeOf(long value) {
if (isLessThanUnsigned(value, 253))
return 1;
else if (isLessThanOrEqualToUnsigned(value, 0xFFFFL))
return 3; // 1 marker + 2 data bytes
else if (isLessThanOrEqualToUnsigned(value, 0xFFFFFFFFL))
return 5; // 1 marker + 4 data bytes
else
return 9; // 1 marker + 8 data bytes
}
public byte[] encode() {
if (isLessThanUnsigned(value, 253)) {
return new byte[]{(byte) value};
} else if (isLessThanOrEqualToUnsigned(value, 0xFFFFL)) {
return new byte[]{(byte) 253, (byte) (value), (byte) (value >> 8)};
} else if (isLessThanOrEqualToUnsigned(value, 0xFFFFFFFFL)) {
byte[] bytes = new byte[5];
bytes[0] = (byte) 254;
Utils.uint32ToByteArrayLE(value, bytes, 1);
return bytes;
} else {
byte[] bytes = new byte[9];
bytes[0] = (byte) 255;
Utils.uint32ToByteArrayLE(value, bytes, 1);
Utils.uint32ToByteArrayLE(value >>> 32, bytes, 5);
return bytes;
}
}
}

View File

@ -1,76 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
@SuppressWarnings("serial")
public class VerificationException extends RuntimeException {
public VerificationException(String msg) {
super(msg);
}
public VerificationException(Exception e) {
super(e);
}
public VerificationException(String msg, Throwable t) {
super(msg, t);
}
public static class EmptyInputsOrOutputs extends VerificationException {
public EmptyInputsOrOutputs() {
super("Transaction had no inputs or no outputs.");
}
}
public static class LargerThanMaxBlockSize extends VerificationException {
public LargerThanMaxBlockSize() {
super("Transaction larger than MAX_BLOCK_SIZE");
}
}
public static class DuplicatedOutPoint extends VerificationException {
public DuplicatedOutPoint() {
super("Duplicated outpoint");
}
}
public static class NegativeValueOutput extends VerificationException {
public NegativeValueOutput() {
super("Transaction output negative");
}
}
public static class ExcessiveValue extends VerificationException {
public ExcessiveValue() {
super("Total transaction output value greater than possible");
}
}
public static class CoinbaseScriptSizeOutOfRange extends VerificationException {
public CoinbaseScriptSizeOutOfRange() {
super("Coinbase script size out of range");
}
}
public static class UnexpectedCoinbaseInput extends VerificationException {
public UnexpectedCoinbaseInput() {
super("Coinbase input as input in non-coinbase transaction");
}
}
}

View File

@ -1,30 +0,0 @@
/**
* Copyright 2011 Noa Resare.
*
* 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 com.dogecoin.dogecoinj.core;
/**
* The verack message, sent by a client accepting the version message they
* received from their peer.
*/
public class VersionAck extends EmptyMessage {
public VersionAck() {
}
// this is needed by the BitcoinSerializer
public VersionAck(NetworkParameters params, byte[] payload) {
}
}

View File

@ -1,318 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* A VersionMessage holds information exchanged during connection setup with another peer. Most of the fields are not
* particularly interesting. The subVer field, since BIP 14, acts as a User-Agent string would. You can and should
* append to or change the subVer for your own software so other implementations can identify it, and you can look at
* the subVer field received from other nodes to see what they are running. <p>
*
* After creating yourself a VersionMessage, you can pass it to {@link PeerGroup#setVersionMessage(VersionMessage)}
* to ensure it will be used for each new connection.
*/
public class VersionMessage extends Message {
private static final long serialVersionUID = 7313594258967483180L;
/** A services flag that denotes whether the peer has a copy of the block chain or not. */
public static final int NODE_NETWORK = 1;
/** A flag that denotes whether the peer supports the getutxos message or not. */
public static final int NODE_GETUTXOS = 2;
/**
* The version number of the protocol spoken.
*/
public int clientVersion;
/**
* Flags defining what optional services are supported.
*/
public long localServices;
/**
* What the other side believes the current time to be, in seconds.
*/
public long time;
/**
* What the other side believes the address of this program is. Not used.
*/
public PeerAddress myAddr;
/**
* What the other side believes their own address is. Not used.
*/
public PeerAddress theirAddr;
/**
* User-Agent as defined in <a href="https://github.com/bitcoin/bips/blob/master/bip-0014.mediawiki">BIP 14</a>.
* The official client sets it to something like "/Satoshi:0.9.1/".
*/
public String subVer;
/**
* How many blocks are in the chain, according to the other side.
*/
public long bestHeight;
/**
* Whether or not to relay tx invs before a filter is received.
* See <a href="https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#extensions-to-existing-messages">BIP 37</a>.
*/
public boolean relayTxesBeforeFilter;
/** The version of this library release, as a string. */
public static final String BITCOINJ_VERSION = "0.13-SNAPSHOT";
/** The value that is prepended to the subVer field of this application. */
public static final String LIBRARY_SUBVER = "/dogecoinj:" + BITCOINJ_VERSION + "/";
public VersionMessage(NetworkParameters params, byte[] payload) throws ProtocolException {
super(params, payload, 0);
}
// It doesn't really make sense to ever lazily parse a version message or to retain the backing bytes.
// If you're receiving this on the wire you need to check the protocol version and it will never need to be sent
// back down the wire.
public VersionMessage(NetworkParameters params, int newBestHeight) {
super(params);
clientVersion = NetworkParameters.PROTOCOL_VERSION;
localServices = 0;
time = System.currentTimeMillis() / 1000;
// Note that the official client doesn't do anything with these, and finding out your own external IP address
// is kind of tricky anyway, so we just put nonsense here for now.
try {
// We hard-code the IPv4 localhost address here rather than use InetAddress.getLocalHost() because some
// mobile phones have broken localhost DNS entries, also, this is faster.
final byte[] localhost = { 127, 0, 0, 1 };
myAddr = new PeerAddress(InetAddress.getByAddress(localhost), params.getPort(), 0);
theirAddr = new PeerAddress(InetAddress.getByAddress(localhost), params.getPort(), 0);
} catch (UnknownHostException e) {
throw new RuntimeException(e); // Cannot happen (illegal IP length).
}
subVer = LIBRARY_SUBVER;
bestHeight = newBestHeight;
relayTxesBeforeFilter = true;
length = 85;
if (protocolVersion > 31402)
length += 8;
length += VarInt.sizeOf(subVer.length()) + subVer.length();
}
@Override
protected void parseLite() throws ProtocolException {
// NOP. VersionMessage is never lazy parsed.
}
@Override
public void parse() throws ProtocolException {
if (parsed)
return;
parsed = true;
clientVersion = (int) readUint32();
localServices = readUint64().longValue();
time = readUint64().longValue();
myAddr = new PeerAddress(params, payload, cursor, 0);
cursor += myAddr.getMessageSize();
theirAddr = new PeerAddress(params, payload, cursor, 0);
cursor += theirAddr.getMessageSize();
// uint64 localHostNonce (random data)
// We don't care about the localhost nonce. It's used to detect connecting back to yourself in cases where
// there are NATs and proxies in the way. However we don't listen for inbound connections so it's irrelevant.
readUint64();
try {
// Initialize default values for flags which may not be sent by old nodes
subVer = "";
bestHeight = 0;
relayTxesBeforeFilter = true;
if (!hasMoreBytes())
return;
// string subVer (currently "")
subVer = readStr();
if (!hasMoreBytes())
return;
// int bestHeight (size of known block chain).
bestHeight = readUint32();
if (!hasMoreBytes())
return;
relayTxesBeforeFilter = readBytes(1)[0] != 0;
} finally {
length = cursor - offset;
}
}
@Override
public void bitcoinSerializeToStream(OutputStream buf) throws IOException {
Utils.uint32ToByteStreamLE(clientVersion, buf);
Utils.uint32ToByteStreamLE(localServices, buf);
Utils.uint32ToByteStreamLE(localServices >> 32, buf);
Utils.uint32ToByteStreamLE(time, buf);
Utils.uint32ToByteStreamLE(time >> 32, buf);
try {
// My address.
myAddr.bitcoinSerialize(buf);
// Their address.
theirAddr.bitcoinSerialize(buf);
} catch (UnknownHostException e) {
throw new RuntimeException(e); // Can't happen.
} catch (IOException e) {
throw new RuntimeException(e); // Can't happen.
}
// Next up is the "local host nonce", this is to detect the case of connecting
// back to yourself. We don't care about this as we won't be accepting inbound
// connections.
Utils.uint32ToByteStreamLE(0, buf);
Utils.uint32ToByteStreamLE(0, buf);
// Now comes subVer.
byte[] subVerBytes = subVer.getBytes("UTF-8");
buf.write(new VarInt(subVerBytes.length).encode());
buf.write(subVerBytes);
// Size of known block chain.
Utils.uint32ToByteStreamLE(bestHeight, buf);
buf.write(relayTxesBeforeFilter ? 1 : 0);
}
/**
* Returns true if the version message indicates the sender has a full copy of the block chain,
* or if it's running in client mode (only has the headers).
*/
public boolean hasBlockChain() {
return (localServices & NODE_NETWORK) == NODE_NETWORK;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
VersionMessage other = (VersionMessage) o;
return other.bestHeight == bestHeight &&
other.clientVersion == clientVersion &&
other.localServices == localServices &&
other.time == time &&
other.subVer.equals(subVer) &&
other.myAddr.equals(myAddr) &&
other.theirAddr.equals(theirAddr) &&
other.relayTxesBeforeFilter == relayTxesBeforeFilter;
}
@Override
public int hashCode() {
return (int) bestHeight ^ clientVersion ^ (int) localServices ^ (int) time ^ subVer.hashCode() ^ myAddr.hashCode()
^ theirAddr.hashCode() * (relayTxesBeforeFilter ? 1 : 2);
}
/**
* VersionMessage does not handle cached byte array so should not have a cached checksum.
*/
@Override
byte[] getChecksum() {
throw new UnsupportedOperationException();
}
/**
* VersionMessage does not handle cached byte array so should not have a cached checksum.
*/
@Override
void setChecksum(byte[] checksum) {
throw new UnsupportedOperationException();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("\n");
sb.append("client version: ").append(clientVersion).append("\n");
sb.append("local services: ").append(localServices).append("\n");
sb.append("time: ").append(time).append("\n");
sb.append("my addr: ").append(myAddr).append("\n");
sb.append("their addr: ").append(theirAddr).append("\n");
sb.append("sub version: ").append(subVer).append("\n");
sb.append("best height: ").append(bestHeight).append("\n");
sb.append("delay tx relay: ").append(!relayTxesBeforeFilter).append("\n");
return sb.toString();
}
public VersionMessage duplicate() {
VersionMessage v = new VersionMessage(params, (int) bestHeight);
v.clientVersion = clientVersion;
v.localServices = localServices;
v.time = time;
v.myAddr = myAddr;
v.theirAddr = theirAddr;
v.subVer = subVer;
v.relayTxesBeforeFilter = relayTxesBeforeFilter;
return v;
}
/**
* Appends the given user-agent information to the subVer field. The subVer is composed of a series of
* name:version pairs separated by slashes in the form of a path. For example a typical subVer field for BitCoinJ
* users might look like "/BitCoinJ:0.4-SNAPSHOT/MultiBit:1.2/" where libraries come further to the left.<p>
*
* There can be as many components as you feel a need for, and the version string can be anything, but it is
* recommended to use A.B.C where A = major, B = minor and C = revision for software releases, and dates for
* auto-generated source repository snapshots. A valid subVer begins and ends with a slash, therefore name
* and version are not allowed to contain such characters. <p>
*
* Anything put in the "comments" field will appear in brackets and may be used for platform info, or anything
* else. For example, calling <tt>appendToSubVer("MultiBit", "1.0", "Windows")</tt> will result in a subVer being
* set of "/BitCoinJ:1.0/MultiBit:1.0(Windows)/". Therefore the / ( and ) characters are reserved in all these
* components. If you don't want to add a comment (recommended), pass null.<p>
*
* See <a href="https://github.com/bitcoin/bips/blob/master/bip-0014.mediawiki">BIP 14</a> for more information.
*
* @param comments Optional (can be null) platform or other node specific information.
* @throws IllegalArgumentException if name, version or comments contains invalid characters.
*/
public void appendToSubVer(String name, String version, @Nullable String comments) {
checkSubVerComponent(name);
checkSubVerComponent(version);
if (comments != null) {
checkSubVerComponent(comments);
subVer = subVer.concat(String.format("%s:%s(%s)/", name, version, comments));
} else {
subVer = subVer.concat(String.format("%s:%s/", name, version));
}
}
private static void checkSubVerComponent(String component) {
if (component.contains("/") || component.contains("(") || component.contains(")"))
throw new IllegalArgumentException("name contains invalid characters");
}
/**
* Returns true if the clientVersion field is >= Pong.MIN_PROTOCOL_VERSION. If it is then ping() is usable.
*/
public boolean isPingPongSupported() {
return clientVersion >= Pong.MIN_PROTOCOL_VERSION;
}
/**
* Returns true if the clientVersion field is >= FilteredBlock.MIN_PROTOCOL_VERSION. If it is then Bloom filtering
* is available and the memory pool of the remote peer will be queried when the downloadData property is true.
*/
public boolean isBloomFilteringSupported() {
return clientVersion >= FilteredBlock.MIN_PROTOCOL_VERSION;
}
/** Returns true if the protocol version and service bits both indicate support for the getutxos message. */
public boolean isGetUTXOsSupported() {
return clientVersion >= GetUTXOsMessage.MIN_PROTOCOL_VERSION &&
(localServices & NODE_GETUTXOS) == NODE_GETUTXOS;
}
}

View File

@ -1,120 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import static com.google.common.base.Preconditions.checkArgument;
import java.io.Serializable;
import java.util.Arrays;
import com.google.common.base.Objects;
import com.google.common.primitives.UnsignedBytes;
/**
* <p>In Bitcoin the following format is often used to represent some type of key:</p>
* <p/>
* <pre>[one version byte] [data bytes] [4 checksum bytes]</pre>
* <p/>
* <p>and the result is then Base58 encoded. This format is used for addresses, and private keys exported using the
* dumpprivkey command.</p>
*/
public class VersionedChecksummedBytes implements Serializable, Cloneable, Comparable<VersionedChecksummedBytes> {
protected final int version;
protected byte[] bytes;
protected VersionedChecksummedBytes(String encoded) throws AddressFormatException {
byte[] versionAndDataBytes = Base58.decodeChecked(encoded);
byte versionByte = versionAndDataBytes[0];
version = versionByte & 0xFF;
bytes = new byte[versionAndDataBytes.length - 1];
System.arraycopy(versionAndDataBytes, 1, bytes, 0, versionAndDataBytes.length - 1);
}
protected VersionedChecksummedBytes(int version, byte[] bytes) {
checkArgument(version >= 0 && version < 256);
this.version = version;
this.bytes = bytes;
}
/**
* Returns the base-58 encoded String representation of this
* object, including version and checksum bytes.
*/
@Override
public String toString() {
// A stringified buffer is:
// 1 byte version + data bytes + 4 bytes check code (a truncated hash)
byte[] addressBytes = new byte[1 + bytes.length + 4];
addressBytes[0] = (byte) version;
System.arraycopy(bytes, 0, addressBytes, 1, bytes.length);
byte[] checksum = Utils.doubleDigest(addressBytes, 0, bytes.length + 1);
System.arraycopy(checksum, 0, addressBytes, bytes.length + 1, 4);
return Base58.encode(addressBytes);
}
@Override
public int hashCode() {
return Objects.hashCode(version, Arrays.hashCode(bytes));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
VersionedChecksummedBytes other = (VersionedChecksummedBytes) o;
return this.version == other.version
&& Arrays.equals(this.bytes, other.bytes);
}
/**
* {@inheritDoc}
*
* This implementation narrows the return type to <code>VersionedChecksummedBytes</code>
* and allows subclasses to throw <code>CloneNotSupportedException</code> even though it
* is never thrown by this implementation.
*/
@Override
public VersionedChecksummedBytes clone() throws CloneNotSupportedException {
return (VersionedChecksummedBytes) super.clone();
}
/**
* {@inheritDoc}
*
* This implementation uses an optimized Google Guava method to compare <code>bytes</code>.
*/
@Override
public int compareTo(VersionedChecksummedBytes o) {
int versionCompare = Integer.valueOf(this.version).compareTo(Integer.valueOf(o.version)); // JDK 6 way
if (versionCompare == 0) {
// Would there be a performance benefit to caching the comparator?
return UnsignedBytes.lexicographicalComparator().compare(this.bytes, o.bytes);
} else {
return versionCompare;
}
}
/**
* Returns the "version" or "header" byte: the first byte of the data. This is used to disambiguate what the
* contents apply to, for example, which network the key or address is valid on.
*
* @return A positive number between 0 and 255.
*/
public int getVersion() {
return version;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,126 +0,0 @@
/**
* Copyright 2013 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import com.dogecoin.dogecoinj.script.Script;
import com.dogecoin.dogecoinj.wallet.KeyChainEventListener;
import java.util.List;
/**
* <p>Implementors are called when the contents of the wallet changes, for instance due to receiving/sending money
* or a block chain re-organize. It may be convenient to derive from {@link AbstractWalletEventListener} instead.</p>
*/
public interface WalletEventListener extends KeyChainEventListener {
/**
* This is called when a transaction is seen that sends coins <b>to</b> this wallet, either because it
* was broadcast across the network or because a block was received. If a transaction is seen when it was broadcast,
* onCoinsReceived won't be called again when a block containing it is received. If you want to know when such a
* transaction receives its first confirmation, register a {@link TransactionConfidence} event listener using
* the object retrieved via {@link com.dogecoin.dogecoinj.core.Transaction#getConfidence()}. It's safe to modify the
* wallet in this callback, for example, by spending the transaction just received.
*
* @param wallet The wallet object that received the coins
* @param tx The transaction which sent us the coins.
* @param prevBalance Balance before the coins were received.
* @param newBalance Current balance of the wallet. This is the 'estimated' balance.
*/
void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance);
/**
* This is called when a transaction is seen that sends coins <b>from</b> this wallet, either
* because it was broadcast across the network or because a block was received. This may at first glance seem
* useless, because in the common case you already know about such transactions because you created them with
* the Wallets createSend/sendCoins methods. However when you have a wallet containing only keys, and you wish
* to replay the block chain to fill it with transactions, it's useful to find out when a transaction is discovered
* that sends coins from the wallet.<p>
*
* It's safe to modify the wallet from inside this callback, but if you're replaying the block chain you should
* be careful to avoid such modifications. Otherwise your changes may be overridden by new data from the chain.
*
* @param wallet The wallet object that this callback relates to (that sent the coins).
* @param tx The transaction that sent the coins to someone else.
* @param prevBalance The wallets balance before this transaction was seen.
* @param newBalance The wallets balance after this transaction was seen. This is the 'estimated' balance.
*/
void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance);
// TODO: Finish onReorganize to be more useful.
/**
* <p>This is called when a block is received that triggers a block chain re-organization.</p>
*
* <p>A re-organize means that the consensus (chain) of the network has diverged and now changed from what we
* believed it was previously. Usually this won't matter because the new consensus will include all our old
* transactions assuming we are playing by the rules. However it's theoretically possible for our balance to
* change in arbitrary ways, most likely, we could lose some money we thought we had.</p>
*
* <p>It is safe to use methods of wallet whilst inside this callback.</p>
*/
void onReorganize(Wallet wallet);
/**
* <p>Called when a transaction changes its confidence level. You can also attach event listeners to
* the individual transactions, if you don't care about all of them. Usually you would save the wallet to disk after
* receiving this callback unless you already set up autosaving.</p>
*
* <p>You should pay attention to this callback in case a transaction becomes <i>dead</i>, that is, a transaction
* you believed to be active (send or receive) becomes overridden by the network. This can happen if</p>
*
* <ol>
* <li>You are sharing keys between wallets and accidentally create/broadcast a double spend.</li>
* <li>Somebody is attacking the network and reversing transactions, ie, the user is a victim of fraud.</li>
* <li>A bug: for example you create a transaction, broadcast it but fail to commit it. The {@link Wallet}
* will then re-use the same outputs when creating the next spend.</li>
* </ol><p>
*
* <p>To find if the transaction is dead, you can use <tt>tx.getConfidence().getConfidenceType() ==
* TransactionConfidence.ConfidenceType.DEAD</tt>. If it is, you should notify the user
* in some way so they know the thing they bought may not arrive/the thing they sold should not be dispatched.</p>
*
* <p>Note that this callback will be invoked for every transaction in the wallet, for every new block that is
* received (because the depth has changed). <b>If you want to update a UI view from the contents of the wallet
* it is more efficient to use onWalletChanged instead.</b></p>
*/
void onTransactionConfidenceChanged(Wallet wallet, Transaction tx);
/**
* <p>Designed for GUI applications to refresh their transaction lists. This callback is invoked in the following
* situations:</p>
*
* <ol>
* <li>A new block is received (and thus building transactions got more confidence)</li>
* <li>A pending transaction is received</li>
* <li>A pending transaction changes confidence due to some non-new-block related event, such as being
* announced by more peers or by a double-spend conflict being observed.</li>
* <li>A re-organize occurs. Call occurs only if the re-org modified any of our transactions.</li>
* <li>A new spend is committed to the wallet.</li>
* <li>The wallet is reset and all transactions removed.<li>
* </ol>
*
* <p>When this is called you can refresh the UI contents from the wallet contents. It's more efficient to use
* this rather than onTransactionConfidenceChanged() + onReorganize() because you only get one callback per block
* rather than one per transaction per block. Note that this is <b>not</b> called when a key is added. </p>
*/
void onWalletChanged(Wallet wallet);
/**
* Called whenever a new watched script is added to the wallet.
*
* @param isAddingScripts will be true if added scripts, false if removed scripts.
*/
void onScriptsChanged(Wallet wallet, List<Script> scripts, boolean isAddingScripts);
}

View File

@ -1,44 +0,0 @@
/*
* Copyright 2013 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
/**
* <p>An object implementing this interface can be added to a {@link Wallet} and provide arbitrary byte arrays that will
* be serialized alongside the wallet. Extensions can be mandatory, in which case applications that don't know how to
* read the given data will refuse to load the wallet at all. Extensions identify themselves with a string ID that
* should use a Java-style reverse DNS identifier to avoid being mixed up with other kinds of extension. To use an
* extension, add an object that implements this interface to the wallet using {@link Wallet#addExtension(WalletExtension)}
* before you load it (to read existing data) and ensure it's present when the wallet is save (to write the data).</p>
*
* <p>Note that extensions are singletons - you cannot add two objects that provide the same ID to the same wallet.</p>
*/
public interface WalletExtension {
/** Returns a Java package/class style name used to disambiguate this extension from others. */
public String getWalletExtensionID();
/**
* If this returns true, the mandatory flag is set when the wallet is serialized and attempts to load it without
* the extension being in the wallet will throw an exception. This method should not change its result during
* the objects lifetime.
*/
public boolean isWalletExtensionMandatory();
/** Returns bytes that will be saved in the wallet. */
public byte[] serializeWalletExtension();
/** Loads the contents of this object from the wallet. */
public void deserializeWalletExtension(Wallet containingWallet, byte[] data) throws Exception;
}

View File

@ -1,38 +0,0 @@
/*
* Copyright 2012 Google Inc.
*
* 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 com.dogecoin.dogecoinj.core;
import java.util.Arrays;
/**
* This exception is thrown by the Address class when you try and decode an address with a version code that isn't
* used by that network. You shouldn't allow the user to proceed in this case as they are trying to send money across
* different chains, an operation that is guaranteed to destroy the money.
*/
public class WrongNetworkException extends AddressFormatException {
/** The version code that was provided in the address. */
public int verCode;
/** The list of acceptable versions that were expected given the addresses network parameters. */
public int[] acceptableVersions;
public WrongNetworkException(int verCode, int[] acceptableVersions) {
super("Version code of address did not match acceptable versions for network: " + verCode + " not in " +
Arrays.toString(acceptableVersions));
this.verCode = verCode;
this.acceptableVersions = acceptableVersions;
}
}

View File

@ -1,8 +0,0 @@
/**
* The core package contains classes for network messages like {@link com.dogecoin.dogecoinj.core.Block} and
* {@link com.dogecoin.dogecoinj.core.Transaction}, peer connectivity via {@link com.dogecoin.dogecoinj.core.PeerGroup},
* block chain management and the {@link com.dogecoin.dogecoinj.core.Wallet} class.
* If what you're doing can be described as basic bitcoin tasks, the code is probably found here.
* To learn more please consult the documentation on the website.
*/
package com.dogecoin.dogecoinj.core;

View File

@ -1,178 +0,0 @@
/*
* Copyright 2014 Andreas Schildbach
*
* 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 com.dogecoin.dogecoinj.crypto;
import com.dogecoin.dogecoinj.core.*;
import com.google.common.base.Charsets;
import com.google.common.base.Objects;
import com.google.common.primitives.Bytes;
import com.lambdaworks.crypto.SCrypt;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.text.Normalizer;
import java.util.Arrays;
import static com.google.common.base.Preconditions.checkState;
/**
* Implementation of <a href="https://github.com/bitcoin/bips/blob/master/bip-0038.mediawiki">BIP 38</a>
* passphrase-protected private keys. Currently, only decryption is supported.
*/
public class BIP38PrivateKey extends VersionedChecksummedBytes {
public final NetworkParameters params;
public final boolean ecMultiply;
public final boolean compressed;
public final boolean hasLotAndSequence;
public final byte[] addressHash;
public final byte[] content;
public static final class BadPassphraseException extends Exception {
}
public BIP38PrivateKey(NetworkParameters params, String encoded) throws AddressFormatException {
super(encoded);
this.params = params;
if (version != 0x01)
throw new AddressFormatException("Mismatched version number: " + version);
if (bytes.length != 38)
throw new AddressFormatException("Wrong number of bytes, excluding version byte: " + bytes.length);
hasLotAndSequence = (bytes[1] & 0x04) != 0; // bit 2
compressed = (bytes[1] & 0x20) != 0; // bit 5
if ((bytes[1] & 0x01) != 0) // bit 0
throw new AddressFormatException("Bit 0x01 reserved for future use.");
if ((bytes[1] & 0x02) != 0) // bit 1
throw new AddressFormatException("Bit 0x02 reserved for future use.");
if ((bytes[1] & 0x08) != 0) // bit 3
throw new AddressFormatException("Bit 0x08 reserved for future use.");
if ((bytes[1] & 0x10) != 0) // bit 4
throw new AddressFormatException("Bit 0x10 reserved for future use.");
final int byte0 = bytes[0] & 0xff;
if (byte0 == 0x42) {
// Non-EC-multiplied key
if ((bytes[1] & 0xc0) != 0xc0) // bits 6+7
throw new AddressFormatException("Bits 0x40 and 0x80 must be set for non-EC-multiplied keys.");
ecMultiply = false;
if (hasLotAndSequence)
throw new AddressFormatException("Non-EC-multiplied keys cannot have lot/sequence.");
} else if (byte0 == 0x43) {
// EC-multiplied key
if ((bytes[1] & 0xc0) != 0x00) // bits 6+7
throw new AddressFormatException("Bits 0x40 and 0x80 must be cleared for EC-multiplied keys.");
ecMultiply = true;
} else {
throw new AddressFormatException("Second byte must by 0x42 or 0x43.");
}
addressHash = Arrays.copyOfRange(bytes, 2, 6);
content = Arrays.copyOfRange(bytes, 6, 38);
}
public ECKey decrypt(String passphrase) throws BadPassphraseException {
String normalizedPassphrase = Normalizer.normalize(passphrase, Normalizer.Form.NFC);
ECKey key = ecMultiply ? decryptEC(normalizedPassphrase) : decryptNoEC(normalizedPassphrase);
Sha256Hash hash = Sha256Hash.createDouble(key.toAddress(params).toString().getBytes(Charsets.US_ASCII));
byte[] actualAddressHash = Arrays.copyOfRange(hash.getBytes(), 0, 4);
if (!Arrays.equals(actualAddressHash, addressHash))
throw new BadPassphraseException();
return key;
}
private ECKey decryptNoEC(String normalizedPassphrase) {
try {
byte[] derived = SCrypt.scrypt(normalizedPassphrase.getBytes(Charsets.UTF_8), addressHash, 16384, 8, 8, 64);
byte[] key = Arrays.copyOfRange(derived, 32, 64);
SecretKeySpec keyspec = new SecretKeySpec(key, "AES");
DRMWorkaround.maybeDisableExportControls();
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, keyspec);
byte[] decrypted = cipher.doFinal(content, 0, 32);
for (int i = 0; i < 32; i++)
decrypted[i] ^= derived[i];
return ECKey.fromPrivate(decrypted, compressed);
} catch (GeneralSecurityException x) {
throw new RuntimeException(x);
}
}
private ECKey decryptEC(String normalizedPassphrase) {
try {
byte[] ownerEntropy = Arrays.copyOfRange(content, 0, 8);
byte[] ownerSalt = hasLotAndSequence ? Arrays.copyOfRange(ownerEntropy, 0, 4) : ownerEntropy;
byte[] passFactorBytes = SCrypt.scrypt(normalizedPassphrase.getBytes(Charsets.UTF_8), ownerSalt, 16384, 8, 8, 32);
if (hasLotAndSequence) {
byte[] hashBytes = Bytes.concat(passFactorBytes, ownerEntropy);
checkState(hashBytes.length == 40);
passFactorBytes = Sha256Hash.createDouble(hashBytes).getBytes();
}
BigInteger passFactor = new BigInteger(1, passFactorBytes);
ECKey k = ECKey.fromPrivate(passFactor, true);
byte[] salt = Bytes.concat(addressHash, ownerEntropy);
checkState(salt.length == 12);
byte[] derived = SCrypt.scrypt(k.getPubKey(), salt, 1024, 1, 1, 64);
byte[] aeskey = Arrays.copyOfRange(derived, 32, 64);
SecretKeySpec keyspec = new SecretKeySpec(aeskey, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, keyspec);
byte[] encrypted2 = Arrays.copyOfRange(content, 16, 32);
byte[] decrypted2 = cipher.doFinal(encrypted2);
checkState(decrypted2.length == 16);
for (int i = 0; i < 16; i++)
decrypted2[i] ^= derived[i + 16];
byte[] encrypted1 = Bytes.concat(Arrays.copyOfRange(content, 8, 16), Arrays.copyOfRange(decrypted2, 0, 8));
byte[] decrypted1 = cipher.doFinal(encrypted1);
checkState(decrypted1.length == 16);
for (int i = 0; i < 16; i++)
decrypted1[i] ^= derived[i];
byte[] seed = Bytes.concat(decrypted1, Arrays.copyOfRange(decrypted2, 8, 16));
checkState(seed.length == 24);
BigInteger seedFactor = new BigInteger(1, Sha256Hash.createDouble(seed).getBytes());
checkState(passFactor.signum() >= 0);
checkState(seedFactor.signum() >= 0);
BigInteger priv = passFactor.multiply(seedFactor).mod(ECKey.CURVE.getN());
return ECKey.fromPrivate(priv, compressed);
} catch (GeneralSecurityException x) {
throw new RuntimeException(x);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BIP38PrivateKey other = (BIP38PrivateKey) o;
return super.equals(other)
&& Objects.equal(this.params, other.params);
}
@Override
public int hashCode() {
return Objects.hashCode(super.hashCode(), params);
}
}

View File

@ -1,89 +0,0 @@
/**
* Copyright 2013 Matija Mazi.
*
* 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 com.dogecoin.dogecoinj.crypto;
/**
* <p>This is just a wrapper for the i (child number) as per BIP 32 with a boolean getter for the most significant bit
* and a getter for the actual 0-based child number. A {@link List} of these forms a <i>path</i> through a
* {@link DeterministicHierarchy}. This class is immutable.
*/
public class ChildNumber {
/**
* The bit that's set in the child number to indicate whether this key is "hardened". Given a hardened key, it is
* not possible to derive a child public key if you know only the hardened public key. With a non-hardened key this
* is possible, so you can derive trees of public keys given only a public parent, but the downside is that it's
* possible to leak private keys if you disclose a parent public key and a child private key (elliptic curve maths
* allows you to work upwards).
*/
public static final int HARDENED_BIT = 0x80000000;
public static final ChildNumber ZERO = new ChildNumber(0);
public static final ChildNumber ONE = new ChildNumber(1);
public static final ChildNumber ZERO_HARDENED = new ChildNumber(0, true);
/** Integer i as per BIP 32 spec, including the MSB denoting derivation type (0 = public, 1 = private) **/
private final int i;
public ChildNumber(int childNumber, boolean isHardened) {
if (hasHardenedBit(childNumber))
throw new IllegalArgumentException("Most significant bit is reserved and shouldn't be set: " + childNumber);
i = isHardened ? (childNumber | HARDENED_BIT) : childNumber;
}
public ChildNumber(int i) {
this.i = i;
}
/** Returns the uint32 encoded form of the path element, including the most significant bit. */
public int getI() {
return i;
}
/** Returns the uint32 encoded form of the path element, including the most significant bit. */
public int i() { return i; }
public boolean isHardened() {
return hasHardenedBit(i);
}
private static boolean hasHardenedBit(int a) {
return (a & HARDENED_BIT) != 0;
}
/** Returns the child number without the hardening bit set (i.e. index in that part of the tree). */
public int num() {
return i & (~HARDENED_BIT);
}
@Override
public String toString() {
return String.format("%d%s", num(), isHardened() ? "H" : "");
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ChildNumber other = (ChildNumber) o;
return i == other.i;
}
@Override
public int hashCode() {
return i;
}
}

View File

@ -1,47 +0,0 @@
package com.dogecoin.dogecoinj.crypto;
import com.dogecoin.dogecoinj.core.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class DRMWorkaround {
private static Logger log = LoggerFactory.getLogger(DRMWorkaround.class);
private static boolean done = false;
public static void maybeDisableExportControls() {
// This sorry story is documented in https://bugs.openjdk.java.net/browse/JDK-7024850
// Oracle received permission to ship AES-256 by default in 2011, but didn't get around to it for Java 8
// even though that shipped in 2014! That's dumb. So we disable the ridiculous US government mandated DRM
// for AES-256 here, as Tor/BIP38 requires it.
if (done) return;
done = true;
if (Utils.isAndroidRuntime())
return;
try {
Field gate = Class.forName("javax.crypto.JceSecurity").getDeclaredField("isRestricted");
gate.setAccessible(true);
gate.setBoolean(null, false);
final Field allPerm = Class.forName("javax.crypto.CryptoAllPermission").getDeclaredField("INSTANCE");
allPerm.setAccessible(true);
Object accessAllAreasCard = allPerm.get(null);
final Constructor<?> constructor = Class.forName("javax.crypto.CryptoPermissions").getDeclaredConstructor();
constructor.setAccessible(true);
Object coll = constructor.newInstance();
Method addPerm = Class.forName("javax.crypto.CryptoPermissions").getDeclaredMethod("add", java.security.Permission.class);
addPerm.setAccessible(true);
addPerm.invoke(coll, accessAllAreasCard);
Field defaultPolicy = Class.forName("javax.crypto.JceSecurity").getDeclaredField("defaultPolicy");
defaultPolicy.setAccessible(true);
defaultPolicy.set(null, coll);
} catch (Exception e) {
log.warn("Failed to deactivate AES-256 barrier logic, Tor mode/BIP38 decryption may crash if this JVM requires it: " + e.getMessage());
}
}
}

View File

@ -1,162 +0,0 @@
/**
* Copyright 2013 Matija Mazi.
*
* 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 com.dogecoin.dogecoinj.crypto;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import static com.google.common.base.Preconditions.checkArgument;
// TODO: This whole API feels a bit object heavy. Do we really need ChildNumber and so many maps, etc?
// TODO: Should we be representing this using an actual tree arrangement in memory instead of a bunch of hashmaps?
/**
* <p>A DeterministicHierarchy calculates and keeps a whole tree (hierarchy) of keys originating from a single
* root key. This implements part of the BIP 32 specification. A deterministic key tree is useful because
* Bitcoin's privacy system require new keys to be created for each transaction, but managing all these
* keys quickly becomes unwieldy. In particular it becomes hard to back up and distribute them. By having
* a way to derive random-looking but deterministic keys we can make wallet backup simpler and gain the
* ability to hand out {@link DeterministicKey}s to other people who can then create new addresses
* on the fly, without having to contact us.</p>
*
* <p>The hierarchy is started from a single root key, and a location in the tree is given by a path which
* is a list of {@link ChildNumber}s.</p>
*/
public class DeterministicHierarchy implements Serializable {
private final Map<ImmutableList<ChildNumber>, DeterministicKey> keys = Maps.newHashMap();
private final ImmutableList<ChildNumber> rootPath;
// Keep track of how many child keys each node has. This is kind of weak.
private final Map<ImmutableList<ChildNumber>, ChildNumber> lastChildNumbers = Maps.newHashMap();
public static final int BIP32_STANDARDISATION_TIME_SECS = 1369267200;
/**
* Constructs a new hierarchy rooted at the given key. Note that this does not have to be the top of the tree.
* You can construct a DeterministicHierarchy for a subtree of a larger tree that you may not own.
*/
public DeterministicHierarchy(DeterministicKey rootKey) {
putKey(rootKey);
rootPath = rootKey.getPath();
}
/**
* Inserts a key into the heirarchy. Used during deserialization: you normally don't need this. Keys must be
* inserted in order.
*/
public void putKey(DeterministicKey key) {
ImmutableList<ChildNumber> path = key.getPath();
// Update our tracking of what the next child in each branch of the tree should be. Just assume that keys are
// inserted in order here.
final DeterministicKey parent = key.getParent();
if (parent != null)
lastChildNumbers.put(parent.getPath(), key.getChildNumber());
keys.put(path, key);
}
/**
* Returns a key for the given path, optionally creating it.
*
* @param path the path to the key
* @param relativePath whether the path is relative to the root path
* @param create whether the key corresponding to path should be created (with any necessary ancestors) if it doesn't exist already
* @return next newly created key using the child derivation function
* @throws IllegalArgumentException if create is false and the path was not found.
*/
public DeterministicKey get(List<ChildNumber> path, boolean relativePath, boolean create) {
ImmutableList<ChildNumber> absolutePath = relativePath
? ImmutableList.<ChildNumber>builder().addAll(rootPath).addAll(path).build()
: ImmutableList.copyOf(path);
if (!keys.containsKey(absolutePath)) {
if (!create)
throw new IllegalArgumentException(String.format("No key found for %s path %s.",
relativePath ? "relative" : "absolute", HDUtils.formatPath(path)));
checkArgument(absolutePath.size() > 0, "Can't derive the master key: nothing to derive from.");
DeterministicKey parent = get(absolutePath.subList(0, absolutePath.size() - 1), false, true);
putKey(HDKeyDerivation.deriveChildKey(parent, absolutePath.get(absolutePath.size() - 1)));
}
return keys.get(absolutePath);
}
/**
* Extends the tree by calculating the next key that hangs off the given parent path. For example, if you pass a
* path of 1/2 here and there are already keys 1/2/1 and 1/2/2 then it will derive 1/2/3.
*
* @param parentPath the path to the parent
* @param relative whether the path is relative to the root path
* @param createParent whether the parent corresponding to path should be created (with any necessary ancestors) if it doesn't exist already
* @param privateDerivation whether to use private or public derivation
* @return next newly created key using the child derivation funtcion
* @throws IllegalArgumentException if the parent doesn't exist and createParent is false.
*/
public DeterministicKey deriveNextChild(ImmutableList<ChildNumber> parentPath, boolean relative, boolean createParent, boolean privateDerivation) {
DeterministicKey parent = get(parentPath, relative, createParent);
int nAttempts = 0;
while (nAttempts++ < HDKeyDerivation.MAX_CHILD_DERIVATION_ATTEMPTS) {
try {
ChildNumber createChildNumber = getNextChildNumberToDerive(parent.getPath(), privateDerivation);
return deriveChild(parent, createChildNumber);
} catch (HDDerivationException ignore) { }
}
throw new HDDerivationException("Maximum number of child derivation attempts reached, this is probably an indication of a bug.");
}
private ChildNumber getNextChildNumberToDerive(ImmutableList<ChildNumber> path, boolean privateDerivation) {
ChildNumber lastChildNumber = lastChildNumbers.get(path);
ChildNumber nextChildNumber = new ChildNumber(lastChildNumber != null ? lastChildNumber.num() + 1 : 0, privateDerivation);
lastChildNumbers.put(path, nextChildNumber);
return nextChildNumber;
}
public int getNumChildren(ImmutableList<ChildNumber> path) {
final ChildNumber cn = lastChildNumbers.get(path);
if (cn == null)
return 0;
else
return cn.num() + 1; // children start with zero based childnumbers
}
/**
* Extends the tree by calculating the requested child for the given path. For example, to get the key at position
* 1/2/3 you would pass 1/2 as the parent path and 3 as the child number.
*
* @param parentPath the path to the parent
* @param relative whether the path is relative to the root path
* @param createParent whether the parent corresponding to path should be created (with any necessary ancestors) if it doesn't exist already
* @return the requested key.
* @throws IllegalArgumentException if the parent doesn't exist and createParent is false.
*/
public DeterministicKey deriveChild(List<ChildNumber> parentPath, boolean relative, boolean createParent, ChildNumber createChildNumber) {
return deriveChild(get(parentPath, relative, createParent), createChildNumber);
}
private DeterministicKey deriveChild(DeterministicKey parent, ChildNumber createChildNumber) {
DeterministicKey childKey = HDKeyDerivation.deriveChildKey(parent, createChildNumber);
putKey(childKey);
return childKey;
}
/**
* Returns the root key that the {@link DeterministicHierarchy} was created with.
*/
public DeterministicKey getRootKey() {
return get(rootPath, false, false);
}
}

View File

@ -1,510 +0,0 @@
/**
* Copyright 2013 Matija Mazi.
* Copyright 2014 Andreas Schildbach
*
* 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 com.dogecoin.dogecoinj.crypto;
import com.dogecoin.dogecoinj.core.*;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.collect.ImmutableList;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.math.ec.ECPoint;
import javax.annotation.Nullable;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.Arrays;
import static com.dogecoin.dogecoinj.core.Utils.HEX;
import static com.google.common.base.Preconditions.*;
/**
* A deterministic key is a node in a {@link DeterministicHierarchy}. As per
* <a href="https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki">the BIP 32 specification</a> it is a pair
* (key, chaincode). If you know its path in the tree and its chain code you can derive more keys from this. To obtain
* one of these, you can call {@link HDKeyDerivation#createMasterPrivateKey(byte[])}.
*/
public class DeterministicKey extends ECKey {
private static final long serialVersionUID = 1L;
private final DeterministicKey parent;
private final ImmutableList<ChildNumber> childNumberPath;
/** 32 bytes */
private final byte[] chainCode;
/** Constructs a key from its components. This is not normally something you should use. */
public DeterministicKey(ImmutableList<ChildNumber> childNumberPath,
byte[] chainCode,
LazyECPoint publicAsPoint,
@Nullable BigInteger priv,
@Nullable DeterministicKey parent) {
super(priv, compressPoint(checkNotNull(publicAsPoint)));
checkArgument(chainCode.length == 32);
this.parent = parent;
this.childNumberPath = checkNotNull(childNumberPath);
this.chainCode = Arrays.copyOf(chainCode, chainCode.length);
}
public DeterministicKey(ImmutableList<ChildNumber> childNumberPath,
byte[] chainCode,
ECPoint publicAsPoint,
@Nullable BigInteger priv,
@Nullable DeterministicKey parent) {
this(childNumberPath, chainCode, new LazyECPoint(publicAsPoint), priv, parent);
}
/** Constructs a key from its components. This is not normally something you should use. */
public DeterministicKey(ImmutableList<ChildNumber> childNumberPath,
byte[] chainCode,
BigInteger priv,
@Nullable DeterministicKey parent) {
super(priv, compressPoint(ECKey.CURVE.getG().multiply(priv)));
checkArgument(chainCode.length == 32);
this.parent = parent;
this.childNumberPath = checkNotNull(childNumberPath);
this.chainCode = Arrays.copyOf(chainCode, chainCode.length);
}
/** Constructs a key from its components. This is not normally something you should use. */
public DeterministicKey(ImmutableList<ChildNumber> childNumberPath,
byte[] chainCode,
KeyCrypter crypter,
LazyECPoint pub,
EncryptedData priv,
@Nullable DeterministicKey parent) {
this(childNumberPath, chainCode, pub, null, parent);
this.encryptedPrivateKey = checkNotNull(priv);
this.keyCrypter = checkNotNull(crypter);
}
/** Clones the key */
public DeterministicKey(DeterministicKey keyToClone, DeterministicKey newParent) {
super(keyToClone.priv, keyToClone.pub.get());
this.parent = newParent;
this.childNumberPath = keyToClone.childNumberPath;
this.chainCode = keyToClone.chainCode;
this.encryptedPrivateKey = keyToClone.encryptedPrivateKey;
}
/**
* Returns the path through some {@link DeterministicHierarchy} which reaches this keys position in the tree.
* A path can be written as 1/2/1 which means the first child of the root, the second child of that node, then
* the first child of that node.
*/
public ImmutableList<ChildNumber> getPath() {
return childNumberPath;
}
/**
* Returns the path of this key as a human readable string starting with M to indicate the master key.
*/
public String getPathAsString() {
return HDUtils.formatPath(getPath());
}
private int getDepth() {
return childNumberPath.size();
}
/** Returns the last element of the path returned by {@link DeterministicKey#getPath()} */
public ChildNumber getChildNumber() {
return getDepth() == 0 ? ChildNumber.ZERO : childNumberPath.get(childNumberPath.size() - 1);
}
/**
* Returns the chain code associated with this key. See the specification to learn more about chain codes.
*/
public byte[] getChainCode() {
return chainCode;
}
/**
* Returns RIPE-MD160(SHA256(pub key bytes)).
*/
public byte[] getIdentifier() {
return Utils.sha256hash160(getPubKey());
}
/** Returns the first 32 bits of the result of {@link #getIdentifier()}. */
public byte[] getFingerprint() {
// TODO: why is this different than armory's fingerprint? BIP 32: "The first 32 bits of the identifier are called the fingerprint."
return Arrays.copyOfRange(getIdentifier(), 0, 4);
}
@Nullable
public DeterministicKey getParent() {
return parent;
}
/**
* Returns private key bytes, padded with zeros to 33 bytes.
* @throws java.lang.IllegalStateException if the private key bytes are missing.
*/
public byte[] getPrivKeyBytes33() {
byte[] bytes33 = new byte[33];
byte[] priv = getPrivKeyBytes();
System.arraycopy(priv, 0, bytes33, 33 - priv.length, priv.length);
return bytes33;
}
/**
* Returns the same key with the private part removed. May return the same instance.
*/
public DeterministicKey getPubOnly() {
if (isPubKeyOnly()) return this;
return new DeterministicKey(getPath(), getChainCode(), pub, null, parent);
}
static byte[] addChecksum(byte[] input) {
int inputLength = input.length;
byte[] checksummed = new byte[inputLength + 4];
System.arraycopy(input, 0, checksummed, 0, inputLength);
byte[] checksum = Utils.doubleDigest(input);
System.arraycopy(checksum, 0, checksummed, inputLength, 4);
return checksummed;
}
@Override
public DeterministicKey encrypt(KeyCrypter keyCrypter, KeyParameter aesKey) throws KeyCrypterException {
throw new UnsupportedOperationException("Must supply a new parent for encryption");
}
public DeterministicKey encrypt(KeyCrypter keyCrypter, KeyParameter aesKey, @Nullable DeterministicKey newParent) throws KeyCrypterException {
// Same as the parent code, except we construct a DeterministicKey instead of an ECKey.
checkNotNull(keyCrypter);
if (newParent != null)
checkArgument(newParent.isEncrypted());
final byte[] privKeyBytes = getPrivKeyBytes();
checkState(privKeyBytes != null, "Private key is not available");
EncryptedData encryptedPrivateKey = keyCrypter.encrypt(privKeyBytes, aesKey);
DeterministicKey key = new DeterministicKey(childNumberPath, chainCode, keyCrypter, pub, encryptedPrivateKey, newParent);
if (newParent == null)
key.setCreationTimeSeconds(getCreationTimeSeconds());
return key;
}
/**
* A deterministic key is considered to be encrypted if it has access to encrypted private key bytes, OR if its
* parent does. The reason is because the parent would be encrypted under the same key and this key knows how to
* rederive its own private key bytes from the parent, if needed.
*/
@Override
public boolean isEncrypted() {
return priv == null && (super.isEncrypted() || (parent != null && parent.isEncrypted()));
}
/**
* Returns this keys {@link com.dogecoin.dogecoinj.crypto.KeyCrypter} <b>or</b> the keycrypter of its parent key.
*/
@Override @Nullable
public KeyCrypter getKeyCrypter() {
if (keyCrypter != null)
return keyCrypter;
else if (parent != null)
return parent.getKeyCrypter();
else
return null;
}
@Override
public ECDSASignature sign(Sha256Hash input, @Nullable KeyParameter aesKey) throws KeyCrypterException {
if (isEncrypted()) {
// If the key is encrypted, ECKey.sign will decrypt it first before rerunning sign. Decryption walks the
// key heirarchy to find the private key (see below), so, we can just run the inherited method.
return super.sign(input, aesKey);
} else {
// If it's not encrypted, derive the private via the parents.
final BigInteger privateKey = findOrDerivePrivateKey();
if (privateKey == null) {
// This key is a part of a public-key only heirarchy and cannot be used for signing
throw new MissingPrivateKeyException();
}
return super.doSign(input, privateKey);
}
}
@Override
public DeterministicKey decrypt(KeyCrypter keyCrypter, KeyParameter aesKey) throws KeyCrypterException {
checkNotNull(keyCrypter);
// Check that the keyCrypter matches the one used to encrypt the keys, if set.
if (this.keyCrypter != null && !this.keyCrypter.equals(keyCrypter))
throw new KeyCrypterException("The keyCrypter being used to decrypt the key is different to the one that was used to encrypt it");
BigInteger privKey = findOrDeriveEncryptedPrivateKey(keyCrypter, aesKey);
DeterministicKey key = new DeterministicKey(childNumberPath, chainCode, privKey, parent);
if (!Arrays.equals(key.getPubKey(), getPubKey()))
throw new KeyCrypterException("Provided AES key is wrong");
if (parent == null)
key.setCreationTimeSeconds(getCreationTimeSeconds());
return key;
}
@Override
public DeterministicKey decrypt(KeyParameter aesKey) throws KeyCrypterException {
return (DeterministicKey) super.decrypt(aesKey);
}
// For when a key is encrypted, either decrypt our encrypted private key bytes, or work up the tree asking parents
// to decrypt and re-derive.
private BigInteger findOrDeriveEncryptedPrivateKey(KeyCrypter keyCrypter, KeyParameter aesKey) {
if (encryptedPrivateKey != null)
return new BigInteger(1, keyCrypter.decrypt(encryptedPrivateKey, aesKey));
// Otherwise we don't have it, but maybe we can figure it out from our parents. Walk up the tree looking for
// the first key that has some encrypted private key data.
DeterministicKey cursor = parent;
while (cursor != null) {
if (cursor.encryptedPrivateKey != null) break;
cursor = cursor.parent;
}
if (cursor == null)
throw new KeyCrypterException("Neither this key nor its parents have an encrypted private key");
byte[] parentalPrivateKeyBytes = keyCrypter.decrypt(cursor.encryptedPrivateKey, aesKey);
return derivePrivateKeyDownwards(cursor, parentalPrivateKeyBytes);
}
@Nullable
private BigInteger findOrDerivePrivateKey() {
DeterministicKey cursor = this;
while (cursor != null) {
if (cursor.priv != null) break;
cursor = cursor.parent;
}
if (cursor == null)
return null;
return derivePrivateKeyDownwards(cursor, cursor.priv.toByteArray());
}
private BigInteger derivePrivateKeyDownwards(DeterministicKey cursor, byte[] parentalPrivateKeyBytes) {
DeterministicKey downCursor = new DeterministicKey(cursor.childNumberPath, cursor.chainCode,
cursor.pub, new BigInteger(1, parentalPrivateKeyBytes), cursor.parent);
// Now we have to rederive the keys along the path back to ourselves. That path can be found by just truncating
// our path with the length of the parents path.
ImmutableList<ChildNumber> path = childNumberPath.subList(cursor.getDepth(), childNumberPath.size());
for (ChildNumber num : path) {
downCursor = HDKeyDerivation.deriveChildKey(downCursor, num);
}
// downCursor is now the same key as us, but with private key bytes.
checkState(downCursor.pub.equals(pub));
return checkNotNull(downCursor.priv);
}
/**
* Derives a child at the given index using hardened derivation. Note: <code>index</code> is
* not the "i" value. If you want the softened derivation, then use instead
* <code>HDKeyDerivation.deriveChildKey(this, new ChildNumber(child, false))</code>.
*/
public DeterministicKey derive(int child) {
return HDKeyDerivation.deriveChildKey(this, new ChildNumber(child, true));
}
/**
* Returns the private key of this deterministic key. Even if this object isn't storing the private key,
* it can be re-derived by walking up to the parents if necessary and this is what will happen.
* @throws java.lang.IllegalStateException if the parents are encrypted or a watching chain.
*/
@Override
public BigInteger getPrivKey() {
final BigInteger key = findOrDerivePrivateKey();
checkState(key != null, "Private key bytes not available");
return key;
}
public byte[] serializePublic(NetworkParameters params) {
return serialize(params, true);
}
public byte[] serializePrivate(NetworkParameters params) {
return serialize(params, false);
}
private byte[] serialize(NetworkParameters params, boolean pub) {
ByteBuffer ser = ByteBuffer.allocate(78);
ser.putInt(pub ? params.getBip32HeaderPub() : params.getBip32HeaderPriv());
ser.put((byte) getDepth());
if (parent == null) {
ser.putInt(0);
} else {
ser.put(parent.getFingerprint());
}
ser.putInt(getChildNumber().i());
ser.put(getChainCode());
ser.put(pub ? getPubKey() : getPrivKeyBytes33());
checkState(ser.position() == 78);
return ser.array();
}
public String serializePubB58(NetworkParameters params) {
return toBase58(serialize(params, true));
}
public String serializePrivB58(NetworkParameters params) {
return toBase58(serialize(params, false));
}
static String toBase58(byte[] ser) {
return Base58.encode(addChecksum(ser));
}
/** Deserialize a base-58-encoded HD Key with no parent */
public static DeterministicKey deserializeB58(String base58, NetworkParameters params) {
return deserializeB58(null, base58, params);
}
/**
* Deserialize a base-58-encoded HD Key.
* @param parent The parent node in the given key's deterministic hierarchy.
*/
public static DeterministicKey deserializeB58(@Nullable DeterministicKey parent, String base58, NetworkParameters params) {
try {
return deserialize(params, Base58.decodeChecked(base58), parent);
} catch (AddressFormatException e) {
throw new IllegalArgumentException(e);
}
}
/**
* Deserialize an HD Key with no parent
*/
public static DeterministicKey deserialize(NetworkParameters params, byte[] serializedKey) {
return deserialize(params, serializedKey, null);
}
/**
* Deserialize an HD Key.
* @param parent The parent node in the given key's deterministic hierarchy.
*/
public static DeterministicKey deserialize(NetworkParameters params, byte[] serializedKey, @Nullable DeterministicKey parent) {
ByteBuffer buffer = ByteBuffer.wrap(serializedKey);
int header = buffer.getInt();
if (header != params.getBip32HeaderPriv() && header != params.getBip32HeaderPub())
throw new IllegalArgumentException("Unknown header bytes: " + toBase58(serializedKey).substring(0, 4));
boolean pub = header == params.getBip32HeaderPub();
byte depth = buffer.get();
byte[] parentFingerprint = new byte[4];
buffer.get(parentFingerprint);
final int i = buffer.getInt();
final ChildNumber childNumber = new ChildNumber(i);
ImmutableList<ChildNumber> path;
if (parent != null) {
if (Arrays.equals(parentFingerprint, HDUtils.longTo4ByteArray(0)))
throw new IllegalArgumentException("Parent was provided but this key doesn't have one");
if (!Arrays.equals(parent.getFingerprint(), parentFingerprint))
throw new IllegalArgumentException("Parent fingerprints don't match");
path = HDUtils.append(parent.getPath(), childNumber);
if (path.size() != depth)
throw new IllegalArgumentException("Depth does not match");
} else {
if (depth >= 1)
// We have been given a key that is not a root key, yet we lack any object representing the parent.
// This can happen when deserializing an account key for a watching wallet. In this case, we assume that
// the client wants to conceal the key's position in the hierarchy. The parent is deemed to be the
// root of the hierarchy.
path = ImmutableList.of(childNumber);
else path = ImmutableList.of();
}
byte[] chainCode = new byte[32];
buffer.get(chainCode);
byte[] data = new byte[33];
buffer.get(data);
checkArgument(!buffer.hasRemaining(), "Found unexpected data in key");
if (pub) {
ECPoint point = ECKey.CURVE.getCurve().decodePoint(data);
return new DeterministicKey(path, chainCode, new LazyECPoint(point), null, parent);
} else {
return new DeterministicKey(path, chainCode, new BigInteger(1, data), parent);
}
}
/**
* The creation time of a deterministic key is equal to that of its parent, unless this key is the root of a tree
* in which case the time is stored alongside the key as per normal, see {@link com.dogecoin.dogecoinj.core.ECKey#getCreationTimeSeconds()}.
*/
@Override
public long getCreationTimeSeconds() {
if (parent != null)
return parent.getCreationTimeSeconds();
else
return super.getCreationTimeSeconds();
}
/**
* The creation time of a deterministic key is equal to that of its parent, unless this key is the root of a tree.
* Thus, setting the creation time on a leaf is forbidden.
*/
@Override
public void setCreationTimeSeconds(long newCreationTimeSeconds) {
if (parent != null)
throw new IllegalStateException("Creation time can only be set on root keys.");
else
super.setCreationTimeSeconds(newCreationTimeSeconds);
}
/**
* Verifies equality of all fields but NOT the parent pointer (thus the same key derived in two separate heirarchy
* objects will equal each other.
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DeterministicKey other = (DeterministicKey) o;
return super.equals(other)
&& Arrays.equals(this.chainCode, other.chainCode)
&& Objects.equal(this.childNumberPath, other.childNumberPath);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + childNumberPath.hashCode();
result = 31 * result + Arrays.hashCode(chainCode);
return result;
}
@Override
public String toString() {
final ToStringHelper helper = Objects.toStringHelper(this).omitNullValues();
helper.add("pub", Utils.HEX.encode(pub.getEncoded()));
helper.add("chainCode", HEX.encode(chainCode));
helper.add("path", getPathAsString());
if (creationTimeSeconds > 0)
helper.add("creationTimeSeconds", creationTimeSeconds);
helper.add("isEncrypted", isEncrypted());
helper.add("isPubKeyOnly", isPubKeyOnly());
return helper.toString();
}
@Override
public void formatKeyWithAddress(boolean includePrivateKeys, StringBuilder builder, NetworkParameters params) {
final Address address = toAddress(params);
builder.append(" addr:");
builder.append(address.toString());
builder.append(" hash160:");
builder.append(Utils.HEX.encode(getPubKeyHash()));
builder.append(" (");
builder.append(getPathAsString());
builder.append(")");
builder.append("\n");
if (includePrivateKeys) {
builder.append(" ");
builder.append(toStringWithPrivate(params));
builder.append("\n");
}
}
}

View File

@ -1,43 +0,0 @@
/**
* Copyright 2014 Google Inc.
*
* 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 com.dogecoin.dogecoinj.crypto;
import com.dogecoin.dogecoinj.wallet.Protos;
import javax.annotation.Nullable;
/**
* Provides a uniform way to access something that can be optionally encrypted with a
* {@link com.dogecoin.dogecoinj.crypto.KeyCrypter}, yielding an {@link com.dogecoin.dogecoinj.crypto.EncryptedData}, and
* which can have a creation time associated with it.
*/
public interface EncryptableItem {
/** Returns whether the item is encrypted or not. If it is, then {@link #getSecretBytes()} will return null. */
public boolean isEncrypted();
/** Returns the raw bytes of the item, if not encrypted, or null if encrypted or the secret is missing. */
@Nullable public byte[] getSecretBytes();
/** Returns the initialization vector and encrypted secret bytes, or null if not encrypted. */
@Nullable public EncryptedData getEncryptedData();
/** Returns an enum constant describing what algorithm was used to encrypt the key or UNENCRYPTED. */
public Protos.Wallet.EncryptionType getEncryptionType();
/** Returns the time in seconds since the UNIX epoch at which this encryptable item was first created/derived. */
public long getCreationTimeSeconds();
}

View File

@ -1,56 +0,0 @@
/**
* Copyright 2013 Jim Burton.
*
* Licensed under the MIT license (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://opensource.org/licenses/mit-license.php
*
* 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 com.dogecoin.dogecoinj.crypto;
import java.util.Arrays;
/**
* <p>An instance of EncryptedData is a holder for an initialization vector and encrypted bytes. It is typically
* used to hold encrypted private key bytes.</p>
*
* <p>The initialisation vector is random data that is used to initialise the AES block cipher when the
* private key bytes were encrypted. You need these for decryption.</p>
*/
public final class EncryptedData {
public final byte[] initialisationVector;
public final byte[] encryptedBytes;
public EncryptedData(byte[] initialisationVector, byte[] encryptedBytes) {
this.initialisationVector = Arrays.copyOf(initialisationVector, initialisationVector.length);
this.encryptedBytes = Arrays.copyOf(encryptedBytes, encryptedBytes.length);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
EncryptedData that = (EncryptedData) o;
return Arrays.equals(encryptedBytes, that.encryptedBytes) && Arrays.equals(initialisationVector, that.initialisationVector);
}
@Override
public int hashCode() {
int result = Arrays.hashCode(initialisationVector);
result = 31 * result + Arrays.hashCode(encryptedBytes);
return result;
}
@Override
public String toString() {
return "EncryptedData [initialisationVector=" + Arrays.toString(initialisationVector) + ", encryptedPrivateKey=" + Arrays.toString(encryptedBytes) + "]";
}
}

View File

@ -1,129 +0,0 @@
/**
* Copyright 2013 Jim Burton.
*
* Licensed under the MIT license (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://opensource.org/licenses/mit-license.php
*
* 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 com.dogecoin.dogecoinj.crypto;
import com.google.common.base.Objects;
import java.util.Arrays;
/**
* <p>An EncryptedPrivateKey contains the information produced after encrypting the private key bytes of an ECKey.</p>
*
* <p>It contains two member variables - initialisationVector and encryptedPrivateBytes. The initialisationVector is
* a randomly chosen list of bytes that were used to initialise the AES block cipher when the private key bytes were encrypted.
* You need these for decryption. The encryptedPrivateBytes are the result of AES encrypting the private keys using
* an AES key that is derived from a user entered password. You need the password to recreate the AES key in order
* to decrypt these bytes.</p>
*/
public class EncryptedPrivateKey {
private byte[] initialisationVector = null;
private byte[] encryptedPrivateBytes = null;
/**
* Cloning constructor.
* @param encryptedPrivateKey EncryptedPrivateKey to clone.
*/
public EncryptedPrivateKey(EncryptedPrivateKey encryptedPrivateKey) {
setInitialisationVector(encryptedPrivateKey.getInitialisationVector());
setEncryptedPrivateBytes(encryptedPrivateKey.getEncryptedBytes());
}
/**
* @param initialisationVector
* @param encryptedPrivateKeys
*/
public EncryptedPrivateKey(byte[] initialisationVector, byte[] encryptedPrivateKeys) {
setInitialisationVector(initialisationVector);
setEncryptedPrivateBytes(encryptedPrivateKeys);
}
public byte[] getInitialisationVector() {
return initialisationVector;
}
/**
* Set the initialisationVector, cloning the bytes.
*
* @param initialisationVector
*/
public void setInitialisationVector(byte[] initialisationVector) {
if (initialisationVector == null) {
this.initialisationVector = null;
return;
}
byte[] cloneIV = new byte[initialisationVector.length];
System.arraycopy(initialisationVector, 0, cloneIV, 0, initialisationVector.length);
this.initialisationVector = cloneIV;
}
public byte[] getEncryptedBytes() {
return encryptedPrivateBytes;
}
/**
* Set the encrypted private key bytes, cloning them.
*
* @param encryptedPrivateBytes
*/
public void setEncryptedPrivateBytes(byte[] encryptedPrivateBytes) {
if (encryptedPrivateBytes == null) {
this.encryptedPrivateBytes = null;
return;
}
this.encryptedPrivateBytes = Arrays.copyOf(encryptedPrivateBytes, encryptedPrivateBytes.length);
}
@Override
public EncryptedPrivateKey clone() {
return new EncryptedPrivateKey(getInitialisationVector(), getEncryptedBytes());
}
@Override
public int hashCode() {
return com.google.common.base.Objects.hashCode(encryptedPrivateBytes, initialisationVector);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
EncryptedPrivateKey other = (EncryptedPrivateKey) o;
return Objects.equal(initialisationVector, other.initialisationVector) &&
Objects.equal(encryptedPrivateBytes, other.encryptedPrivateBytes);
}
@Override
public String toString() {
return "EncryptedPrivateKey [initialisationVector=" + Arrays.toString(initialisationVector) + ", encryptedPrivateKey=" + Arrays.toString(encryptedPrivateBytes) + "]";
}
/**
* Clears all the EncryptedPrivateKey contents from memory (overwriting all data including PRIVATE KEYS).
* WARNING - this method irreversibly deletes the private key information.
*/
public void clear() {
if (encryptedPrivateBytes != null) {
Arrays.fill(encryptedPrivateBytes, (byte)0);
}
if (initialisationVector != null) {
Arrays.fill(initialisationVector, (byte)0);
}
}
}

View File

@ -1,23 +0,0 @@
/**
* Copyright 2013 Matija Mazi.
*
* 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 com.dogecoin.dogecoinj.crypto;
public class HDDerivationException extends RuntimeException {
public HDDerivationException(String message) {
super(message);
}
}

View File

@ -1,244 +0,0 @@
/**
* Copyright 2013 Matija Mazi.
*
* 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 com.dogecoin.dogecoinj.crypto;
import com.dogecoin.dogecoinj.core.ECKey;
import com.dogecoin.dogecoinj.core.Utils;
import com.google.common.collect.ImmutableList;
import org.spongycastle.crypto.macs.HMac;
import org.spongycastle.math.ec.ECPoint;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.SecureRandom;
import java.util.Arrays;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
/**
* Implementation of the <a href="https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki">BIP 32</a>
* deterministic wallet child key generation algorithm.
*/
public final class HDKeyDerivation {
static {
// Init proper random number generator, as some old Android installations have bugs that make it unsecure.
if (Utils.isAndroidRuntime())
new LinuxSecureRandom();
RAND_INT = new BigInteger(256, new SecureRandom());
}
// Some arbitrary random number. Doesn't matter what it is.
private static final BigInteger RAND_INT;
private HDKeyDerivation() { }
/**
* Child derivation may fail (although with extremely low probability); in such case it is re-attempted.
* This is the maximum number of re-attempts (to avoid an infinite loop in case of bugs etc.).
*/
public static final int MAX_CHILD_DERIVATION_ATTEMPTS = 100;
public static final HMac MASTER_HMAC_SHA512 = HDUtils.createHmacSha512Digest("Bitcoin seed".getBytes());
/**
* Generates a new deterministic key from the given seed, which can be any arbitrary byte array. However resist
* the temptation to use a string as the seed - any key derived from a password is likely to be weak and easily
* broken by attackers (this is not theoretical, people have had money stolen that way). This method checks
* that the given seed is at least 64 bits long.
*
* @throws HDDerivationException if generated master key is invalid (private key 0 or >= n).
* @throws IllegalArgumentException if the seed is less than 8 bytes and could be brute forced.
*/
public static DeterministicKey createMasterPrivateKey(byte[] seed) throws HDDerivationException {
checkArgument(seed.length > 8, "Seed is too short and could be brute forced");
// Calculate I = HMAC-SHA512(key="Bitcoin seed", msg=S)
byte[] i = HDUtils.hmacSha512(MASTER_HMAC_SHA512, seed);
// Split I into two 32-byte sequences, Il and Ir.
// Use Il as master secret key, and Ir as master chain code.
checkState(i.length == 64, i.length);
byte[] il = Arrays.copyOfRange(i, 0, 32);
byte[] ir = Arrays.copyOfRange(i, 32, 64);
Arrays.fill(i, (byte)0);
DeterministicKey masterPrivKey = createMasterPrivKeyFromBytes(il, ir);
Arrays.fill(il, (byte)0);
Arrays.fill(ir, (byte)0);
// Child deterministic keys will chain up to their parents to find the keys.
masterPrivKey.setCreationTimeSeconds(Utils.currentTimeSeconds());
return masterPrivKey;
}
/**
* @throws HDDerivationException if privKeyBytes is invalid (0 or >= n).
*/
public static DeterministicKey createMasterPrivKeyFromBytes(byte[] privKeyBytes, byte[] chainCode) throws HDDerivationException {
BigInteger priv = new BigInteger(1, privKeyBytes);
assertNonZero(priv, "Generated master key is invalid.");
assertLessThanN(priv, "Generated master key is invalid.");
return new DeterministicKey(ImmutableList.<ChildNumber>of(), chainCode, priv, null);
}
public static DeterministicKey createMasterPubKeyFromBytes(byte[] pubKeyBytes, byte[] chainCode) {
return new DeterministicKey(ImmutableList.<ChildNumber>of(), chainCode, new LazyECPoint(ECKey.CURVE.getCurve(), pubKeyBytes), null, null);
}
/**
* Derives a key given the "extended" child number, ie. the 0x80000000 bit of the value that you
* pass for <code>childNumber</code> will determine whether to use hardened derivation or not.
* Consider whether your code would benefit from the clarity of the equivalent, but explicit, form
* of this method that takes a <code>ChildNumber</code> rather than an <code>int</code>, for example:
* <code>deriveChildKey(parent, new ChildNumber(childNumber, true))</code>
* where the value of the hardened bit of <code>childNumber</code> is zero.
*/
public static DeterministicKey deriveChildKey(DeterministicKey parent, int childNumber) {
return deriveChildKey(parent, new ChildNumber(childNumber));
}
/**
* Derives a key of the "extended" child number, ie. with the 0x80000000 bit specifying whether to use
* hardened derivation or not. If derivation fails, tries a next child.
*/
public static DeterministicKey deriveThisOrNextChildKey(DeterministicKey parent, int childNumber) {
int nAttempts = 0;
ChildNumber child = new ChildNumber(childNumber);
boolean isHardened = child.isHardened();
while (nAttempts < MAX_CHILD_DERIVATION_ATTEMPTS) {
try {
child = new ChildNumber(child.num() + nAttempts, isHardened);
return deriveChildKey(parent, child);
} catch (HDDerivationException ignore) { }
nAttempts++;
}
throw new HDDerivationException("Maximum number of child derivation attempts reached, this is probably an indication of a bug.");
}
/**
* @throws HDDerivationException if private derivation is attempted for a public-only parent key, or
* if the resulting derived key is invalid (eg. private key == 0).
*/
public static DeterministicKey deriveChildKey(DeterministicKey parent, ChildNumber childNumber) throws HDDerivationException {
if (parent.isPubKeyOnly()) {
RawKeyBytes rawKey = deriveChildKeyBytesFromPublic(parent, childNumber, PublicDeriveMode.NORMAL);
return new DeterministicKey(
HDUtils.append(parent.getPath(), childNumber),
rawKey.chainCode,
new LazyECPoint(ECKey.CURVE.getCurve(), rawKey.keyBytes),
null,
parent);
} else {
RawKeyBytes rawKey = deriveChildKeyBytesFromPrivate(parent, childNumber);
return new DeterministicKey(
HDUtils.append(parent.getPath(), childNumber),
rawKey.chainCode,
new BigInteger(1, rawKey.keyBytes),
parent);
}
}
public static RawKeyBytes deriveChildKeyBytesFromPrivate(DeterministicKey parent,
ChildNumber childNumber) throws HDDerivationException {
checkArgument(parent.hasPrivKey(), "Parent key must have private key bytes for this method.");
byte[] parentPublicKey = ECKey.compressPoint(parent.getPubKeyPoint()).getEncoded();
assert parentPublicKey.length == 33 : parentPublicKey.length;
ByteBuffer data = ByteBuffer.allocate(37);
if (childNumber.isHardened()) {
data.put(parent.getPrivKeyBytes33());
} else {
data.put(parentPublicKey);
}
data.putInt(childNumber.i());
byte[] i = HDUtils.hmacSha512(parent.getChainCode(), data.array());
assert i.length == 64 : i.length;
byte[] il = Arrays.copyOfRange(i, 0, 32);
byte[] chainCode = Arrays.copyOfRange(i, 32, 64);
BigInteger ilInt = new BigInteger(1, il);
assertLessThanN(ilInt, "Illegal derived key: I_L >= n");
final BigInteger priv = parent.getPrivKey();
BigInteger ki = priv.add(ilInt).mod(ECKey.CURVE.getN());
assertNonZero(ki, "Illegal derived key: derived private key equals 0.");
return new RawKeyBytes(ki.toByteArray(), chainCode);
}
public enum PublicDeriveMode {
NORMAL,
WITH_INVERSION
}
public static RawKeyBytes deriveChildKeyBytesFromPublic(DeterministicKey parent, ChildNumber childNumber, PublicDeriveMode mode) throws HDDerivationException {
checkArgument(!childNumber.isHardened(), "Can't use private derivation with public keys only.");
byte[] parentPublicKey = ECKey.compressPoint(parent.getPubKeyPoint()).getEncoded();
assert parentPublicKey.length == 33 : parentPublicKey.length;
ByteBuffer data = ByteBuffer.allocate(37);
data.put(parentPublicKey);
data.putInt(childNumber.i());
byte[] i = HDUtils.hmacSha512(parent.getChainCode(), data.array());
assert i.length == 64 : i.length;
byte[] il = Arrays.copyOfRange(i, 0, 32);
byte[] chainCode = Arrays.copyOfRange(i, 32, 64);
BigInteger ilInt = new BigInteger(1, il);
assertLessThanN(ilInt, "Illegal derived key: I_L >= n");
final ECPoint G = ECKey.CURVE.getG();
final BigInteger N = ECKey.CURVE.getN();
ECPoint Ki;
switch (mode) {
case NORMAL:
Ki = G.multiply(ilInt).add(parent.getPubKeyPoint());
break;
case WITH_INVERSION:
// This trick comes from Gregory Maxwell. Check the homomorphic properties of our curve hold. The
// below calculations should be redundant and give the same result as NORMAL but if the precalculated
// tables have taken a bit flip will yield a different answer. This mode is used when vending a key
// to perform a last-ditch sanity check trying to catch bad RAM.
Ki = G.multiply(ilInt.add(RAND_INT));
BigInteger additiveInverse = RAND_INT.negate().mod(N);
Ki = Ki.add(G.multiply(additiveInverse));
Ki = Ki.add(parent.getPubKeyPoint());
break;
default: throw new AssertionError();
}
assertNonInfinity(Ki, "Illegal derived key: derived public key equals infinity.");
return new RawKeyBytes(Ki.getEncoded(true), chainCode);
}
private static void assertNonZero(BigInteger integer, String errorMessage) {
if (integer.equals(BigInteger.ZERO))
throw new HDDerivationException(errorMessage);
}
private static void assertNonInfinity(ECPoint point, String errorMessage) {
if (point.equals(ECKey.CURVE.getCurve().getInfinity()))
throw new HDDerivationException(errorMessage);
}
private static void assertLessThanN(BigInteger integer, String errorMessage) {
if (integer.compareTo(ECKey.CURVE.getN()) > 0)
throw new HDDerivationException(errorMessage);
}
public static class RawKeyBytes {
public final byte[] keyBytes, chainCode;
public RawKeyBytes(byte[] keyBytes, byte[] chainCode) {
this.keyBytes = keyBytes;
this.chainCode = chainCode;
}
}
}

View File

@ -1,100 +0,0 @@
/**
* Copyright 2013 Matija Mazi.
* Copyright 2014 Giannis Dzegoutanis.
*
* 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 com.dogecoin.dogecoinj.crypto;
import com.dogecoin.dogecoinj.core.ECKey;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import org.spongycastle.crypto.digests.SHA512Digest;
import org.spongycastle.crypto.macs.HMac;
import org.spongycastle.crypto.params.KeyParameter;
import javax.annotation.Nonnull;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Static utilities used in BIP 32 Hierarchical Deterministic Wallets (HDW).
*/
public final class HDUtils {
private static final Joiner PATH_JOINER = Joiner.on("/");
static HMac createHmacSha512Digest(byte[] key) {
SHA512Digest digest = new SHA512Digest();
HMac hMac = new HMac(digest);
hMac.init(new KeyParameter(key));
return hMac;
}
static byte[] hmacSha512(HMac hmacSha512, byte[] input) {
hmacSha512.reset();
hmacSha512.update(input, 0, input.length);
byte[] out = new byte[64];
hmacSha512.doFinal(out, 0);
return out;
}
public static byte[] hmacSha512(byte[] key, byte[] data) {
return hmacSha512(createHmacSha512Digest(key), data);
}
static byte[] toCompressed(byte[] uncompressedPoint) {
return ECKey.CURVE.getCurve().decodePoint(uncompressedPoint).getEncoded(true);
}
static byte[] longTo4ByteArray(long n) {
byte[] bytes = Arrays.copyOfRange(ByteBuffer.allocate(8).putLong(n).array(), 4, 8);
assert bytes.length == 4 : bytes.length;
return bytes;
}
public static ImmutableList<ChildNumber> append(List<ChildNumber> path, ChildNumber childNumber) {
return ImmutableList.<ChildNumber>builder().addAll(path).add(childNumber).build();
}
public static String formatPath(List<ChildNumber> path) {
return PATH_JOINER.join(Iterables.concat(Collections.singleton("M"), path));
}
/**
* The path is a human-friendly representation of the deterministic path. For example:
*
* "44H / 0H / 0H / 1 / 1"
*
* Where a letter "H" means hardened key. Spaces are ignored.
*/
public static List<ChildNumber> parsePath(@Nonnull String path) {
String[] parsedNodes = path.replace("M", "").split("/");
List<ChildNumber> nodes = new ArrayList<ChildNumber>();
for (String n : parsedNodes) {
n = n.replaceAll(" ", "");
if (n.length() == 0) continue;
boolean isHard = n.endsWith("H");
if (isHard) n = n.substring(0, n.length() - 1);
int nodeNumber = Integer.parseInt(n);
nodes.add(new ChildNumber(nodeNumber, isHard));
}
return nodes;
}
}

Some files were not shown because too many files have changed in this diff Show More