mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-11-03 05:57:21 +00:00
Remove existing build pom.xml
Added genesis block construction for Dogecoin network. Added difficulty calculations for Dogecoin network. Completed difficulty calculation code for Dogecoin. Added code for parsing Dogecoin blocks, and unit tests for same.
This commit is contained in:
278
src/main/java/org/altcoinj/core/AltcoinBlock.java
Normal file
278
src/main/java/org/altcoinj/core/AltcoinBlock.java
Normal file
@@ -0,0 +1,278 @@
|
||||
/**
|
||||
* 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 org.altcoinj.core;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.altcoinj.core.ScryptHash;
|
||||
import static org.altcoinj.core.Utils.scryptDigest;
|
||||
|
||||
import static org.bitcoinj.core.Coin.FIFTY_COINS;
|
||||
import static org.bitcoinj.core.Utils.doubleDigest;
|
||||
import static org.bitcoinj.core.Utils.doubleDigestTwoBuffers;
|
||||
|
||||
/**
|
||||
* <p>A block is a group of transactions, and is one of the fundamental data structures of the Bitcoin system.
|
||||
* It records a set of {@link Transaction}s together with some data that links it into a place in the global block
|
||||
* chain, and proves that a difficult calculation was done over its contents. See
|
||||
* <a href="http://www.bitcoin.org/bitcoin.pdf">the Bitcoin technical paper</a> for
|
||||
* more detail on blocks. <p/>
|
||||
*
|
||||
* To get a block, you can either build one from the raw bytes you can get from another implementation, or request one
|
||||
* specifically using {@link Peer#getBlock(Sha256Hash)}, or grab one from a downloaded {@link BlockChain}.
|
||||
*/
|
||||
public class AltcoinBlock extends org.bitcoinj.core.Block {
|
||||
/** Bit used to indicate that a block contains an AuxPoW section, where the network supports AuxPoW */
|
||||
public static final int BLOCK_FLAG_AUXPOW = (1 << 8);
|
||||
|
||||
private boolean auxpowParsed = false;
|
||||
private boolean auxpowBytesValid = false;
|
||||
|
||||
/** AuxPoW header element, if applicable. */
|
||||
@Nullable private AuxPoW auxpow;
|
||||
|
||||
private ScryptHash scryptHash;
|
||||
|
||||
/** Special case constructor, used for the genesis node, cloneAsHeader and unit tests. */
|
||||
public AltcoinBlock(NetworkParameters params) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
/** Constructs a block object from the Bitcoin wire format. */
|
||||
public AltcoinBlock(NetworkParameters params, byte[] payloadBytes) throws ProtocolException {
|
||||
super(params, payloadBytes, 0, false, false, payloadBytes.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contruct a block object from the Bitcoin wire format.
|
||||
* @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
|
||||
*/
|
||||
public AltcoinBlock(NetworkParameters params, byte[] payloadBytes, boolean parseLazy, boolean parseRetain, int length)
|
||||
throws ProtocolException {
|
||||
super(params, payloadBytes, 0, parseLazy, parseRetain, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contruct a block object from the Bitcoin wire format. Used in the case of a block
|
||||
* contained within another message (i.e. for AuxPoW header).
|
||||
*
|
||||
* @param params NetworkParameters object.
|
||||
* @param payloadBytes Bitcoin protocol formatted byte array containing message content.
|
||||
* @param offset The location of the first payload byte within the array.
|
||||
* @param parent The message element which contains this block, maybe null for no parent.
|
||||
* @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 AltcoinBlock(NetworkParameters params, byte[] payloadBytes, int offset, @Nullable Message parent, boolean parseLazy, boolean parseRetain, int length)
|
||||
throws ProtocolException {
|
||||
// TODO: Keep the parent
|
||||
super(params, payloadBytes, offset, parseLazy, parseRetain, length);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a block initialized with all the given fields.
|
||||
* @param params Which network the block is for.
|
||||
* @param version This should usually be set to 1 or 2, depending on if the height is in the coinbase input.
|
||||
* @param prevBlockHash Reference to previous block in the chain or {@link Sha256Hash#ZERO_HASH} if genesis.
|
||||
* @param merkleRoot The root of the merkle tree formed by the transactions.
|
||||
* @param time UNIX time when the block was mined.
|
||||
* @param difficultyTarget Number which this block hashes lower than.
|
||||
* @param nonce Arbitrary number to make the block hash lower than the target.
|
||||
* @param transactions List of transactions including the coinbase.
|
||||
*/
|
||||
public AltcoinBlock(NetworkParameters params, long version, Sha256Hash prevBlockHash, Sha256Hash merkleRoot, long time,
|
||||
long difficultyTarget, long nonce, List<Transaction> transactions) {
|
||||
super(params, version, prevBlockHash, merkleRoot, time, difficultyTarget, nonce, transactions);
|
||||
}
|
||||
|
||||
private ScryptHash calculateScryptHash() {
|
||||
try {
|
||||
ByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(HEADER_SIZE);
|
||||
writeHeader(bos);
|
||||
return new ScryptHash(Utils.reverseBytes(scryptDigest(bos.toByteArray())));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e); // Cannot happen.
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new RuntimeException(e); // Cannot happen.
|
||||
}
|
||||
}
|
||||
|
||||
public AuxPoW getAuxPoW() {
|
||||
// TODO: maybeParseAuxPoW();
|
||||
return this.auxpow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Scrypt hash of the block (which for a valid, solved block should be
|
||||
* below the target). Big endian.
|
||||
*/
|
||||
public ScryptHash getScryptHash() {
|
||||
if (scryptHash == null)
|
||||
scryptHash = calculateScryptHash();
|
||||
return scryptHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Scrypt hash of the block.
|
||||
*/
|
||||
public String getScryptHashAsString() {
|
||||
return getScryptHash().toString();
|
||||
}
|
||||
|
||||
protected void parseAuxPoW() throws ProtocolException {
|
||||
if (this.auxpowParsed)
|
||||
return;
|
||||
|
||||
this.auxpow = null;
|
||||
if (this.params instanceof AuxPoWNetworkParameters) {
|
||||
final AuxPoWNetworkParameters altcoinParams = (AuxPoWNetworkParameters)this.params;
|
||||
if (altcoinParams.isAuxPoWBlockVersion(this.getVersion())) {
|
||||
// The following is used in dogecoinj, but I don't think we necessarily need it
|
||||
// payload.length >= 160) { // We have at least 2 headers in an Aux block. Workaround for StoredBlocks
|
||||
this.auxpow = new AuxPoW(params, payload, cursor, this, parseLazy, parseRetain);
|
||||
optimalEncodingMessageSize += auxpow.getOptimalEncodingMessageSize();
|
||||
}
|
||||
}
|
||||
|
||||
this.auxpowParsed = true;
|
||||
this.auxpowBytesValid = parseRetain;
|
||||
}
|
||||
|
||||
@Override
|
||||
void parse() throws ProtocolException {
|
||||
parseHeader();
|
||||
parseAuxPoW();
|
||||
parseTransactions();
|
||||
length = cursor - offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseTransactions() {
|
||||
if (null != this.auxpow) {
|
||||
parseTransactions(HEADER_SIZE + auxpow.getMessageSize());
|
||||
} else {
|
||||
parseTransactions(HEADER_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseLite() throws ProtocolException {
|
||||
// Ignore the header since it has fixed length. If length is not provided we will have to
|
||||
// invoke a light parse of transactions to calculate the length.
|
||||
if (length == UNKNOWN_LENGTH) {
|
||||
Preconditions.checkState(parseLazy,
|
||||
"Performing lite parse of block transaction as block was initialised from byte array " +
|
||||
"without providing length. This should never need to happen.");
|
||||
parseAuxPoW();
|
||||
parseTransactions();
|
||||
length = cursor - offset;
|
||||
} else {
|
||||
transactionBytesValid = !transactionsParsed || parseRetain && length > HEADER_SIZE;
|
||||
}
|
||||
headerBytesValid = !headerParsed || parseRetain && length >= HEADER_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
void writeHeader(OutputStream stream) throws IOException {
|
||||
super.writeHeader(stream);
|
||||
// TODO: Write the AuxPoW header
|
||||
}
|
||||
|
||||
/** Returns a copy of the block, but without any transactions. */
|
||||
@Override
|
||||
public Block cloneAsHeader() {
|
||||
maybeParseHeader();
|
||||
AltcoinBlock block = new AltcoinBlock(params);
|
||||
block.nonce = nonce;
|
||||
block.prevBlockHash = prevBlockHash;
|
||||
block.merkleRoot = getMerkleRoot();
|
||||
block.version = version;
|
||||
block.time = time;
|
||||
block.difficultyTarget = difficultyTarget;
|
||||
block.transactions = null;
|
||||
block.hash = getHash();
|
||||
block.auxpow = auxpow;
|
||||
return block;
|
||||
}
|
||||
|
||||
/** Returns true if the hash of the block is OK (lower than difficulty target). */
|
||||
protected boolean checkProofOfWork(boolean throwException) throws VerificationException {
|
||||
// TODO: Add AuxPoW support
|
||||
|
||||
// This part is key - it is what proves the block was as difficult to make as it claims
|
||||
// to be. Note however that in the context of this function, the block can claim to be
|
||||
// as difficult as it wants to be .... if somebody was able to take control of our network
|
||||
// connection and fork us onto a different chain, they could send us valid blocks with
|
||||
// ridiculously easy difficulty and this function would accept them.
|
||||
//
|
||||
// To prevent this attack from being possible, elsewhere we check that the difficultyTarget
|
||||
// field is of the right value. This requires us to have the preceeding blocks.
|
||||
BigInteger target = getDifficultyTargetAsInteger();
|
||||
|
||||
BigInteger h = getHash().toBigInteger();
|
||||
if (h.compareTo(target) > 0) {
|
||||
// Proof of work check failed!
|
||||
if (throwException)
|
||||
throw new VerificationException("Hash is higher than target: " + getHashAsString() + " vs "
|
||||
+ target.toString(16));
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the block data to ensure it follows the rules laid out in the network parameters. Specifically,
|
||||
* throws an exception if the proof of work is invalid, or if the timestamp is too far from what it should be.
|
||||
* This is <b>not</b> everything that is required for a block to be valid, only what is checkable independent
|
||||
* of the chain and without a transaction index.
|
||||
*
|
||||
* @throws VerificationException
|
||||
*/
|
||||
@Override
|
||||
public void verifyHeader() throws VerificationException {
|
||||
super.verifyHeader();
|
||||
}
|
||||
}
|
||||
274
src/main/java/org/altcoinj/core/AuxPoW.java
Normal file
274
src/main/java/org/altcoinj/core/AuxPoW.java
Normal file
@@ -0,0 +1,274 @@
|
||||
/**
|
||||
* Copyright 2011 Google Inc.
|
||||
* Copyright 2014 Andreas Schildbach
|
||||
* Copyright 2015 J. Ross Nicoll
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.altcoinj.core;
|
||||
|
||||
import org.bitcoinj.crypto.TransactionSignature;
|
||||
import org.bitcoinj.script.Script;
|
||||
import org.bitcoinj.script.ScriptBuilder;
|
||||
import org.bitcoinj.script.ScriptOpCodes;
|
||||
import org.bitcoinj.utils.ExchangeRate;
|
||||
import org.bitcoinj.wallet.WalletTransaction.Pool;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.common.primitives.Longs;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import static org.bitcoinj.core.Utils.*;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
/**
|
||||
* <p>An AuxPoW header wraps a block header from another coin, enabling the foreign
|
||||
* chain's proof of work to be used for this chain as well.</p>
|
||||
*/
|
||||
public class AuxPoW extends ChildMessage implements Serializable {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AuxPoW.class);
|
||||
private static final long serialVersionUID = -8567546957352643140L;
|
||||
|
||||
private Transaction transaction;
|
||||
private Sha256Hash hashBlock;
|
||||
private MerkleBranch coinbaseBranch;
|
||||
private MerkleBranch blockchainBranch;
|
||||
private Block parentBlockHeader;
|
||||
|
||||
// Transactions can be encoded in a way that will use more bytes than is optimal
|
||||
// (due to VarInts having multiple encodings)
|
||||
// MAX_BLOCK_SIZE must be compared to the optimal encoding, not the actual encoding, so when parsing, we keep track
|
||||
// of the size of the ideal encoding in addition to the actual message size (which Message needs) so that Blocks
|
||||
// can properly keep track of optimal encoded size
|
||||
private transient int optimalEncodingMessageSize;
|
||||
|
||||
public AuxPoW(NetworkParameters params, @Nullable Message parent) {
|
||||
super(params);
|
||||
transaction = new Transaction(params);
|
||||
hashBlock = Sha256Hash.ZERO_HASH;
|
||||
coinbaseBranch = new MerkleBranch(params, this);
|
||||
blockchainBranch = new MerkleBranch(params, this);
|
||||
parentBlockHeader = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an AuxPoW header by reading payload starting from offset bytes in. Length of header is fixed.
|
||||
* @param params NetworkParameters object.1
|
||||
* @param payload Bitcoin protocol formatted byte array containing message content.
|
||||
* @param offset The location of the first payload byte within the array.
|
||||
* @param parent The message element which contains this header.
|
||||
* @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 AuxPoW(NetworkParameters params, byte[] payload, int offset, Message parent, boolean parseLazy, boolean parseRetain)
|
||||
throws ProtocolException {
|
||||
super(params, payload, offset, parent, parseLazy, parseRetain, Message.UNKNOWN_LENGTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an AuxPoW header by reading payload starting from offset bytes in. Length of header is fixed.
|
||||
*/
|
||||
public AuxPoW(NetworkParameters params, byte[] payload, @Nullable Message parent, boolean parseLazy, boolean parseRetain)
|
||||
throws ProtocolException {
|
||||
super(params, payload, 0, parent, parseLazy, parseRetain, Message.UNKNOWN_LENGTH);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseLite() throws ProtocolException {
|
||||
length = calcLength(payload, offset);
|
||||
cursor = offset + length;
|
||||
}
|
||||
|
||||
protected static int calcLength(byte[] buf, int offset) {
|
||||
VarInt varint;
|
||||
// jump past transaction
|
||||
int cursor = offset + Transaction.calcLength(buf, offset);
|
||||
|
||||
// jump past header hash
|
||||
cursor += 4;
|
||||
|
||||
// Coin base branch
|
||||
cursor += MerkleBranch.calcLength(buf, offset);
|
||||
|
||||
// Block chain branch
|
||||
cursor += MerkleBranch.calcLength(buf, offset);
|
||||
|
||||
// Block header
|
||||
cursor += Block.HEADER_SIZE;
|
||||
|
||||
return cursor - offset + 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
void parse() throws ProtocolException {
|
||||
|
||||
if (parsed)
|
||||
return;
|
||||
|
||||
cursor = offset;
|
||||
transaction = new Transaction(params, payload, cursor, this, parseLazy, parseRetain, Message.UNKNOWN_LENGTH);
|
||||
cursor += transaction.getOptimalEncodingMessageSize();
|
||||
optimalEncodingMessageSize = transaction.getOptimalEncodingMessageSize();
|
||||
|
||||
hashBlock = readHash();
|
||||
optimalEncodingMessageSize += 32; // Add the hash size to the optimal encoding
|
||||
|
||||
coinbaseBranch = new MerkleBranch(params, this, payload, cursor, parseLazy, parseRetain);
|
||||
cursor += coinbaseBranch.getOptimalEncodingMessageSize();
|
||||
optimalEncodingMessageSize += coinbaseBranch.getOptimalEncodingMessageSize();
|
||||
|
||||
blockchainBranch = new MerkleBranch(params, this, payload, cursor, parseLazy, parseRetain);
|
||||
cursor += blockchainBranch.getOptimalEncodingMessageSize();
|
||||
optimalEncodingMessageSize += blockchainBranch.getOptimalEncodingMessageSize();
|
||||
|
||||
// Make a copy of JUST the contained block header, so the block parser doesn't try reading
|
||||
// transactions past the end
|
||||
byte[] blockBytes = Arrays.copyOfRange(payload, cursor, cursor + Block.HEADER_SIZE);
|
||||
cursor += Block.HEADER_SIZE;
|
||||
parentBlockHeader = new AltcoinBlock(params, blockBytes, 0, this, parseLazy, parseRetain, Block.HEADER_SIZE);
|
||||
|
||||
length = cursor - offset;
|
||||
}
|
||||
|
||||
public int getOptimalEncodingMessageSize() {
|
||||
if (optimalEncodingMessageSize != 0)
|
||||
return optimalEncodingMessageSize;
|
||||
maybeParse();
|
||||
if (optimalEncodingMessageSize != 0)
|
||||
return optimalEncodingMessageSize;
|
||||
optimalEncodingMessageSize = getMessageSize();
|
||||
return optimalEncodingMessageSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* A human readable version of the transaction useful for debugging. The format is not guaranteed to be stable.
|
||||
* @param chain If provided, will be used to estimate lock times (if set). Can be null.
|
||||
*/
|
||||
public String toString(@Nullable AbstractBlockChain chain) {
|
||||
return transaction.toString(chain);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
|
||||
transaction.bitcoinSerialize(stream);
|
||||
stream.write(Utils.reverseBytes(hashBlock.getBytes()));
|
||||
|
||||
coinbaseBranch.bitcoinSerialize(stream);
|
||||
blockchainBranch.bitcoinSerialize(stream);
|
||||
|
||||
parentBlockHeader.bitcoinSerializeToStream(stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
AuxPoW input = (AuxPoW) o;
|
||||
if (!transaction.equals(input.transaction)) return false;
|
||||
if (!hashBlock.equals(input.hashBlock)) return false;
|
||||
if (!coinbaseBranch.equals(input.hashBlock)) return false;
|
||||
if (!blockchainBranch.equals(input.hashBlock)) return false;
|
||||
if (!parentBlockHeader.equals(input.hashBlock)) return false;
|
||||
return getHash().equals(input.getHash());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 1;
|
||||
result = 31 * result + transaction.hashCode();
|
||||
result = 31 * result + hashBlock.hashCode();
|
||||
result = 31 * result + coinbaseBranch.hashCode();
|
||||
result = 31 * result + blockchainBranch.hashCode();
|
||||
result = 31 * result + parentBlockHeader.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the block header from the parent blockchain. The hash of the header
|
||||
* is the value which should match the difficulty target. Note that blocks are
|
||||
* not necessarily part of the parent blockchain, they simply must be valid
|
||||
* blocks at the difficulty of the child blockchain.
|
||||
*/
|
||||
public Block getParentBlockHeader() {
|
||||
return parentBlockHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the coinbase transaction from the AuxPoW header. This should contain a
|
||||
* reference back to the block hash in its input scripts, to prove that the
|
||||
* transaction was created after the block.
|
||||
*/
|
||||
public Transaction getCoinbase() {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Merkle branch used to connect the AuXPow header with this blockchain.
|
||||
*/
|
||||
public MerkleBranch getBlockchainBranch() {
|
||||
return blockchainBranch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Merkle branch used to connect the coinbase transaction with this blockchain.
|
||||
*/
|
||||
public MerkleBranch getCoinbaseBranch() {
|
||||
return coinbaseBranch;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Checks the transaction contents for sanity, in ways that can be done in a standalone manner.
|
||||
* Does <b>not</b> perform all checks on a transaction such as whether the inputs are already spent.
|
||||
* Specifically this method verifies:</p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>That there is at least one input and output.</li>
|
||||
* <li>That the serialized size is not larger than the max block size.</li>
|
||||
* <li>That no outputs have negative value.</li>
|
||||
* <li>That the outputs do not sum to larger than the max allowed quantity of coin in the system.</li>
|
||||
* <li>If the tx is a coinbase tx, the coinbase scriptSig size is within range. Otherwise that there are no
|
||||
* coinbase inputs in the tx.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @throws VerificationException
|
||||
*/
|
||||
public void verify() throws VerificationException {
|
||||
maybeParse();
|
||||
// TODO: Verify the AuxPoW data
|
||||
}
|
||||
}
|
||||
223
src/main/java/org/altcoinj/core/MerkleBranch.java
Normal file
223
src/main/java/org/altcoinj/core/MerkleBranch.java
Normal file
@@ -0,0 +1,223 @@
|
||||
/**
|
||||
* 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 org.altcoinj.core;
|
||||
|
||||
import static org.bitcoinj.core.Utils.doubleDigestTwoBuffers;
|
||||
import static org.bitcoinj.core.Utils.reverseBytes;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A Merkle branch contains the hashes from a leaf of a Merkle tree
|
||||
* up to its root, plus a bitset used to define how the hashes are applied.
|
||||
* Given the hash of the leaf, this can be used to calculate the tree
|
||||
* root. This is useful for proving that a leaf belongs to a given tree.
|
||||
*/
|
||||
public class MerkleBranch extends ChildMessage implements Serializable {
|
||||
private static final long serialVersionUID = 2;
|
||||
|
||||
// Merkle branches can be encoded in a way that will use more bytes than is optimal
|
||||
// (due to VarInts having multiple encodings)
|
||||
// MAX_BLOCK_SIZE must be compared to the optimal encoding, not the actual encoding, so when parsing, we keep track
|
||||
// of the size of the ideal encoding in addition to the actual message size (which Message needs) so that Blocks
|
||||
// can properly keep track of optimal encoded size
|
||||
private transient int optimalEncodingMessageSize;
|
||||
|
||||
private List<Sha256Hash> branchHashes;
|
||||
private long branchSideMask;
|
||||
|
||||
public MerkleBranch(NetworkParameters params, @Nullable ChildMessage parent) {
|
||||
super(params);
|
||||
setParent(parent);
|
||||
|
||||
this.branchHashes = new ArrayList<Sha256Hash>();
|
||||
this.branchSideMask = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes an input message. This is usually part of a merkle branch message.
|
||||
*/
|
||||
public MerkleBranch(NetworkParameters params, @Nullable ChildMessage parent, byte[] payload, int offset) throws ProtocolException {
|
||||
super(params, payload, offset);
|
||||
setParent(parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes an input message. This is usually part of a merkle branch 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 MerkleBranch(NetworkParameters params, ChildMessage parent, byte[] payload, int offset,
|
||||
boolean parseLazy, boolean parseRetain)
|
||||
throws ProtocolException {
|
||||
super(params, payload, offset, parent, parseLazy, parseRetain, UNKNOWN_LENGTH);
|
||||
}
|
||||
|
||||
public MerkleBranch(NetworkParameters params, @Nullable ChildMessage parent,
|
||||
final List<Sha256Hash> hashes, final long branchSideMask) {
|
||||
super(params);
|
||||
setParent(parent);
|
||||
|
||||
this.branchHashes = hashes;
|
||||
this.branchSideMask = branchSideMask;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseLite() throws ProtocolException {
|
||||
length = calcLength(payload, offset);
|
||||
cursor = offset + length;
|
||||
}
|
||||
|
||||
protected static int calcLength(byte[] buf, int offset) {
|
||||
VarInt varint = new VarInt(buf, offset);
|
||||
|
||||
return ((int) varint.value) * 4 + 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
void parse() throws ProtocolException {
|
||||
if (parsed)
|
||||
return;
|
||||
|
||||
cursor = offset;
|
||||
|
||||
final int hashCount = (int) readVarInt();
|
||||
optimalEncodingMessageSize += VarInt.sizeOf(hashCount);
|
||||
branchHashes = new ArrayList<Sha256Hash>(hashCount);
|
||||
for (int hashIdx = 0; hashIdx < hashCount; hashIdx++) {
|
||||
branchHashes.add(readHash());
|
||||
}
|
||||
optimalEncodingMessageSize += 32 * hashCount;
|
||||
branchSideMask = readUint32();
|
||||
optimalEncodingMessageSize += 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
|
||||
stream.write(new VarInt(branchHashes.size()).encode());
|
||||
for (Sha256Hash hash: branchHashes) {
|
||||
stream.write(Utils.reverseBytes(hash.getBytes()));
|
||||
}
|
||||
Utils.uint32ToByteStreamLE(branchSideMask, stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the merkle branch root based on the supplied hashes and the given leaf hash.
|
||||
* Used to verify that the given leaf and root are part of the same tree.
|
||||
*/
|
||||
public Sha256Hash calculateMerkleRoot(final Sha256Hash leaf) {
|
||||
byte[] target = reverseBytes(leaf.getBytes());
|
||||
long mask = branchSideMask;
|
||||
|
||||
for (Sha256Hash hash: branchHashes) {
|
||||
target = (mask & 1) == 0
|
||||
? doubleDigestTwoBuffers(target, 0, 32, reverseBytes(hash.getBytes()), 0, 32)
|
||||
: doubleDigestTwoBuffers(reverseBytes(hash.getBytes()), 0, 32, target, 0, 32);
|
||||
mask >>= 1;
|
||||
}
|
||||
return new Sha256Hash(reverseBytes(target));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the hashes which make up this branch.
|
||||
*/
|
||||
public List<Sha256Hash> getHashes() {
|
||||
return Collections.unmodifiableList(this.branchHashes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of hashes in this branch.
|
||||
*/
|
||||
public int getSize() {
|
||||
return branchHashes.size();
|
||||
}
|
||||
|
||||
public int getOptimalEncodingMessageSize() {
|
||||
if (optimalEncodingMessageSize != 0)
|
||||
return optimalEncodingMessageSize;
|
||||
maybeParse();
|
||||
if (optimalEncodingMessageSize != 0)
|
||||
return optimalEncodingMessageSize;
|
||||
optimalEncodingMessageSize = getMessageSize();
|
||||
return optimalEncodingMessageSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a human readable debug string.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Merkle branch";
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Should check that the merkle branch side bits are not wider than the
|
||||
* provided hashes.
|
||||
* @throws VerificationException If the branch is invalid.
|
||||
*/
|
||||
public void verify() throws VerificationException {
|
||||
maybeParse();
|
||||
// TODO: Check the flags make sense for the inputs
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
MerkleBranch input = (MerkleBranch) o;
|
||||
|
||||
if (!branchHashes.equals(input.branchHashes)) return false;
|
||||
if (branchSideMask != input.branchSideMask) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 1;
|
||||
result = 31 * result + branchHashes.hashCode();
|
||||
result = 31 * result + (int) branchSideMask;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
34
src/main/java/org/altcoinj/core/ScryptHash.java
Normal file
34
src/main/java/org/altcoinj/core/ScryptHash.java
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright 2015 Ross Nicoll
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.altcoinj.core;
|
||||
|
||||
import org.bitcoinj.core.Sha256Hash;
|
||||
|
||||
/**
|
||||
* Scrypt hash. Currently extends Sha256Hash (so no real type safety is provided),
|
||||
* but in time the two classes should have a common superclass rather than one
|
||||
* extending the other directly.
|
||||
*/
|
||||
public class ScryptHash extends Sha256Hash {
|
||||
|
||||
public ScryptHash(byte[] rawHashBytes) {
|
||||
super(rawHashBytes);
|
||||
}
|
||||
|
||||
public ScryptHash(String hexString) {
|
||||
super(hexString);
|
||||
}
|
||||
}
|
||||
33
src/main/java/org/altcoinj/core/Utils.java
Normal file
33
src/main/java/org/altcoinj/core/Utils.java
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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 org.altcoinj.core;
|
||||
|
||||
import com.lambdaworks.crypto.SCrypt;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class Utils {
|
||||
/**
|
||||
* Calculates the Scrypt hash of the given byte range.
|
||||
* The resulting hash is in small endian form.
|
||||
*/
|
||||
public static byte[] scryptDigest(byte[] input) throws GeneralSecurityException {
|
||||
return SCrypt.scrypt(input, input, 1024, 1, 1, 32);
|
||||
}
|
||||
}
|
||||
288
src/main/java/org/altcoinj/params/AbstractDogecoinParams.java
Normal file
288
src/main/java/org/altcoinj/params/AbstractDogecoinParams.java
Normal file
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
* 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 org.altcoinj.params;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.math.BigInteger;
|
||||
import org.bitcoinj.core.AltcoinBlock;
|
||||
|
||||
import org.bitcoinj.core.AuxPoWNetworkParameters;
|
||||
import org.bitcoinj.core.Block;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import static org.bitcoinj.core.Coin.COIN;
|
||||
import org.bitcoinj.core.NetworkParameters;
|
||||
import org.bitcoinj.core.Sha256Hash;
|
||||
import org.bitcoinj.core.Utils;
|
||||
import org.bitcoinj.core.VerificationException;
|
||||
import org.bitcoinj.script.Script;
|
||||
import org.bitcoinj.script.ScriptOpCodes;
|
||||
import org.bitcoinj.store.BlockStore;
|
||||
import org.bitcoinj.store.BlockStoreException;
|
||||
import org.bitcoinj.utils.MonetaryFormat;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
/**
|
||||
* Parameters for the main Dogecoin production network on which people trade goods and services.
|
||||
*/
|
||||
public class AbstractDogecoinParams extends NetworkParameters {
|
||||
/** Standard format for the DOGE denomination. */
|
||||
public static final MonetaryFormat DOGE;
|
||||
/** Standard format for the mDOGE denomination. */
|
||||
public static final MonetaryFormat MDOGE;
|
||||
/** Standard format for the Koinu denomination. */
|
||||
public static final MonetaryFormat KOINU;
|
||||
|
||||
public static final int DIGISHIELD_BLOCK_HEIGHT = 145000; // Block height to use Digishield from
|
||||
public static final int DOGE_TARGET_TIMESPAN = 4 * 60 * 60; // 4 hours per difficulty cycle, on average.
|
||||
public static final int DOGE_TARGET_TIMESPAN_NEW = 60; // 60s per difficulty cycle, on average. Kicks in after block 145k.
|
||||
public static final int DOGE_TARGET_SPACING = 1 * 60; // 1 minute per block.
|
||||
public static final int DOGE_INTERVAL = DOGE_TARGET_TIMESPAN / DOGE_TARGET_SPACING;
|
||||
public static final int DOGE_INTERVAL_NEW = DOGE_TARGET_TIMESPAN_NEW / DOGE_TARGET_SPACING;
|
||||
|
||||
/** Currency code for base 1 Dogecoin. */
|
||||
public static final String CODE_DOGE = "DOGE";
|
||||
/** Currency code for base 1/1,000 Dogecoin. */
|
||||
public static final String CODE_MDOGE = "mDOGE";
|
||||
/** Currency code for base 1/100,000,000 Dogecoin. */
|
||||
public static final String CODE_KOINU = "Koinu";
|
||||
|
||||
public static final int BLOCK_VERSION_DEFAULT = 0x00000002;
|
||||
public static final int BLOCK_VERSION_AUXPOW = 0x00620002;
|
||||
public static final int BLOCK_VERSION_FLAG_AUXPOW = 0x00000100;
|
||||
|
||||
static {
|
||||
DOGE = MonetaryFormat.BTC.noCode()
|
||||
.code(0, CODE_DOGE)
|
||||
.code(3, CODE_MDOGE)
|
||||
.code(7, CODE_KOINU);
|
||||
MDOGE = DOGE.shift(3).minDecimals(2).optionalDecimals(2);
|
||||
KOINU = DOGE.shift(7).minDecimals(0).optionalDecimals(2);
|
||||
}
|
||||
|
||||
/** The string returned by getId() for the main, production network where people trade things. */
|
||||
public static final String ID_DOGE_MAINNET = "org.dogecoin.production";
|
||||
/** The string returned by getId() for the testnet. */
|
||||
public static final String ID_DOGE_TESTNET = "org.dogecoin.test";
|
||||
|
||||
protected final int newInterval;
|
||||
protected final int newTargetTimespan;
|
||||
protected final int diffChangeTarget;
|
||||
|
||||
protected Logger log = LoggerFactory.getLogger(AbstractDogecoinParams.class);
|
||||
|
||||
public AbstractDogecoinParams(final int setDiffChangeTarget) {
|
||||
super();
|
||||
genesisBlock = createGenesis(this);
|
||||
interval = DOGE_INTERVAL;
|
||||
newInterval = DOGE_INTERVAL_NEW;
|
||||
targetTimespan = DOGE_TARGET_TIMESPAN;
|
||||
newTargetTimespan = DOGE_TARGET_TIMESPAN_NEW;
|
||||
maxTarget = Utils.decodeCompactBits(0x1e0fffffL);
|
||||
diffChangeTarget = setDiffChangeTarget;
|
||||
|
||||
packetMagic = 0xc0c0c0c0;
|
||||
bip32HeaderPub = 0x0488C42E; //The 4 byte header that serializes in base58 to "xpub". (?)
|
||||
bip32HeaderPriv = 0x0488E1F4; //The 4 byte header that serializes in base58 to "xprv" (?)
|
||||
}
|
||||
|
||||
private static AltcoinBlock createGenesis(NetworkParameters params) {
|
||||
AltcoinBlock genesisBlock = new AltcoinBlock(params);
|
||||
Transaction t = new Transaction(params);
|
||||
try {
|
||||
byte[] bytes = Utils.HEX.decode
|
||||
("04ffff001d0104084e696e746f6e646f");
|
||||
t.addInput(new TransactionInput(params, t, bytes));
|
||||
ByteArrayOutputStream scriptPubKeyBytes = new ByteArrayOutputStream();
|
||||
Script.writeBytes(scriptPubKeyBytes, Utils.HEX.decode
|
||||
("040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9"));
|
||||
scriptPubKeyBytes.write(ScriptOpCodes.OP_CHECKSIG);
|
||||
t.addOutput(new TransactionOutput(params, t, COIN.multiply(88), scriptPubKeyBytes.toByteArray()));
|
||||
} catch (Exception e) {
|
||||
// Cannot happen.
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
genesisBlock.addTransaction(t);
|
||||
return genesisBlock;
|
||||
}
|
||||
|
||||
/** How many blocks pass between difficulty adjustment periods. After new diff algo. */
|
||||
public int getNewInterval() {
|
||||
return newInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
public MonetaryFormat getMonetaryFormat() {
|
||||
return DOGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Coin getMaxMoney() {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Coin getMinNonDustOutput() {
|
||||
return Coin.COIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUriScheme() {
|
||||
return "dogecoin";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMaxMoney() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkDifficultyTransitions(StoredBlock storedPrev, Block nextBlock, BlockStore blockStore)
|
||||
throws VerificationException, BlockStoreException {
|
||||
final Block prev = storedPrev.getHeader();
|
||||
final int previousHeight = storedPrev.getHeight();
|
||||
final boolean digishieldAlgorithm = previousHeight + 1 >= this.getDigishieldBlockHeight();
|
||||
final int retargetInterval = digishieldAlgorithm
|
||||
? this.getInterval()
|
||||
: this.getNewInterval();
|
||||
|
||||
// Is this supposed to be a difficulty transition point?
|
||||
if ((storedPrev.getHeight() + 1) % retargetInterval != 0) {
|
||||
// No ... so check the difficulty didn't actually change.
|
||||
if (nextBlock.getDifficultyTarget() != prev.getDifficultyTarget())
|
||||
throw new VerificationException("Unexpected change in difficulty at height " + storedPrev.getHeight() +
|
||||
": " + Long.toHexString(nextBlock.getDifficultyTarget()) + " vs " +
|
||||
Long.toHexString(prev.getDifficultyTarget()));
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to find a block far back in the chain. It's OK that this is expensive because it only occurs every
|
||||
// two weeks after the initial block chain download.
|
||||
StoredBlock cursor = blockStore.get(prev.getHash());
|
||||
int goBack = retargetInterval - 1;
|
||||
if (cursor.getHeight()+1 != retargetInterval)
|
||||
goBack = retargetInterval;
|
||||
|
||||
for (int i = 0; i < goBack; i++) {
|
||||
if (cursor == null) {
|
||||
// This should never happen. If it does, it means we are following an incorrect or busted chain.
|
||||
throw new VerificationException(
|
||||
"Difficulty transition point but we did not find a way back to the genesis block.");
|
||||
}
|
||||
cursor = blockStore.get(cursor.getHeader().getPrevBlockHash());
|
||||
}
|
||||
|
||||
//We used checkpoints...
|
||||
if (cursor == null) {
|
||||
log.debug("Difficulty transition: Hit checkpoint!");
|
||||
return;
|
||||
}
|
||||
|
||||
Block blockIntervalAgo = cursor.getHeader();
|
||||
long receivedTargetCompact = nextBlock.getDifficultyTarget();
|
||||
long newTargetCompact = this.getNewDifficultyTarget(previousHeight, prev.getTimeSeconds(),
|
||||
receivedTargetCompact, blockIntervalAgo.getTimeSeconds());
|
||||
|
||||
if (newTargetCompact != receivedTargetCompact)
|
||||
throw new VerificationException("Network provided difficulty bits do not match what was calculated: " +
|
||||
newTargetCompact + " vs " + receivedTargetCompact);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param previousHeight Height of the block immediately previous to the one we're calculating difficulty of.
|
||||
* @param previousBlockTime Time of the block immediately previous to the one we're calculating difficulty of.
|
||||
* @param lastDifficultyTarget Compact difficulty target of the last retarget block.
|
||||
* @param lastRetargetTime Time of the last difficulty retarget.
|
||||
* @return New difficulty target as compact bytes.
|
||||
*/
|
||||
protected long getNewDifficultyTarget(int previousHeight, long previousBlockTime,
|
||||
final long lastDifficultyTarget, final long lastRetargetTime) {
|
||||
final int height = previousHeight + 1;
|
||||
final boolean digishieldAlgorithm = height >= this.getDigishieldBlockHeight();
|
||||
final int retargetTimespan = digishieldAlgorithm
|
||||
? this.getNewTargetTimespan()
|
||||
: this.getTargetTimespan();
|
||||
int actualTime = (int) (previousBlockTime - lastRetargetTime);
|
||||
final int minTimespan;
|
||||
final int maxTimespan;
|
||||
|
||||
// Limit the adjustment step.
|
||||
if (digishieldAlgorithm)
|
||||
{
|
||||
// Round towards zero to match the C++ implementation.
|
||||
if (actualTime < retargetTimespan) {
|
||||
actualTime = (int)Math.ceil(retargetTimespan + (actualTime - retargetTimespan) / 8.0);
|
||||
} else {
|
||||
actualTime = (int)Math.floor(retargetTimespan + (actualTime - retargetTimespan) / 8.0);
|
||||
}
|
||||
minTimespan = retargetTimespan - (retargetTimespan / 4);
|
||||
maxTimespan = retargetTimespan + (retargetTimespan / 2);
|
||||
}
|
||||
else if (height > 10000)
|
||||
{
|
||||
minTimespan = retargetTimespan / 4;
|
||||
maxTimespan = retargetTimespan * 4;
|
||||
}
|
||||
else if (height > 5000)
|
||||
{
|
||||
minTimespan = retargetTimespan / 8;
|
||||
maxTimespan = retargetTimespan * 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
minTimespan = retargetTimespan / 16;
|
||||
maxTimespan = retargetTimespan * 4;
|
||||
}
|
||||
actualTime = Math.min(maxTimespan, Math.max(minTimespan, actualTime));
|
||||
|
||||
BigInteger newTarget = Utils.decodeCompactBits(lastDifficultyTarget);
|
||||
newTarget = newTarget.multiply(BigInteger.valueOf(actualTime));
|
||||
newTarget = newTarget.divide(BigInteger.valueOf(retargetTimespan));
|
||||
|
||||
if (newTarget.compareTo(this.getMaxTarget()) > 0) {
|
||||
log.info("Difficulty hit proof of work limit: {}", newTarget.toString(16));
|
||||
newTarget = this.getMaxTarget();
|
||||
}
|
||||
|
||||
int accuracyBytes = (int) (lastDifficultyTarget >>> 24) - 3;
|
||||
|
||||
// The calculated difficulty is to a higher precision than received, so reduce here.
|
||||
BigInteger mask = BigInteger.valueOf(0xFFFFFFL).shiftLeft(accuracyBytes * 8);
|
||||
newTarget = newTarget.and(mask);
|
||||
return Utils.encodeCompactBits(newTarget);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the block height from which the Digishield difficulty calculation
|
||||
* algorithm is used.
|
||||
*/
|
||||
public int getDigishieldBlockHeight() {
|
||||
return DIGISHIELD_BLOCK_HEIGHT;
|
||||
}
|
||||
}
|
||||
103
src/main/java/org/altcoinj/params/DogecoinMainNetParams.java
Normal file
103
src/main/java/org/altcoinj/params/DogecoinMainNetParams.java
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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 org.altcoinj.params;
|
||||
|
||||
import org.altcoinj.core.ScryptHash;
|
||||
import org.bitcoinj.core.AltcoinBlock;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
/**
|
||||
* Parameters for the main production network on which people trade goods and services.
|
||||
*/
|
||||
public class DogecoinMainNetParams extends AbstractDogecoinParams {
|
||||
protected static final int DIFFICULTY_CHANGE_TARGET = 145000;
|
||||
|
||||
public DogecoinMainNetParams() {
|
||||
super(DIFFICULTY_CHANGE_TARGET);
|
||||
dumpedPrivateKeyHeader = 158; //This is always addressHeader + 128
|
||||
addressHeader = 30;
|
||||
p2shHeader = 22;
|
||||
acceptableAddressCodes = new int[] { addressHeader, p2shHeader };
|
||||
port = 22556;
|
||||
packetMagic = 0xc0c0c0c0;
|
||||
bip32HeaderPub = 0x0488C42E; //The 4 byte header that serializes in base58 to "xpub". (?)
|
||||
bip32HeaderPriv = 0x0488E1F4; //The 4 byte header that serializes in base58 to "xprv" (?)
|
||||
genesisBlock.setDifficultyTarget(0x1e0ffff0L);
|
||||
genesisBlock.setTime(1386325540L);
|
||||
genesisBlock.setNonce(99943L);
|
||||
id = ID_DOGE_MAINNET;
|
||||
subsidyDecreaseBlockCount = 100000;
|
||||
spendableCoinbaseDepth = 100;
|
||||
|
||||
// Note this is an SHA256 hash, not a Scrypt hash. Scrypt hashes are only
|
||||
// used in difficulty calculations.
|
||||
String genesisHash = genesisBlock.getHashAsString();
|
||||
checkState(genesisHash.equals("1a91e3dace36e2be3bf030a65679fe821aa1d6ef92e7c9902eb318182c355691"),
|
||||
genesisHash);
|
||||
|
||||
// This contains (at a minimum) the blocks which are not BIP30 compliant. BIP30 changed how duplicate
|
||||
// transactions are handled. Duplicated transactions could occur in the case where a coinbase had the same
|
||||
// extraNonce and the same outputs but appeared at different heights, and greatly complicated re-org handling.
|
||||
// Having these here simplifies block connection logic considerably.
|
||||
checkpoints.put( 0, new ScryptHash("1a91e3dace36e2be3bf030a65679fe821aa1d6ef92e7c9902eb318182c355691"));
|
||||
checkpoints.put( 42279, new ScryptHash("8444c3ef39a46222e87584ef956ad2c9ef401578bd8b51e8e4b9a86ec3134d3a"));
|
||||
checkpoints.put( 42400, new ScryptHash("557bb7c17ed9e6d4a6f9361cfddf7c1fc0bdc394af7019167442b41f507252b4"));
|
||||
checkpoints.put(104679, new ScryptHash("35eb87ae90d44b98898fec8c39577b76cb1eb08e1261cfc10706c8ce9a1d01cf"));
|
||||
checkpoints.put(128370, new ScryptHash("3f9265c94cab7dc3bd6a2ad2fb26c8845cb41cff437e0a75ae006997b4974be6"));
|
||||
checkpoints.put(145000, new ScryptHash("cc47cae70d7c5c92828d3214a266331dde59087d4a39071fa76ddfff9b7bde72"));
|
||||
checkpoints.put(165393, new ScryptHash("7154efb4009e18c1c6a6a79fc6015f48502bcd0a1edd9c20e44cd7cbbe2eeef1"));
|
||||
checkpoints.put(186774, new ScryptHash("3c712c49b34a5f34d4b963750d6ba02b73e8a938d2ee415dcda141d89f5cb23a"));
|
||||
checkpoints.put(199992, new ScryptHash("3408ff829b7104eebaf61fd2ba2203ef2a43af38b95b353e992ef48f00ebb190"));
|
||||
checkpoints.put(225000, new ScryptHash("be148d9c5eab4a33392a6367198796784479720d06bfdd07bd547fe934eea15a"));
|
||||
checkpoints.put(250000, new ScryptHash("0e4bcfe8d970979f7e30e2809ab51908d435677998cf759169407824d4f36460"));
|
||||
checkpoints.put(270639, new ScryptHash("c587a36dd4f60725b9dd01d99694799bef111fc584d659f6756ab06d2a90d911"));
|
||||
checkpoints.put(299742, new ScryptHash("1cc89c0c8a58046bf0222fe131c099852bd9af25a80e07922918ef5fb39d6742"));
|
||||
checkpoints.put(323141, new ScryptHash("60c9f919f9b271add6ef5671e9538bad296d79f7fdc6487ba702bf2ba131d31d"));
|
||||
checkpoints.put(339202, new ScryptHash("8c29048df5ae9df38a67ea9470fdd404d281a3a5c6f33080cd5bf14aa496ab03"));
|
||||
checkpoints.put(350000, new ScryptHash("2bdcba23a47049e69c4fec4c425462e30f3d21d25223bde0ed36be4ea59a7075"));
|
||||
checkpoints.put(370005, new ScryptHash("7be5af2c5bdcb79047dcd691ef613b82d4f1c20835677daed936de37a4782e15"));
|
||||
checkpoints.put(371337, new ScryptHash("60323982f9c5ff1b5a954eac9dc1269352835f47c2c5222691d80f0d50dcf053"));
|
||||
checkpoints.put(400002, new ScryptHash("a5021d69a83f39aef10f3f24f932068d6ff322c654d20562def3fac5703ce3aa"));
|
||||
|
||||
dnsSeeds = new String[] {
|
||||
"seed.dogecoin.com",
|
||||
"seed.mophides.com",
|
||||
"seed.dogechain.info",
|
||||
};
|
||||
}
|
||||
|
||||
private static DogecoinMainNetParams instance;
|
||||
public static synchronized DogecoinMainNetParams get() {
|
||||
if (instance == null) {
|
||||
instance = new DogecoinMainNetParams();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPaymentProtocolId() {
|
||||
// TODO: CHANGE THIS
|
||||
return ID_DOGE_MAINNET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuxPoWBlockVersion(long version) {
|
||||
return version >= BLOCK_VERSION_AUXPOW
|
||||
&& (version & BLOCK_VERSION_FLAG_AUXPOW) > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2013 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 org.altcoinj.params;
|
||||
|
||||
import org.bitcoinj.core.NetworkParameters;
|
||||
import org.bitcoinj.core.Utils;
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
/**
|
||||
* Parameters for the testnet, a separate public instance of Bitcoin that has relaxed rules suitable for development
|
||||
* and testing of applications and new Bitcoin versions.
|
||||
*/
|
||||
public class DogecoinTestNet3Params extends AbstractDogecoinParams {
|
||||
protected static final int DIFFICULTY_CHANGE_TARGET = 145000;
|
||||
|
||||
public DogecoinTestNet3Params() {
|
||||
super(DIFFICULTY_CHANGE_TARGET);
|
||||
id = ID_DOGE_TESTNET;
|
||||
// Genesis hash is bb0a78264637406b6360aad926284d544d7049f45189db5664f3c4d07350559e
|
||||
packetMagic = 0xfcc1b7dc;
|
||||
|
||||
maxTarget = Utils.decodeCompactBits(0x1e0fffffL);
|
||||
port = 44556;
|
||||
addressHeader = 113;
|
||||
p2shHeader = 196;
|
||||
acceptableAddressCodes = new int[] { addressHeader, p2shHeader };
|
||||
dumpedPrivateKeyHeader = 241;
|
||||
genesisBlock.setTime(1391503289L);
|
||||
genesisBlock.setDifficultyTarget(0x1e0ffff0L);
|
||||
genesisBlock.setNonce(997879);
|
||||
spendableCoinbaseDepth = 30;
|
||||
subsidyDecreaseBlockCount = 100000;
|
||||
String genesisHash = genesisBlock.getHashAsString();
|
||||
checkState(genesisHash.equals("bb0a78264637406b6360aad926284d544d7049f45189db5664f3c4d07350559e"));
|
||||
alertSigningKey = Hex.decode("042756726da3c7ef515d89212ee1705023d14be389e25fe15611585661b9a20021908b2b80a3c7200a0139dd2b26946606aab0eef9aa7689a6dc2c7eee237fa834");
|
||||
|
||||
dnsSeeds = new String[] {
|
||||
"testnets.chain.so" // Chain.so
|
||||
};
|
||||
bip32HeaderPub = 0x043587CF;
|
||||
bip32HeaderPriv = 0x04358394;
|
||||
}
|
||||
|
||||
private static DogecoinTestNet3Params instance;
|
||||
public static synchronized DogecoinTestNet3Params get() {
|
||||
if (instance == null) {
|
||||
instance = new DogecoinTestNet3Params();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPaymentProtocolId() {
|
||||
// TODO: CHANGE ME
|
||||
return PAYMENT_PROTOCOL_ID_TESTNET;
|
||||
}
|
||||
}
|
||||
5
src/main/java/org/altcoinj/params/package-info.java
Normal file
5
src/main/java/org/altcoinj/params/package-info.java
Normal file
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Network parameters encapsulate some of the differences between different altcoin networks such as the main
|
||||
* network, the testnet, regtest mode, unit testing params and so on.
|
||||
*/
|
||||
package org.altcoinj.params;
|
||||
5
src/main/java/org/altcoinj/protocols/package-info.java
Normal file
5
src/main/java/org/altcoinj/protocols/package-info.java
Normal file
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* High level protocols that build on top of Bitcoin go here: we have the payment protocol for sending transactions
|
||||
* from sender to receiver with metadata, and a micropayment channels implementation.
|
||||
*/
|
||||
package org.altcoinj.protocols;
|
||||
259
src/paymentchannel.proto
Normal file
259
src/paymentchannel.proto
Normal file
@@ -0,0 +1,259 @@
|
||||
/** 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Authors: Mike Hearn, Matt Corallo
|
||||
*/
|
||||
|
||||
/* Notes:
|
||||
* - Endianness: All byte arrays that represent numbers (such as hashes and private keys) are Big Endian
|
||||
* - To regenerate after editing, run mvn clean package -DupdateProtobuf
|
||||
*/
|
||||
|
||||
package paymentchannels;
|
||||
|
||||
option java_package = "org.bitcoin.paymentchannel";
|
||||
option java_outer_classname = "Protos";
|
||||
|
||||
// This message is designed to be either sent raw over the network (e.g. length prefixed) or embedded inside another
|
||||
// protocol that is being extended to support micropayments. In this file "primary" typically can be read as "client"
|
||||
// and "secondary" as "server".
|
||||
message TwoWayChannelMessage {
|
||||
enum MessageType {
|
||||
CLIENT_VERSION = 1;
|
||||
SERVER_VERSION = 2;
|
||||
INITIATE = 3;
|
||||
PROVIDE_REFUND = 4;
|
||||
RETURN_REFUND = 5;
|
||||
PROVIDE_CONTRACT = 6;
|
||||
// Note that there are no optional fields set for CHANNEL_OPEN, it is sent from the
|
||||
// secondary to the primary to indicate that the provided contract was received,
|
||||
// verified, and broadcast successfully and the primary can now provide UPDATE messages
|
||||
// at will to begin paying secondary. If the channel is interrupted after the
|
||||
// CHANNEL_OPEN message (ie closed without an explicit CLOSE or ERROR) the primary may
|
||||
// reopen the channel by setting the contract transaction hash in its CLIENT_VERSION
|
||||
// message.
|
||||
CHANNEL_OPEN = 7;
|
||||
UPDATE_PAYMENT = 8;
|
||||
// Sent by the server to the client after an UPDATE_PAYMENT message is successfully processed.
|
||||
PAYMENT_ACK = 11;
|
||||
// Either side can send this message. If the client sends it to the server, then the server
|
||||
// takes the most recent signature it received in an UPDATE_PAYMENT and uses it to create a
|
||||
// valid transaction, which it then broadcasts on the network.
|
||||
//
|
||||
// Once broadcast is complete, it sends back another CLOSE message with the settlement field set, containing
|
||||
// the final state of the contract.
|
||||
//
|
||||
// The server is allowed to initiate settlement whenever it wants, in which case the client will
|
||||
// asynchronously receive a CLOSE message with the settlement field set. The server is also allowed
|
||||
// to send a CLOSE to mark the end of a connection without any settlement taking place, in which
|
||||
// case this is just an equivalent to a TCP FIN packet. An explicit end-of-protocol markers can be
|
||||
// useful when this protocol is embedded inside another.
|
||||
CLOSE = 9;
|
||||
|
||||
// Used to indicate an error condition.
|
||||
// Both parties should make an effort to send either an ERROR or a CLOSE immediately
|
||||
// before closing the socket (unless they just received an ERROR or a CLOSE). This is important
|
||||
// because the protocol may not run over TCP.
|
||||
ERROR = 10;
|
||||
};
|
||||
|
||||
// This is required so if a new message type is added in future, old software aborts trying
|
||||
// to read the message as early as possible. If the message doesn't parse, the socket should
|
||||
// be closed.
|
||||
required MessageType type = 1;
|
||||
|
||||
// Now one optional field for each message. Only the field specified by type should be read.
|
||||
optional ClientVersion client_version = 2;
|
||||
optional ServerVersion server_version = 3;
|
||||
optional Initiate initiate = 4;
|
||||
optional ProvideRefund provide_refund = 5;
|
||||
optional ReturnRefund return_refund = 6;
|
||||
optional ProvideContract provide_contract = 7;
|
||||
optional UpdatePayment update_payment = 8;
|
||||
optional PaymentAck payment_ack = 11;
|
||||
optional Settlement settlement = 9;
|
||||
|
||||
optional Error error = 10;
|
||||
}
|
||||
|
||||
// Sent by primary to secondary on opening the connection. If anything is received before this is
|
||||
// sent, the socket is closed.
|
||||
message ClientVersion {
|
||||
required int32 major = 1;
|
||||
optional int32 minor = 2 [default = 0];
|
||||
|
||||
// The hash of the multisig contract of a previous channel. This indicates that the primary
|
||||
// wishes to reopen the given channel. If the server is willing to reopen it, it simply
|
||||
// responds with a SERVER_VERSION and then immediately sends a CHANNEL_OPEN, it otherwise
|
||||
// follows SERVER_VERSION with an Initiate representing a new channel
|
||||
optional bytes previous_channel_contract_hash = 3;
|
||||
|
||||
// How many seconds should the channel be open, only used when a new channel is created.
|
||||
// Defaults to 24 h minus 60 seconds, 24*60*60 - 60
|
||||
optional uint64 time_window_secs = 4 [default = 86340];
|
||||
}
|
||||
|
||||
// Send by secondary to primary upon receiving the ClientVersion message. If it is willing to
|
||||
// speak the given major version, it sends back the same major version and the minor version it
|
||||
// speaks. If it is not, it may send back a lower major version representing the highest version
|
||||
// it is willing to speak, or sends a NO_ACCEPTABLE_VERSION Error. If the secondary sends back a
|
||||
// lower major version, the secondary should either expect to continue with that version, or
|
||||
// should immediately close the connection with a NO_ACCEPTABLE_VERSION Error. Backwards
|
||||
// incompatible changes to the protocol bump the major version. Extensions bump the minor version
|
||||
message ServerVersion {
|
||||
required int32 major = 1;
|
||||
optional int32 minor = 2 [default = 0];
|
||||
}
|
||||
|
||||
// Sent from server to client once version nego is done.
|
||||
message Initiate {
|
||||
// This must be a raw pubkey in regular ECDSA form. Both compressed and non-compressed forms
|
||||
// are accepted. It is used only in the creation of the multisig contract, as outputs are
|
||||
// created entirely by the secondary
|
||||
required bytes multisig_key = 1;
|
||||
|
||||
// Once a channel is exhausted a new one must be set up. So secondary indicates the minimum
|
||||
// size it's willing to accept here. This can be lower to trade off resources against
|
||||
// security but shouldn't be so low the transactions get rejected by the network as spam.
|
||||
// Zero isn't a sensible value to have here, so we make the field required.
|
||||
required uint64 min_accepted_channel_size = 2;
|
||||
|
||||
// Rough UNIX time for when the channel expires. This is determined by the block header
|
||||
// timestamps which can be very inaccurate when miners use the obsolete RollNTime hack.
|
||||
// Channels could also be specified in terms of block heights but then how do you know the
|
||||
// current chain height if you don't have internet access? Trust the server? Probably opens up
|
||||
// attack vectors. We can assume the client has an independent clock, however. If the client
|
||||
// considers this value too far off (eg more than a day), it may send an ERROR and close the
|
||||
// channel.
|
||||
required uint64 expire_time_secs = 3;
|
||||
|
||||
// The amount of money the server requires for the initial payment. The act of opening a channel
|
||||
// always transfers some quantity of money to the server: it's impossible to have a channel with
|
||||
// zero value transferred. This rule ensures that you can't get a channel that can't be settled
|
||||
// due to having paid under the dust limit. Because the dust limit will float in future, the
|
||||
// server tells the client what it thinks it is, and the client is supposed to sanity check this
|
||||
// value.
|
||||
required uint64 min_payment = 4;
|
||||
}
|
||||
|
||||
// Sent from primary to secondary after Initiate to begin the refund transaction signing.
|
||||
message ProvideRefund {
|
||||
// This must be a raw pubkey in regular ECDSA form. Both compressed and non-compressed forms
|
||||
// are accepted. It is only used in the creation of the multisig contract.
|
||||
required bytes multisig_key = 1;
|
||||
|
||||
// The serialized bytes of the return transaction in Satoshi format.
|
||||
// * It must have exactly one input which spends the multisig output (see ProvideContract for
|
||||
// details of exactly what that output must look like). This output must have a sequence
|
||||
// number of 0.
|
||||
// * It must have the lock time set to a time after the min_time_window_secs (from the
|
||||
// Initiate message).
|
||||
// * It must have exactly one output which goes back to the primary. This output's
|
||||
// scriptPubKey will be reused to create payment transactions.
|
||||
required bytes tx = 2;
|
||||
}
|
||||
|
||||
// Sent from secondary to primary after it has done initial verification of the refund
|
||||
// transaction. Contains the primary's signature which is required to spend the multisig contract
|
||||
// to the refund transaction. Must be signed using SIGHASH_NONE|SIGHASH_ANYONECANPAY (and include
|
||||
// the postfix type byte) to allow the client to add any outputs/inputs it wants as long as the
|
||||
// input's sequence and transaction's nLockTime remain set.
|
||||
message ReturnRefund {
|
||||
required bytes signature = 1;
|
||||
}
|
||||
|
||||
// Sent from the primary to the secondary to complete initialization.
|
||||
message ProvideContract {
|
||||
// The serialized bytes of the transaction in Satoshi format.
|
||||
// * It must be signed and completely valid and ready for broadcast (ie it includes the
|
||||
// necessary fees) TODO: tell the client how much fee it needs
|
||||
// * Its first output must be a 2-of-2 multisig output with the first pubkey being the
|
||||
// primary's and the second being the secondary's (ie the script must be exactly "OP_2
|
||||
// ProvideRefund.multisig_key Initiate.multisig_key OP_2 OP_CHECKMULTISIG")
|
||||
required bytes tx = 1;
|
||||
|
||||
// To open the channel, an initial payment of the server-specified dust limit value must be
|
||||
// provided. This ensures that the channel is never in an un-settleable state due to either
|
||||
// no payment tx having been provided at all, or a payment that is smaller than the dust
|
||||
// limit being provided.
|
||||
required UpdatePayment initial_payment = 2;
|
||||
}
|
||||
|
||||
// This message can only be used by the primary after it has received a CHANNEL_OPEN message. It
|
||||
// creates a new payment transaction. Note that we don't resubmit the entire TX, this is to avoid
|
||||
// (re)parsing bugs and overhead. The payment transaction is created by the primary by:
|
||||
// * Adding an input which spends the multisig contract
|
||||
// * Setting this input's scriptSig to the given signature and a new signature created by the
|
||||
// primary (the primary should ensure the signature provided correctly spends the multisig
|
||||
// contract)
|
||||
// * Adding an output who's scriptPubKey is the same as the refund output (the only output) in
|
||||
// the refund transaction
|
||||
// * Setting this output's value to client_change_value (which must be lower than the most recent
|
||||
// client_change_value and lower than the multisig contract's output value)
|
||||
// * Adding any number of additional outputs as desired (leaving sufficient fee, if necessary)
|
||||
// * Adding any number of additional inputs as desired (eg to add more fee)
|
||||
message UpdatePayment {
|
||||
// The value which is sent back to the primary. The rest of the multisig output is left for
|
||||
// the secondary to do with as they wish.
|
||||
required uint64 client_change_value = 1;
|
||||
// A SIGHASH_SINGLE|SIGHASH_ANYONECANPAY signature (including the postfix type byte) which
|
||||
// spends the primary's part of the multisig contract's output. This signature only covers
|
||||
// the primary's refund output and thus the secondary is free to do what they wish with their
|
||||
// part of the multisig output.
|
||||
required bytes signature = 2;
|
||||
// Information about this update. Used to extend this protocol.
|
||||
optional bytes info = 3;
|
||||
|
||||
}
|
||||
|
||||
// This message is sent as an acknowledgement of an UpdatePayment message
|
||||
message PaymentAck {
|
||||
// Information about this update. Used to extend this protocol
|
||||
optional bytes info = 1;
|
||||
}
|
||||
|
||||
message Settlement {
|
||||
// A copy of the fully signed final contract that settles the channel. The client can verify
|
||||
// the transaction is correct and then commit it to their wallet.
|
||||
required bytes tx = 3;
|
||||
}
|
||||
|
||||
// An Error can be sent by either party at any time
|
||||
// Both parties should make an effort to send either an ERROR or a CLOSE immediately before
|
||||
// closing the socket (unless they just received an ERROR or a CLOSE)
|
||||
message Error {
|
||||
enum ErrorCode {
|
||||
TIMEOUT = 1; // Protocol timeout occurred (one party hung).
|
||||
SYNTAX_ERROR = 2; // Generic error indicating some message was not properly
|
||||
// formatted or was out of order.
|
||||
NO_ACCEPTABLE_VERSION = 3; // We don't speak the version the other side asked for.
|
||||
BAD_TRANSACTION = 4; // A provided transaction was not in the proper structure
|
||||
// (wrong inputs/outputs, sequence, lock time, signature,
|
||||
// etc)
|
||||
TIME_WINDOW_UNACCEPTABLE = 5; // The expire time specified by the secondary was unacceptable
|
||||
// for the primary
|
||||
CHANNEL_VALUE_TOO_LARGE = 6; // The minimum channel value specified by the secondary was
|
||||
// too large for the primary
|
||||
MIN_PAYMENT_TOO_LARGE = 7; // The min "dust limit" specified by the server was too large for the client.
|
||||
|
||||
OTHER = 8;
|
||||
};
|
||||
optional ErrorCode code = 1 [default=OTHER];
|
||||
optional string explanation = 2; // NOT SAFE FOR HTML WITHOUT ESCAPING
|
||||
|
||||
// Can be set by the client when erroring to the server if a value was out of range. Can help with debugging.
|
||||
optional uint64 expected_value = 3;
|
||||
}
|
||||
70
src/paymentrequest.proto
Normal file
70
src/paymentrequest.proto
Normal file
@@ -0,0 +1,70 @@
|
||||
/** 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Authors: Mike Hearn, Gavin Andresen
|
||||
*/
|
||||
|
||||
/* Notes:
|
||||
* - Endianness: All byte arrays that represent numbers (such as hashes and private keys) are Big Endian
|
||||
* - To regenerate after editing, run mvn clean package -DupdateProtobuf
|
||||
*/
|
||||
|
||||
//
|
||||
// Simple Bitcoin Payment Protocol messages
|
||||
//
|
||||
// Use fields 100+ for extensions;
|
||||
// to avoid conflicts, register extensions at:
|
||||
// https://en.bitcoin.it/wiki/Payment_Request
|
||||
//
|
||||
|
||||
package payments;
|
||||
option java_package = "org.bitcoin.protocols.payments";
|
||||
option java_outer_classname = "Protos";
|
||||
|
||||
// Generalized form of "send payment to this/these bitcoin addresses"
|
||||
message Output {
|
||||
optional uint64 amount = 1 [default = 0]; // amount is integer-number-of-satoshis
|
||||
required bytes script = 2; // usually one of the standard Script forms
|
||||
}
|
||||
message PaymentDetails {
|
||||
optional string network = 1 [default = "main"]; // "main" or "test"
|
||||
repeated Output outputs = 2; // Where payment should be sent
|
||||
required uint64 time = 3; // Timestamp; when payment request created
|
||||
optional uint64 expires = 4; // Timestamp; when this request should be considered invalid
|
||||
optional string memo = 5; // Human-readable description of request for the customer
|
||||
optional string payment_url = 6; // URL to send Payment and get PaymentACK
|
||||
optional bytes merchant_data = 7; // Arbitrary data to include in the Payment message
|
||||
}
|
||||
message PaymentRequest {
|
||||
optional uint32 payment_details_version = 1 [default = 1];
|
||||
optional string pki_type = 2 [default = "none"]; // none / x509+sha256 / x509+sha1
|
||||
optional bytes pki_data = 3; // depends on pki_type
|
||||
required bytes serialized_payment_details = 4; // PaymentDetails
|
||||
optional bytes signature = 5; // pki-dependent signature
|
||||
}
|
||||
message X509Certificates {
|
||||
repeated bytes certificate = 1; // DER-encoded X.509 certificate chain
|
||||
}
|
||||
message Payment {
|
||||
optional bytes merchant_data = 1; // From PaymentDetails.merchant_data
|
||||
repeated bytes transactions = 2; // Signed transactions that satisfy PaymentDetails.outputs
|
||||
repeated Output refund_to = 3; // Where to send refunds, if a refund is necessary
|
||||
optional string memo = 4; // Human-readable message for the merchant
|
||||
}
|
||||
message PaymentACK {
|
||||
required Payment payment = 1; // Payment message that triggered this ACK
|
||||
optional string memo = 2; // human-readable message for customer
|
||||
}
|
||||
26
src/peerseeds.proto
Normal file
26
src/peerseeds.proto
Normal file
@@ -0,0 +1,26 @@
|
||||
package org.bitcoin.crawler;
|
||||
|
||||
//
|
||||
// A simple protocol for describing signed sets of IP addresses. Intended to be distributed via HTTP[S] or in files.
|
||||
//
|
||||
|
||||
option java_package = "org.bitcoin.crawler";
|
||||
option java_outer_classname = "PeerSeedProtos";
|
||||
|
||||
message PeerSeedData {
|
||||
required string ip_address = 1;
|
||||
required uint32 port = 2;
|
||||
required uint32 services = 3;
|
||||
}
|
||||
|
||||
message PeerSeeds {
|
||||
repeated PeerSeedData seed = 1;
|
||||
required uint64 timestamp = 2; // seconds since UNIX epoch
|
||||
required string net = 3;
|
||||
}
|
||||
|
||||
message SignedPeerSeeds {
|
||||
required bytes peer_seeds = 1;
|
||||
required bytes signature = 2;
|
||||
required bytes pubkey = 3;
|
||||
}
|
||||
51
src/storedclientpaymentchannel.proto
Normal file
51
src/storedclientpaymentchannel.proto
Normal file
@@ -0,0 +1,51 @@
|
||||
/** 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Authors: Mike Hearn, Matt Corallo
|
||||
*/
|
||||
|
||||
/* Notes:
|
||||
* - Endianness: All byte arrays that represent numbers (such as hashes and private keys) are Big Endian
|
||||
* - To regenerate after editing, run mvn clean package -DupdateProtobuf
|
||||
*/
|
||||
|
||||
package paymentchannels;
|
||||
|
||||
option java_package = "com.dogecoin.dogecoinj.protocols.channels";
|
||||
option java_outer_classname = "ClientState";
|
||||
|
||||
|
||||
// A set of StoredPaymentChannel's
|
||||
message StoredClientPaymentChannels {
|
||||
repeated StoredClientPaymentChannel channels = 1;
|
||||
}
|
||||
|
||||
// A client-side payment channel in serialized form, which can be reloaded later if the client restarts and wants to
|
||||
// reopen an existing channel
|
||||
message StoredClientPaymentChannel {
|
||||
required bytes id = 1;
|
||||
required bytes contractTransaction = 2;
|
||||
required bytes refundTransaction = 3;
|
||||
required bytes myPublicKey = 8;
|
||||
// Deprecated, key is already stored in the wallet, and found using myPublicKey;
|
||||
required bytes myKey = 4;
|
||||
required uint64 valueToMe = 5;
|
||||
required uint64 refundFees = 6;
|
||||
// When set, the hash of the transaction that was presented by the server for closure of the channel.
|
||||
// It spends the contractTransaction and is expected to be broadcast to the network by the server.
|
||||
// It's supposed to be in the wallet already.
|
||||
optional bytes closeTransactionHash = 7;
|
||||
}
|
||||
44
src/storedserverpaymentchannel.proto
Normal file
44
src/storedserverpaymentchannel.proto
Normal file
@@ -0,0 +1,44 @@
|
||||
/** 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Authors: Mike Hearn, Matt Corallo
|
||||
*/
|
||||
|
||||
/* Notes:
|
||||
* - Endianness: All byte arrays that represent numbers (such as hashes and private keys) are Big Endian
|
||||
* - To regenerate after editing, run mvn clean package -DupdateProtobuf
|
||||
*/
|
||||
|
||||
package paymentchannels;
|
||||
|
||||
option java_package = "com.dogecoin.dogecoinj.protocols.channels";
|
||||
option java_outer_classname = "ServerState";
|
||||
|
||||
|
||||
// A set of StoredPaymentChannel's
|
||||
message StoredServerPaymentChannels {
|
||||
repeated StoredServerPaymentChannel channels = 1;
|
||||
}
|
||||
|
||||
// A server-side payment channel in serialized form, which can be reloaded later if the server restarts
|
||||
message StoredServerPaymentChannel {
|
||||
required uint64 bestValueToMe = 1;
|
||||
optional bytes bestValueSignature = 2;
|
||||
required uint64 refundTransactionUnlockTimeSecs = 3;
|
||||
required bytes contractTransaction = 4;
|
||||
required bytes clientOutput = 5;
|
||||
required bytes myKey = 6;
|
||||
}
|
||||
228
src/test/java/org/altcoinj/core/AddressTest.java
Normal file
228
src/test/java/org/altcoinj/core/AddressTest.java
Normal file
@@ -0,0 +1,228 @@
|
||||
/**
|
||||
* 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.MainNetParams;
|
||||
import com.dogecoin.dogecoinj.params.Networks;
|
||||
import com.dogecoin.dogecoinj.params.TestNet3Params;
|
||||
import com.dogecoin.dogecoinj.script.Script;
|
||||
import com.dogecoin.dogecoinj.script.ScriptBuilder;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static com.dogecoin.dogecoinj.core.Utils.HEX;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class AddressTest {
|
||||
static final NetworkParameters testParams = TestNet3Params.get();
|
||||
static final NetworkParameters mainParams = MainNetParams.get();
|
||||
|
||||
@Test
|
||||
public void stringification() throws Exception {
|
||||
// Test a testnet address.
|
||||
Address a = new Address(testParams, HEX.decode("8e34b02b3c2552791c2151394a1958fe8d40348d"));
|
||||
assertEquals("nhA5LMB3mtmVf1xNsHnoGakmFyq1fuzyb7", a.toString());
|
||||
assertFalse(a.isP2SHAddress());
|
||||
|
||||
Address b = new Address(mainParams, HEX.decode("6bf21708a0ee6cabde2f3bec6f7880c29b1b1d7e"));
|
||||
assertEquals("DEyrrVQspH26SS2wjfZdFT579NLBto1x64", b.toString());
|
||||
assertFalse(b.isP2SHAddress());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decoding() throws Exception {
|
||||
Address a = new Address(testParams, "nhA5LMB3mtmVf1xNsHnoGakmFyq1fuzyb7");
|
||||
assertEquals("8e34b02b3c2552791c2151394a1958fe8d40348d", Utils.HEX.encode(a.getHash160()));
|
||||
|
||||
Address b = new Address(mainParams, "DEyrrVQspH26SS2wjfZdFT579NLBto1x64");
|
||||
assertEquals("6bf21708a0ee6cabde2f3bec6f7880c29b1b1d7e", Utils.HEX.encode(b.getHash160()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void errorPaths() {
|
||||
// Check what happens if we try and decode garbage.
|
||||
try {
|
||||
new Address(testParams, "this is not a valid address!");
|
||||
fail();
|
||||
} catch (WrongNetworkException e) {
|
||||
fail();
|
||||
} catch (AddressFormatException e) {
|
||||
// Success.
|
||||
}
|
||||
|
||||
// Check the empty case.
|
||||
try {
|
||||
new Address(testParams, "");
|
||||
fail();
|
||||
} catch (WrongNetworkException e) {
|
||||
fail();
|
||||
} catch (AddressFormatException e) {
|
||||
// Success.
|
||||
}
|
||||
|
||||
// Check the case of a mismatched network.
|
||||
try {
|
||||
new Address(testParams, "DEyrrVQspH26SS2wjfZdFT579NLBto1x64");
|
||||
fail();
|
||||
} catch (WrongNetworkException e) {
|
||||
// Success.
|
||||
assertEquals(e.verCode, MainNetParams.get().getAddressHeader());
|
||||
assertTrue(Arrays.equals(e.acceptableVersions, TestNet3Params.get().getAcceptableAddressCodes()));
|
||||
} catch (AddressFormatException e) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNetwork() throws Exception {
|
||||
NetworkParameters params = Address.getParametersFromAddress("DEyrrVQspH26SS2wjfZdFT579NLBto1x64");
|
||||
assertEquals(MainNetParams.get().getId(), params.getId());
|
||||
params = Address.getParametersFromAddress("nhA5LMB3mtmVf1xNsHnoGakmFyq1fuzyb7");
|
||||
assertEquals(TestNet3Params.get().getId(), params.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAltNetwork() throws Exception {
|
||||
// An alternative network
|
||||
class AltNetwork extends MainNetParams {
|
||||
AltNetwork() {
|
||||
super();
|
||||
id = "alt.network";
|
||||
addressHeader = 48;
|
||||
p2shHeader = 5;
|
||||
acceptableAddressCodes = new int[] { addressHeader, p2shHeader };
|
||||
}
|
||||
}
|
||||
AltNetwork altNetwork = new AltNetwork();
|
||||
// Add new network params
|
||||
Networks.register(altNetwork);
|
||||
// Check if can parse address
|
||||
NetworkParameters params = Address.getParametersFromAddress("LLxSnHLN2CYyzB5eWTR9K9rS9uWtbTQFb6");
|
||||
assertEquals(altNetwork.getId(), params.getId());
|
||||
// Check if main network works as before
|
||||
params = Address.getParametersFromAddress("DEyrrVQspH26SS2wjfZdFT579NLBto1x64");
|
||||
assertEquals(MainNetParams.get().getId(), params.getId());
|
||||
// Unregister network
|
||||
Networks.unregister(altNetwork);
|
||||
try {
|
||||
Address.getParametersFromAddress("LLxSnHLN2CYyzB5eWTR9K9rS9uWtbTQFb6");
|
||||
fail();
|
||||
} catch (AddressFormatException e) { }
|
||||
}
|
||||
|
||||
@Test
|
||||
public void p2shAddress() throws Exception {
|
||||
// Test that we can construct P2SH addresses
|
||||
Address mainNetP2SHAddress = new Address(MainNetParams.get(), "9wWHL91mYrdiBEw9uHuBtS42in2XqWKrRY");
|
||||
assertEquals(mainNetP2SHAddress.version, MainNetParams.get().p2shHeader);
|
||||
assertTrue(mainNetP2SHAddress.isP2SHAddress());
|
||||
Address testNetP2SHAddress = new Address(TestNet3Params.get(), "2N8jyJyivK4trjisMYPHyMsdnTyWVDTWxaL");
|
||||
assertEquals(testNetP2SHAddress.version, TestNet3Params.get().p2shHeader);
|
||||
assertTrue(testNetP2SHAddress.isP2SHAddress());
|
||||
|
||||
// Test that we can determine what network a P2SH address belongs to
|
||||
NetworkParameters mainNetParams = Address.getParametersFromAddress("9wWHL91mYrdiBEw9uHuBtS42in2XqWKrRY");
|
||||
assertEquals(MainNetParams.get().getId(), mainNetParams.getId());
|
||||
NetworkParameters testNetParams = Address.getParametersFromAddress("2N8jyJyivK4trjisMYPHyMsdnTyWVDTWxaL");
|
||||
assertEquals(TestNet3Params.get().getId(), testNetParams.getId());
|
||||
|
||||
// Test that we can convert them from hashes
|
||||
byte[] hex = HEX.decode("379ad9b7ba73bdc1e29e286e014d4e2e1f6884e3");
|
||||
Address a = Address.fromP2SHHash(mainParams, hex);
|
||||
assertEquals("9wWHL91mYrdiBEw9uHuBtS42in2XqWKrRY", a.toString());
|
||||
Address b = Address.fromP2SHHash(testParams, HEX.decode("a9f9b28507bbe69c13eaed4f880bb22d17450b56"));
|
||||
assertEquals("2N8jyJyivK4trjisMYPHyMsdnTyWVDTWxaL", b.toString());
|
||||
Address c = Address.fromP2SHScript(mainParams, ScriptBuilder.createP2SHOutputScript(hex));
|
||||
assertEquals("9wWHL91mYrdiBEw9uHuBtS42in2XqWKrRY", c.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void p2shAddressCreationFromKeys() throws Exception {
|
||||
// import some keys from this example: https://gist.github.com/gavinandresen/3966071
|
||||
ECKey key1 = new DumpedPrivateKey(mainParams, "QVUd4dwqxqePZgBaC6ny5rHvNHu6CoT8t1sTTPnF5RfFAjtKjTQH").getKey();
|
||||
key1 = ECKey.fromPrivate(key1.getPrivKeyBytes());
|
||||
ECKey key2 = new DumpedPrivateKey(mainParams, "QTZSzo8RphsaJFiEJAEvjvRqqP9MVyWpT1ns9hVRij4nXTE3XTzP").getKey();
|
||||
key2 = ECKey.fromPrivate(key2.getPrivKeyBytes());
|
||||
ECKey key3 = new DumpedPrivateKey(mainParams, "QS2YZKyPB6nDH7WnMuT4YKwLQwZQ3vN2FCPTwTCeyUNSKeRyPgRk").getKey();
|
||||
key3 = ECKey.fromPrivate(key3.getPrivKeyBytes());
|
||||
|
||||
List<ECKey> keys = Arrays.asList(key1, key2, key3);
|
||||
Script p2shScript = ScriptBuilder.createP2SHOutputScript(2, keys);
|
||||
Address address = Address.fromP2SHScript(mainParams, p2shScript);
|
||||
assertEquals("ACdJj7YT7dJkV6bv6cRenUMCTDQxSdZSo5", address.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cloning() throws Exception {
|
||||
Address a = new Address(testParams, HEX.decode("fda79a24e50ff70ff42f7d89585da5bd19d9e5cc"));
|
||||
Address b = a.clone();
|
||||
|
||||
assertEquals(a, b);
|
||||
assertNotSame(a, b);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void comparisonCloneEqualTo() throws Exception {
|
||||
Address a = new Address(mainParams, "1Dorian4RoXcnBv9hnQ4Y2C1an6NJ4UrjX");
|
||||
Address b = a.clone();
|
||||
|
||||
int result = a.compareTo(b);
|
||||
assertEquals(0, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void comparisonEqualTo() throws Exception {
|
||||
Address a = new Address(mainParams, "1Dorian4RoXcnBv9hnQ4Y2C1an6NJ4UrjX");
|
||||
Address b = a.clone();
|
||||
|
||||
int result = a.compareTo(b);
|
||||
assertEquals(0, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void comparisonLessThan() throws Exception {
|
||||
Address a = new Address(mainParams, "1Dorian4RoXcnBv9hnQ4Y2C1an6NJ4UrjX");
|
||||
Address b = new Address(mainParams, "1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P");
|
||||
|
||||
int result = a.compareTo(b);
|
||||
assertTrue(result < 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void comparisonGreaterThan() throws Exception {
|
||||
Address a = new Address(mainParams, "1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P");
|
||||
Address b = new Address(mainParams, "1Dorian4RoXcnBv9hnQ4Y2C1an6NJ4UrjX");
|
||||
|
||||
int result = a.compareTo(b);
|
||||
assertTrue(result > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void comparisonBytesVsString() throws Exception {
|
||||
// TODO: To properly test this we need a much larger data set
|
||||
Address a = new Address(mainParams, "1Dorian4RoXcnBv9hnQ4Y2C1an6NJ4UrjX");
|
||||
Address b = new Address(mainParams, "1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P");
|
||||
|
||||
int resultBytes = a.compareTo(b);
|
||||
int resultsString = a.toString().compareTo(b.toString());
|
||||
assertTrue( resultBytes < 0 );
|
||||
assertTrue( resultsString < 0 );
|
||||
}
|
||||
}
|
||||
50
src/test/java/org/altcoinj/core/AuxPoWTest.java
Normal file
50
src/test/java/org/altcoinj/core/AuxPoWTest.java
Normal file
@@ -0,0 +1,50 @@
|
||||
package org.bitcoinj.core;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
import org.bitcoinj.params.TestNet3Params;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.bitcoinj.core.CoinbaseBlockTest.getBytes;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* AuxPoW header parsing/serialization and validation
|
||||
*/
|
||||
public class AuxPoWTest {
|
||||
static final NetworkParameters params = TestNet3Params.get();
|
||||
|
||||
/**
|
||||
* Parse the AuxPoW header from Dogecoin block #403,931.
|
||||
*/
|
||||
@Test
|
||||
public void parseAuxPoWHeader() throws Exception {
|
||||
byte[] auxpowAsBytes = getBytes(getClass().getResourceAsStream("auxpow_header.bin"));
|
||||
AuxPoW auxpow = new AuxPoW(params, auxpowAsBytes, (ChildMessage) null, false, false);
|
||||
MerkleBranch branch = auxpow.getCoinbaseBranch();
|
||||
Sha256Hash expected = new Sha256Hash("089b911f5e471c0e1800f3384281ebec5b372fbb6f358790a92747ade271ccdf");
|
||||
|
||||
assertEquals(expected, auxpow.getCoinbase().getHash());
|
||||
assertEquals(3, auxpow.getCoinbaseBranch().getSize());
|
||||
assertEquals(6, auxpow.getBlockchainBranch().getSize());
|
||||
|
||||
expected = new Sha256Hash("a22a9b01671d639fa6389f62ecf8ce69204c8ed41d5f1a745e0c5ba7116d5b4c");
|
||||
assertEquals(expected, auxpow.getParentBlockHeader().getHash());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test serializing the AuxPoW header from Dogecoin block #403,931.
|
||||
*/
|
||||
@Test
|
||||
public void serializeAuxPoWHeader() throws Exception {
|
||||
byte[] auxpowAsBytes = getBytes(getClass().getResourceAsStream("auxpow_header.bin"));
|
||||
AuxPoW auxpow = new AuxPoW(params, auxpowAsBytes, (ChildMessage) null, false, false);
|
||||
byte[] expected = auxpowAsBytes;
|
||||
byte[] actual = auxpow.bitcoinSerialize();
|
||||
|
||||
assertArrayEquals(expected, actual);
|
||||
}
|
||||
}
|
||||
53
src/test/java/org/altcoinj/core/DumpedPrivateKeyTest.java
Normal file
53
src/test/java/org/altcoinj/core/DumpedPrivateKeyTest.java
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.dogecoin.dogecoinj.params.MainNetParams;
|
||||
|
||||
public class DumpedPrivateKeyTest {
|
||||
@Test
|
||||
public void testJavaSerialization() throws Exception {
|
||||
|
||||
DumpedPrivateKey key = new DumpedPrivateKey(MainNetParams.get(), new ECKey().getPrivKeyBytes(), true);
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
new ObjectOutputStream(os).writeObject(key);
|
||||
DumpedPrivateKey keyCopy = (DumpedPrivateKey) new ObjectInputStream(new ByteArrayInputStream(os.toByteArray()))
|
||||
.readObject();
|
||||
assertEquals(key, keyCopy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cloning() throws Exception {
|
||||
DumpedPrivateKey a = new DumpedPrivateKey(MainNetParams.get(), new ECKey().getPrivKeyBytes(), true);
|
||||
// TODO: Consider overriding clone() in DumpedPrivateKey to narrow the type
|
||||
DumpedPrivateKey b = (DumpedPrivateKey) a.clone();
|
||||
|
||||
assertEquals(a, b);
|
||||
assertNotSame(a, b);
|
||||
}
|
||||
|
||||
}
|
||||
62
src/test/java/org/altcoinj/core/MerkleBranchTest.java
Normal file
62
src/test/java/org/altcoinj/core/MerkleBranchTest.java
Normal file
@@ -0,0 +1,62 @@
|
||||
package org.bitcoinj.core;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
import org.bitcoinj.params.TestNet3Params;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.bitcoinj.core.CoinbaseBlockTest.getBytes;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Check merkle branch parsing and root calculation.
|
||||
*/
|
||||
public class MerkleBranchTest {
|
||||
static final NetworkParameters params = TestNet3Params.get();
|
||||
|
||||
/**
|
||||
* Parse the coinbase merkle branch from Dogecoin block #403,931.
|
||||
*/
|
||||
@Test
|
||||
public void parseMerkleBranch() throws Exception {
|
||||
byte[] branchAsBytes = getBytes(getClass().getResourceAsStream("auxpow_merkle_branch.bin"));
|
||||
MerkleBranch branch = new MerkleBranch(params, (ChildMessage) null, branchAsBytes, 0);
|
||||
Sha256Hash[] expected = new Sha256Hash[] {
|
||||
new Sha256Hash("be079078869399faccaa764c10e9df6e9981701759ad18e13724d9ca58831348"),
|
||||
new Sha256Hash("5f5bfb2c79541778499cab956a103887147f2ab5d4a717f32f9eeebd29e1f894"),
|
||||
new Sha256Hash("d8c6fe42ca25076159cd121a5e20c48c1bc53ab90730083e44a334566ea6bbcb")
|
||||
};
|
||||
|
||||
assertArrayEquals(expected, branch.getHashes().toArray(new Sha256Hash[branch.getSize()]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the transaction merkle branch from Dogecoin block #403,931, then
|
||||
* serialize it back again to verify serialization works.
|
||||
*/
|
||||
@Test
|
||||
public void serializeMerkleBranch() throws Exception {
|
||||
byte[] expected = getBytes(getClass().getResourceAsStream("auxpow_merkle_branch.bin"));
|
||||
MerkleBranch branch = new MerkleBranch(params, (ChildMessage) null, expected, 0,
|
||||
false, false);
|
||||
byte[] actual = branch.bitcoinSerialize();
|
||||
|
||||
assertArrayEquals(expected, actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the AuxPoW merkle branch root from Dogecoin block #403,931.
|
||||
*/
|
||||
@Test
|
||||
public void calculateRootBranch() throws Exception {
|
||||
byte[] branchAsBytes = getBytes(getClass().getResourceAsStream("auxpow_merkle_branch2.bin"));
|
||||
MerkleBranch branch = new MerkleBranch(params, (ChildMessage) null, branchAsBytes, 0);
|
||||
Sha256Hash txId = new Sha256Hash("0c836b86991631d34a8a68054e2f62db919b39d1ee43c27ab3344d6aa82fa609");
|
||||
Sha256Hash expected = new Sha256Hash("ce3040fdb7e37484f6a1ca4f8f5da81e6b7e404ec91102315a233e03a0c39c95");
|
||||
|
||||
assertEquals(expected, branch.calculateMerkleRoot(txId));
|
||||
}
|
||||
}
|
||||
853
src/test/java/org/altcoinj/core/PeerGroupTest.java
Normal file
853
src/test/java/org/altcoinj/core/PeerGroupTest.java
Normal file
@@ -0,0 +1,853 @@
|
||||
/*
|
||||
* 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.net.discovery.PeerDiscovery;
|
||||
import com.dogecoin.dogecoinj.net.discovery.PeerDiscoveryException;
|
||||
import com.dogecoin.dogecoinj.params.UnitTestParams;
|
||||
import com.dogecoin.dogecoinj.testing.FakeTxBuilder;
|
||||
import com.dogecoin.dogecoinj.testing.InboundMessageQueuer;
|
||||
import com.dogecoin.dogecoinj.testing.TestWithPeerGroup;
|
||||
import com.dogecoin.dogecoinj.utils.Threading;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.net.InetAddresses;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.SettableFuture;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.BindException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static com.dogecoin.dogecoinj.core.Coin.COIN;
|
||||
import static com.dogecoin.dogecoinj.core.Coin.valueOf;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
||||
// TX announcement and broadcast is tested in TransactionBroadcastTest.
|
||||
|
||||
@RunWith(value = Parameterized.class)
|
||||
public class PeerGroupTest extends TestWithPeerGroup {
|
||||
static final NetworkParameters params = UnitTestParams.get();
|
||||
private BlockingQueue<Peer> connectedPeers;
|
||||
private BlockingQueue<Peer> disconnectedPeers;
|
||||
private PeerEventListener listener;
|
||||
private Map<Peer, AtomicInteger> peerToMessageCount;
|
||||
|
||||
@Parameterized.Parameters
|
||||
public static Collection<ClientType[]> parameters() {
|
||||
return Arrays.asList(new ClientType[] {ClientType.NIO_CLIENT_MANAGER},
|
||||
new ClientType[] {ClientType.BLOCKING_CLIENT_MANAGER});
|
||||
}
|
||||
|
||||
public PeerGroupTest(ClientType clientType) {
|
||||
super(clientType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
peerToMessageCount = new HashMap<Peer, AtomicInteger>();
|
||||
connectedPeers = new LinkedBlockingQueue<Peer>();
|
||||
disconnectedPeers = new LinkedBlockingQueue<Peer>();
|
||||
listener = new AbstractPeerEventListener() {
|
||||
@Override
|
||||
public void onPeerConnected(Peer peer, int peerCount) {
|
||||
connectedPeers.add(peer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPeerDisconnected(Peer peer, int peerCount) {
|
||||
disconnectedPeers.add(peer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message onPreMessageReceived(Peer peer, Message m) {
|
||||
AtomicInteger messageCount = peerToMessageCount.get(peer);
|
||||
if (messageCount == null) {
|
||||
messageCount = new AtomicInteger(0);
|
||||
peerToMessageCount.put(peer, messageCount);
|
||||
}
|
||||
messageCount.incrementAndGet();
|
||||
// Just pass the message right through for further processing.
|
||||
return m;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() {
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listener() throws Exception {
|
||||
peerGroup.start();
|
||||
peerGroup.addEventListener(listener);
|
||||
|
||||
// Create a couple of peers.
|
||||
InboundMessageQueuer p1 = connectPeer(1);
|
||||
InboundMessageQueuer p2 = connectPeer(2);
|
||||
connectedPeers.take();
|
||||
connectedPeers.take();
|
||||
|
||||
pingAndWait(p1);
|
||||
pingAndWait(p2);
|
||||
Threading.waitForUserCode();
|
||||
assertEquals(0, disconnectedPeers.size());
|
||||
|
||||
p1.close();
|
||||
disconnectedPeers.take();
|
||||
assertEquals(0, disconnectedPeers.size());
|
||||
p2.close();
|
||||
disconnectedPeers.take();
|
||||
assertEquals(0, disconnectedPeers.size());
|
||||
|
||||
assertTrue(peerGroup.removeEventListener(listener));
|
||||
assertFalse(peerGroup.removeEventListener(listener));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void peerDiscoveryPolling() throws InterruptedException {
|
||||
// Check that if peer discovery fails, we keep trying until we have some nodes to talk with.
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final AtomicBoolean result = new AtomicBoolean();
|
||||
peerGroup.addPeerDiscovery(new PeerDiscovery() {
|
||||
@Override
|
||||
public InetSocketAddress[] getPeers(long unused, TimeUnit unused2) throws PeerDiscoveryException {
|
||||
if (!result.getAndSet(true)) {
|
||||
// Pretend we are not connected to the internet.
|
||||
throw new PeerDiscoveryException("test failure");
|
||||
} else {
|
||||
// Return a bogus address.
|
||||
latch.countDown();
|
||||
return new InetSocketAddress[]{new InetSocketAddress("localhost", 1)};
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
}
|
||||
});
|
||||
peerGroup.start();
|
||||
latch.await();
|
||||
// Check that we did indeed throw an exception. If we got here it means we threw and then PeerGroup tried
|
||||
// again a bit later.
|
||||
assertTrue(result.get());
|
||||
}
|
||||
|
||||
// Utility method to create a PeerDiscovery with a certain number of addresses.
|
||||
private PeerDiscovery createPeerDiscovery(int nrOfAddressesWanted, int port) {
|
||||
final InetSocketAddress[] addresses = new InetSocketAddress[nrOfAddressesWanted];
|
||||
for (int addressNr = 0; addressNr < nrOfAddressesWanted; addressNr++) {
|
||||
// make each address unique by using the counter to increment the port.
|
||||
addresses[addressNr] = new InetSocketAddress("localhost", port + addressNr);
|
||||
}
|
||||
return new PeerDiscovery() {
|
||||
public InetSocketAddress[] getPeers(long unused, TimeUnit unused2) throws PeerDiscoveryException {
|
||||
return addresses;
|
||||
}
|
||||
public void shutdown() {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiplePeerDiscovery() throws InterruptedException {
|
||||
peerGroup.setMaxPeersToDiscoverCount(98);
|
||||
peerGroup.addPeerDiscovery(createPeerDiscovery(1, 0));
|
||||
peerGroup.addPeerDiscovery(createPeerDiscovery(2, 100));
|
||||
peerGroup.addPeerDiscovery(createPeerDiscovery(96, 200));
|
||||
peerGroup.addPeerDiscovery(createPeerDiscovery(3, 300));
|
||||
peerGroup.addPeerDiscovery(createPeerDiscovery(1, 400));
|
||||
peerGroup.addEventListener(new AbstractPeerEventListener() {
|
||||
@Override
|
||||
public void onPeersDiscovered(Set<PeerAddress> peerAddresses) {
|
||||
assertEquals(99, peerAddresses.size());
|
||||
}
|
||||
});
|
||||
peerGroup.start();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void receiveTxBroadcast() throws Exception {
|
||||
// Check that when we receive transactions on all our peers, we do the right thing.
|
||||
peerGroup.start();
|
||||
|
||||
// Create a couple of peers.
|
||||
InboundMessageQueuer p1 = connectPeer(1);
|
||||
InboundMessageQueuer p2 = connectPeer(2);
|
||||
|
||||
// Check the peer accessors.
|
||||
assertEquals(2, peerGroup.numConnectedPeers());
|
||||
Set<Peer> tmp = new HashSet<Peer>(peerGroup.getConnectedPeers());
|
||||
Set<Peer> expectedPeers = new HashSet<Peer>();
|
||||
expectedPeers.add(peerOf(p1));
|
||||
expectedPeers.add(peerOf(p2));
|
||||
assertEquals(tmp, expectedPeers);
|
||||
|
||||
Coin value = COIN;
|
||||
Transaction t1 = FakeTxBuilder.createFakeTx(unitTestParams, value, address);
|
||||
InventoryMessage inv = new InventoryMessage(unitTestParams);
|
||||
inv.addTransaction(t1);
|
||||
|
||||
// Note: we start with p2 here to verify that transactions are downloaded from whichever peer announces first
|
||||
// which does not have to be the same as the download peer (which is really the "block download peer").
|
||||
inbound(p2, inv);
|
||||
assertTrue(outbound(p2) instanceof GetDataMessage);
|
||||
inbound(p1, inv);
|
||||
assertNull(outbound(p1)); // Only one peer is used to download.
|
||||
inbound(p2, t1);
|
||||
assertNull(outbound(p1));
|
||||
// Asks for dependency.
|
||||
GetDataMessage getdata = (GetDataMessage) outbound(p2);
|
||||
assertNotNull(getdata);
|
||||
inbound(p2, new NotFoundMessage(unitTestParams, getdata.getItems()));
|
||||
pingAndWait(p2);
|
||||
assertEquals(value, wallet.getBalance(Wallet.BalanceType.ESTIMATED));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void receiveTxBroadcastOnAddedWallet() throws Exception {
|
||||
// Check that when we receive transactions on all our peers, we do the right thing.
|
||||
peerGroup.start();
|
||||
|
||||
// Create a peer.
|
||||
InboundMessageQueuer p1 = connectPeer(1);
|
||||
|
||||
Wallet wallet2 = new Wallet(unitTestParams);
|
||||
ECKey key2 = wallet2.freshReceiveKey();
|
||||
Address address2 = key2.toAddress(unitTestParams);
|
||||
|
||||
peerGroup.addWallet(wallet2);
|
||||
blockChain.addWallet(wallet2);
|
||||
|
||||
assertEquals(BloomFilter.class, waitForOutbound(p1).getClass());
|
||||
assertEquals(MemoryPoolMessage.class, waitForOutbound(p1).getClass());
|
||||
|
||||
Coin value = COIN;
|
||||
Transaction t1 = FakeTxBuilder.createFakeTx(unitTestParams, value, address2);
|
||||
InventoryMessage inv = new InventoryMessage(unitTestParams);
|
||||
inv.addTransaction(t1);
|
||||
|
||||
inbound(p1, inv);
|
||||
assertTrue(outbound(p1) instanceof GetDataMessage);
|
||||
inbound(p1, t1);
|
||||
// Asks for dependency.
|
||||
GetDataMessage getdata = (GetDataMessage) outbound(p1);
|
||||
assertNotNull(getdata);
|
||||
inbound(p1, new NotFoundMessage(unitTestParams, getdata.getItems()));
|
||||
pingAndWait(p1);
|
||||
assertEquals(value, wallet2.getBalance(Wallet.BalanceType.ESTIMATED));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleDownloadPeer1() throws Exception {
|
||||
// Check that we don't attempt to retrieve blocks on multiple peers.
|
||||
peerGroup.start();
|
||||
|
||||
// Create a couple of peers.
|
||||
InboundMessageQueuer p1 = connectPeer(1);
|
||||
InboundMessageQueuer p2 = connectPeer(2);
|
||||
assertEquals(2, peerGroup.numConnectedPeers());
|
||||
|
||||
// Set up a little block chain. We heard about b1 but not b2 (it is pending download). b3 is solved whilst we
|
||||
// are downloading the chain.
|
||||
Block b1 = FakeTxBuilder.createFakeBlock(blockStore).block;
|
||||
blockChain.add(b1);
|
||||
Block b2 = FakeTxBuilder.makeSolvedTestBlock(b1);
|
||||
Block b3 = FakeTxBuilder.makeSolvedTestBlock(b2);
|
||||
|
||||
// Peer 1 and 2 receives an inv advertising a newly solved block.
|
||||
InventoryMessage inv = new InventoryMessage(params);
|
||||
inv.addBlock(b3);
|
||||
// Only peer 1 tries to download it.
|
||||
inbound(p1, inv);
|
||||
pingAndWait(p1);
|
||||
|
||||
assertTrue(outbound(p1) instanceof GetDataMessage);
|
||||
assertNull(outbound(p2));
|
||||
// Peer 1 goes away, peer 2 becomes the download peer and thus queries the remote mempool.
|
||||
final SettableFuture<Void> p1CloseFuture = SettableFuture.create();
|
||||
peerOf(p1).addEventListener(new AbstractPeerEventListener() {
|
||||
@Override
|
||||
public void onPeerDisconnected(Peer peer, int peerCount) {
|
||||
p1CloseFuture.set(null);
|
||||
}
|
||||
});
|
||||
closePeer(peerOf(p1));
|
||||
p1CloseFuture.get();
|
||||
// Peer 2 fetches it next time it hears an inv (should it fetch immediately?).
|
||||
inbound(p2, inv);
|
||||
assertTrue(outbound(p2) instanceof GetDataMessage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleDownloadPeer2() throws Exception {
|
||||
// Check that we don't attempt multiple simultaneous block chain downloads, when adding a new peer in the
|
||||
// middle of an existing chain download.
|
||||
// Create a couple of peers.
|
||||
peerGroup.start();
|
||||
|
||||
// Create a couple of peers.
|
||||
InboundMessageQueuer p1 = connectPeer(1);
|
||||
|
||||
// Set up a little block chain.
|
||||
Block b1 = FakeTxBuilder.createFakeBlock(blockStore).block;
|
||||
Block b2 = FakeTxBuilder.makeSolvedTestBlock(b1);
|
||||
Block b3 = FakeTxBuilder.makeSolvedTestBlock(b2);
|
||||
|
||||
// Expect a zero hash getblocks on p1. This is how the process starts.
|
||||
peerGroup.startBlockChainDownload(new AbstractPeerEventListener() {
|
||||
});
|
||||
GetBlocksMessage getblocks = (GetBlocksMessage) outbound(p1);
|
||||
assertEquals(Sha256Hash.ZERO_HASH, getblocks.getStopHash());
|
||||
// We give back an inv with some blocks in it.
|
||||
InventoryMessage inv = new InventoryMessage(params);
|
||||
inv.addBlock(b1);
|
||||
inv.addBlock(b2);
|
||||
inv.addBlock(b3);
|
||||
|
||||
inbound(p1, inv);
|
||||
assertTrue(outbound(p1) instanceof GetDataMessage);
|
||||
// We hand back the first block.
|
||||
inbound(p1, b1);
|
||||
// Now we successfully connect to another peer. There should be no messages sent.
|
||||
InboundMessageQueuer p2 = connectPeer(2);
|
||||
Message message = (Message)outbound(p2);
|
||||
assertNull(message == null ? "" : message.toString(), message);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transactionConfidence() throws Exception {
|
||||
// Checks that we correctly count how many peers broadcast a transaction, so we can establish some measure of
|
||||
// its trustworthyness assuming an untampered with internet connection.
|
||||
peerGroup.start();
|
||||
|
||||
final Transaction[] event = new Transaction[1];
|
||||
final TransactionConfidence[] confEvent = new TransactionConfidence[1];
|
||||
peerGroup.addEventListener(new AbstractPeerEventListener() {
|
||||
@Override
|
||||
public void onTransaction(Peer peer, Transaction t) {
|
||||
event[0] = t;
|
||||
}
|
||||
}, Threading.SAME_THREAD);
|
||||
|
||||
InboundMessageQueuer p1 = connectPeer(1);
|
||||
InboundMessageQueuer p2 = connectPeer(2);
|
||||
InboundMessageQueuer p3 = connectPeer(3);
|
||||
|
||||
Transaction tx = FakeTxBuilder.createFakeTx(params, valueOf(20, 0), address);
|
||||
InventoryMessage inv = new InventoryMessage(params);
|
||||
inv.addTransaction(tx);
|
||||
|
||||
// Peer 2 advertises the tx but does not receive it yet.
|
||||
inbound(p2, inv);
|
||||
assertTrue(outbound(p2) instanceof GetDataMessage);
|
||||
assertEquals(0, tx.getConfidence().numBroadcastPeers());
|
||||
assertTrue(blockChain.getContext().getConfidenceTable().maybeWasSeen(tx.getHash()));
|
||||
assertNull(event[0]);
|
||||
// Peer 1 advertises the tx, we don't do anything as it's already been requested.
|
||||
inbound(p1, inv);
|
||||
assertNull(outbound(p1));
|
||||
// Peer 2 gets sent the tx and requests the dependency.
|
||||
inbound(p2, tx);
|
||||
assertTrue(outbound(p2) instanceof GetDataMessage);
|
||||
tx = event[0]; // We want to use the canonical copy delivered by the PeerGroup from now on.
|
||||
assertNotNull(tx);
|
||||
event[0] = null;
|
||||
|
||||
// Peer 1 (the download peer) advertises the tx, we download it.
|
||||
inbound(p1, inv); // returns getdata
|
||||
inbound(p1, tx); // returns nothing after a queue drain.
|
||||
// Two peers saw this tx hash.
|
||||
assertEquals(2, tx.getConfidence().numBroadcastPeers());
|
||||
assertTrue(tx.getConfidence().wasBroadcastBy(peerOf(p1).getAddress()));
|
||||
assertTrue(tx.getConfidence().wasBroadcastBy(peerOf(p2).getAddress()));
|
||||
|
||||
tx.getConfidence().addEventListener(new TransactionConfidence.Listener() {
|
||||
@Override
|
||||
public void onConfidenceChanged(TransactionConfidence confidence, TransactionConfidence.Listener.ChangeReason reason) {
|
||||
confEvent[0] = confidence;
|
||||
}
|
||||
});
|
||||
// A straggler reports in.
|
||||
inbound(p3, inv);
|
||||
pingAndWait(p3);
|
||||
Threading.waitForUserCode();
|
||||
assertEquals(tx.getHash(), confEvent[0].getTransactionHash());
|
||||
assertEquals(3, tx.getConfidence().numBroadcastPeers());
|
||||
assertTrue(tx.getConfidence().wasBroadcastBy(peerOf(p3).getAddress()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWalletCatchupTime() throws Exception {
|
||||
// Check the fast catchup time was initialized to something around the current runtime minus a week.
|
||||
// The wallet was already added to the peer in setup.
|
||||
final int WEEK = 86400 * 7;
|
||||
final long now = Utils.currentTimeSeconds();
|
||||
peerGroup.start();
|
||||
assertTrue(peerGroup.getFastCatchupTimeSecs() > now - WEEK - 10000);
|
||||
Wallet w2 = new Wallet(params);
|
||||
ECKey key1 = new ECKey();
|
||||
key1.setCreationTimeSeconds(now - 86400); // One day ago.
|
||||
w2.importKey(key1);
|
||||
peerGroup.addWallet(w2);
|
||||
peerGroup.waitForJobQueue();
|
||||
assertEquals(peerGroup.getFastCatchupTimeSecs(), now - 86400 - WEEK);
|
||||
// Adding a key to the wallet should update the fast catchup time, but asynchronously and in the background
|
||||
// due to the need to avoid complicated lock inversions.
|
||||
ECKey key2 = new ECKey();
|
||||
key2.setCreationTimeSeconds(now - 100000);
|
||||
w2.importKey(key2);
|
||||
peerGroup.waitForJobQueue();
|
||||
assertEquals(peerGroup.getFastCatchupTimeSecs(), now - WEEK - 100000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noPings() throws Exception {
|
||||
peerGroup.start();
|
||||
peerGroup.setPingIntervalMsec(0);
|
||||
VersionMessage versionMessage = new VersionMessage(params, 2);
|
||||
versionMessage.clientVersion = FilteredBlock.MIN_PROTOCOL_VERSION;
|
||||
versionMessage.localServices = VersionMessage.NODE_NETWORK;
|
||||
connectPeer(1, versionMessage);
|
||||
peerGroup.waitForPeers(1).get();
|
||||
assertFalse(peerGroup.getConnectedPeers().get(0).getLastPingTime() < Long.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pings() throws Exception {
|
||||
peerGroup.start();
|
||||
peerGroup.setPingIntervalMsec(100);
|
||||
VersionMessage versionMessage = new VersionMessage(params, 2);
|
||||
versionMessage.clientVersion = FilteredBlock.MIN_PROTOCOL_VERSION;
|
||||
versionMessage.localServices = VersionMessage.NODE_NETWORK;
|
||||
InboundMessageQueuer p1 = connectPeer(1, versionMessage);
|
||||
Ping ping = (Ping) waitForOutbound(p1);
|
||||
inbound(p1, new Pong(ping.getNonce()));
|
||||
pingAndWait(p1);
|
||||
assertTrue(peerGroup.getConnectedPeers().get(0).getLastPingTime() < Long.MAX_VALUE);
|
||||
// The call to outbound should block until a ping arrives.
|
||||
ping = (Ping) waitForOutbound(p1);
|
||||
inbound(p1, new Pong(ping.getNonce()));
|
||||
assertTrue(peerGroup.getConnectedPeers().get(0).getLastPingTime() < Long.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void downloadPeerSelection() throws Exception {
|
||||
peerGroup.start();
|
||||
VersionMessage versionMessage2 = new VersionMessage(params, 2);
|
||||
versionMessage2.clientVersion = FilteredBlock.MIN_PROTOCOL_VERSION;
|
||||
versionMessage2.localServices = VersionMessage.NODE_NETWORK;
|
||||
VersionMessage versionMessage3 = new VersionMessage(params, 3);
|
||||
versionMessage3.clientVersion = FilteredBlock.MIN_PROTOCOL_VERSION;
|
||||
versionMessage3.localServices = VersionMessage.NODE_NETWORK;
|
||||
assertNull(peerGroup.getDownloadPeer());
|
||||
Peer a = connectPeer(1, versionMessage2).peer;
|
||||
assertEquals(2, peerGroup.getMostCommonChainHeight());
|
||||
assertEquals(a, peerGroup.getDownloadPeer());
|
||||
connectPeer(2, versionMessage2);
|
||||
assertEquals(2, peerGroup.getMostCommonChainHeight());
|
||||
assertEquals(a, peerGroup.getDownloadPeer()); // No change.
|
||||
Peer c = connectPeer(3, versionMessage3).peer;
|
||||
assertEquals(2, peerGroup.getMostCommonChainHeight());
|
||||
assertEquals(a, peerGroup.getDownloadPeer()); // No change yet.
|
||||
connectPeer(4, versionMessage3);
|
||||
assertEquals(3, peerGroup.getMostCommonChainHeight());
|
||||
assertEquals(c, peerGroup.getDownloadPeer()); // Switch to first peer advertising new height.
|
||||
// New peer with a higher protocol version but same chain height.
|
||||
//TODO: When PeerGroup.selectDownloadPeer.PREFERRED_VERSION is not equal to vMinRequiredProtocolVersion,
|
||||
// reenable this test
|
||||
/*VersionMessage versionMessage4 = new VersionMessage(params, 3);
|
||||
versionMessage4.clientVersion = 100000;
|
||||
versionMessage4.localServices = VersionMessage.NODE_NETWORK;
|
||||
InboundMessageQueuer d = connectPeer(5, versionMessage4);
|
||||
assertEquals(d.peer, peerGroup.getDownloadPeer());*/
|
||||
}
|
||||
|
||||
@Test
|
||||
public void peerTimeoutTest() throws Exception {
|
||||
peerGroup.start();
|
||||
peerGroup.setConnectTimeoutMillis(100);
|
||||
|
||||
final SettableFuture<Void> peerConnectedFuture = SettableFuture.create();
|
||||
final SettableFuture<Void> peerDisconnectedFuture = SettableFuture.create();
|
||||
peerGroup.addEventListener(new AbstractPeerEventListener() {
|
||||
@Override
|
||||
public void onPeerConnected(Peer peer, int peerCount) {
|
||||
peerConnectedFuture.set(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPeerDisconnected(Peer peer, int peerCount) {
|
||||
peerDisconnectedFuture.set(null);
|
||||
}
|
||||
}, Threading.SAME_THREAD);
|
||||
connectPeerWithoutVersionExchange(0);
|
||||
Thread.sleep(50);
|
||||
assertFalse(peerConnectedFuture.isDone() || peerDisconnectedFuture.isDone());
|
||||
Thread.sleep(60);
|
||||
assertTrue(!peerConnectedFuture.isDone());
|
||||
assertTrue(!peerConnectedFuture.isDone() && peerDisconnectedFuture.isDone());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void peerPriority() throws Exception {
|
||||
final List<InetSocketAddress> addresses = Lists.newArrayList(
|
||||
new InetSocketAddress("localhost", 2000),
|
||||
new InetSocketAddress("localhost", 2001),
|
||||
new InetSocketAddress("localhost", 2002)
|
||||
);
|
||||
peerGroup.addEventListener(listener);
|
||||
peerGroup.addPeerDiscovery(new PeerDiscovery() {
|
||||
@Override
|
||||
public InetSocketAddress[] getPeers(long unused, TimeUnit unused2) throws PeerDiscoveryException {
|
||||
return addresses.toArray(new InetSocketAddress[addresses.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
}
|
||||
});
|
||||
peerGroup.setMaxConnections(3);
|
||||
|
||||
Utils.setMockSleep(true);
|
||||
blockJobs = true;
|
||||
|
||||
jobBlocks.release(2); // startup + first peer discovery
|
||||
peerGroup.start();
|
||||
|
||||
jobBlocks.release(3); // One for each peer.
|
||||
handleConnectToPeer(0);
|
||||
handleConnectToPeer(1);
|
||||
handleConnectToPeer(2);
|
||||
connectedPeers.take();
|
||||
connectedPeers.take();
|
||||
connectedPeers.take();
|
||||
addresses.clear();
|
||||
addresses.addAll(Lists.newArrayList(new InetSocketAddress("localhost", 2003)));
|
||||
stopPeerServer(2);
|
||||
assertEquals(2002, disconnectedPeers.take().getAddress().getPort()); // peer died
|
||||
|
||||
// discovers, connects to new peer
|
||||
jobBlocks.release(1);
|
||||
handleConnectToPeer(3);
|
||||
assertEquals(2003, connectedPeers.take().getAddress().getPort());
|
||||
|
||||
stopPeerServer(1);
|
||||
assertEquals(2001, disconnectedPeers.take().getAddress().getPort()); // peer died
|
||||
|
||||
// Alternates trying two offline peers
|
||||
jobBlocks.release(10);
|
||||
assertEquals(2001, disconnectedPeers.take().getAddress().getPort());
|
||||
assertEquals(2002, disconnectedPeers.take().getAddress().getPort());
|
||||
assertEquals(2001, disconnectedPeers.take().getAddress().getPort());
|
||||
assertEquals(2002, disconnectedPeers.take().getAddress().getPort());
|
||||
assertEquals(2001, disconnectedPeers.take().getAddress().getPort());
|
||||
|
||||
// Peer 2 comes online
|
||||
startPeerServer(2);
|
||||
jobBlocks.release(1);
|
||||
handleConnectToPeer(2);
|
||||
assertEquals(2002, connectedPeers.take().getAddress().getPort());
|
||||
|
||||
jobBlocks.release(6);
|
||||
stopPeerServer(2);
|
||||
assertEquals(2002, disconnectedPeers.take().getAddress().getPort()); // peer died
|
||||
|
||||
// Peer 2 is tried before peer 1, since it has a lower backoff due to recent success
|
||||
assertEquals(2002, disconnectedPeers.take().getAddress().getPort());
|
||||
assertEquals(2001, disconnectedPeers.take().getAddress().getPort());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBloomOnP2Pubkey() throws Exception {
|
||||
// Cover bug 513. When a relevant transaction with a p2pubkey output is found, the Bloom filter should be
|
||||
// recalculated to include that transaction hash but not re-broadcast as the remote nodes should have followed
|
||||
// the same procedure. However a new node that's connected should get the fresh filter.
|
||||
peerGroup.start();
|
||||
final ECKey key = wallet.currentReceiveKey();
|
||||
// Create a couple of peers.
|
||||
InboundMessageQueuer p1 = connectPeer(1);
|
||||
InboundMessageQueuer p2 = connectPeer(2);
|
||||
// Create a pay to pubkey tx.
|
||||
Transaction tx = FakeTxBuilder.createFakeTx(params, COIN, key);
|
||||
Transaction tx2 = new Transaction(params);
|
||||
tx2.addInput(tx.getOutput(0));
|
||||
TransactionOutPoint outpoint = tx2.getInput(0).getOutpoint();
|
||||
assertTrue(p1.lastReceivedFilter.contains(key.getPubKey()));
|
||||
assertFalse(p1.lastReceivedFilter.contains(tx.getHash().getBytes()));
|
||||
inbound(p1, tx);
|
||||
// p1 requests dep resolution, p2 is quiet.
|
||||
assertTrue(outbound(p1) instanceof GetDataMessage);
|
||||
final Sha256Hash dephash = tx.getInput(0).getOutpoint().getHash();
|
||||
final InventoryItem inv = new InventoryItem(InventoryItem.Type.Transaction, dephash);
|
||||
inbound(p1, new NotFoundMessage(params, ImmutableList.of(inv)));
|
||||
assertNull(outbound(p1));
|
||||
assertNull(outbound(p2));
|
||||
peerGroup.waitForJobQueue();
|
||||
// Now we connect p3 and there is a new bloom filter sent, that DOES match the relevant outpoint.
|
||||
InboundMessageQueuer p3 = connectPeer(3);
|
||||
assertTrue(p3.lastReceivedFilter.contains(key.getPubKey()));
|
||||
assertTrue(p3.lastReceivedFilter.contains(outpoint.bitcoinSerialize()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBloomResendOnNewKey() throws Exception {
|
||||
// Check that when we add a new key to the wallet, the Bloom filter is re-calculated and re-sent but only once
|
||||
// we exceed the lookahead threshold.
|
||||
wallet.setKeychainLookaheadSize(5);
|
||||
wallet.setKeychainLookaheadThreshold(4);
|
||||
peerGroup.start();
|
||||
// Create a couple of peers.
|
||||
InboundMessageQueuer p1 = connectPeer(1);
|
||||
InboundMessageQueuer p2 = connectPeer(2);
|
||||
peerGroup.waitForJobQueue();
|
||||
BloomFilter f1 = p1.lastReceivedFilter;
|
||||
ECKey key = null;
|
||||
// We have to run ahead of the lookahead zone for this test. There should only be one bloom filter recalc.
|
||||
for (int i = 0; i < wallet.getKeychainLookaheadSize() + wallet.getKeychainLookaheadThreshold() + 1; i++) {
|
||||
key = wallet.freshReceiveKey();
|
||||
}
|
||||
peerGroup.waitForJobQueue();
|
||||
BloomFilter bf, f2 = null;
|
||||
while ((bf = (BloomFilter) outbound(p1)) != null) {
|
||||
assertEquals(MemoryPoolMessage.class, outbound(p1).getClass());
|
||||
f2 = bf;
|
||||
}
|
||||
assertNotNull(key);
|
||||
assertNotNull(f2);
|
||||
assertNull(outbound(p1));
|
||||
// Check the last filter received.
|
||||
assertNotEquals(f1, f2);
|
||||
assertTrue(f2.contains(key.getPubKey()));
|
||||
assertTrue(f2.contains(key.getPubKeyHash()));
|
||||
assertFalse(f1.contains(key.getPubKey()));
|
||||
assertFalse(f1.contains(key.getPubKeyHash()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void waitForNumPeers1() throws Exception {
|
||||
ListenableFuture<List<Peer>> future = peerGroup.waitForPeers(3);
|
||||
peerGroup.start();
|
||||
assertFalse(future.isDone());
|
||||
connectPeer(1);
|
||||
assertFalse(future.isDone());
|
||||
connectPeer(2);
|
||||
assertFalse(future.isDone());
|
||||
assertTrue(peerGroup.waitForPeers(2).isDone()); // Immediate completion.
|
||||
connectPeer(3);
|
||||
future.get();
|
||||
assertTrue(future.isDone());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void waitForPeersOfVersion() throws Exception {
|
||||
final int baseVer = peerGroup.getMinRequiredProtocolVersion() + 3000;
|
||||
final int newVer = baseVer + 1000;
|
||||
|
||||
ListenableFuture<List<Peer>> future = peerGroup.waitForPeersOfVersion(2, newVer);
|
||||
|
||||
VersionMessage ver1 = new VersionMessage(params, 10);
|
||||
ver1.clientVersion = baseVer;
|
||||
ver1.localServices = VersionMessage.NODE_NETWORK;
|
||||
VersionMessage ver2 = new VersionMessage(params, 10);
|
||||
ver2.clientVersion = newVer;
|
||||
ver2.localServices = VersionMessage.NODE_NETWORK;
|
||||
peerGroup.start();
|
||||
assertFalse(future.isDone());
|
||||
connectPeer(1, ver1);
|
||||
assertFalse(future.isDone());
|
||||
connectPeer(2, ver2);
|
||||
assertFalse(future.isDone());
|
||||
assertTrue(peerGroup.waitForPeersOfVersion(1, newVer).isDone()); // Immediate completion.
|
||||
connectPeer(3, ver2);
|
||||
future.get();
|
||||
assertTrue(future.isDone());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void waitForPeersWithServiceFlags() throws Exception {
|
||||
ListenableFuture<List<Peer>> future = peerGroup.waitForPeersWithServiceMask(2, 3);
|
||||
|
||||
VersionMessage ver1 = new VersionMessage(params, 10);
|
||||
ver1.clientVersion = 70000;
|
||||
ver1.localServices = VersionMessage.NODE_NETWORK;
|
||||
VersionMessage ver2 = new VersionMessage(params, 10);
|
||||
ver2.clientVersion = 70000;
|
||||
ver2.localServices = VersionMessage.NODE_NETWORK | 2;
|
||||
peerGroup.start();
|
||||
assertFalse(future.isDone());
|
||||
connectPeer(1, ver1);
|
||||
assertTrue(peerGroup.findPeersWithServiceMask(3).isEmpty());
|
||||
assertFalse(future.isDone());
|
||||
connectPeer(2, ver2);
|
||||
assertFalse(future.isDone());
|
||||
assertEquals(1, peerGroup.findPeersWithServiceMask(3).size());
|
||||
assertTrue(peerGroup.waitForPeersWithServiceMask(1, 0x3).isDone()); // Immediate completion.
|
||||
connectPeer(3, ver2);
|
||||
future.get();
|
||||
assertTrue(future.isDone());
|
||||
peerGroup.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferLocalPeer() throws IOException {
|
||||
// Because we are using the same port (8333 or 18333) that is used by Satoshi client
|
||||
// We have to consider 2 cases:
|
||||
// 1. Test are executed on the same machine that is running full node / Satoshi client
|
||||
// 2. Test are executed without any full node running locally
|
||||
// We have to avoid to connecting to real and external services in unit tests
|
||||
// So we skip this test in case we have already something running on port params.getPort()
|
||||
|
||||
// Check that if we have a localhost port 8333 or 18333 then it's used instead of the p2p network.
|
||||
ServerSocket local = null;
|
||||
try {
|
||||
local = new ServerSocket(params.getPort(), 100, InetAddresses.forString("127.0.0.1"));
|
||||
}
|
||||
catch(BindException e) { // Port already in use, skipping this test.
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
peerGroup.setUseLocalhostPeerWhenPossible(true);
|
||||
peerGroup.start();
|
||||
local.accept().close(); // Probe connect
|
||||
local.accept(); // Real connect
|
||||
// If we get here it used the local peer. Check no others are in use.
|
||||
assertEquals(1, peerGroup.getMaxConnections());
|
||||
assertEquals(PeerAddress.localhost(params), peerGroup.getPendingPeers().get(0).getAddress());
|
||||
} finally {
|
||||
local.close();
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends Message> T assertNextMessageIs(InboundMessageQueuer q, Class<T> klass) throws Exception {
|
||||
Message outbound = waitForOutbound(q);
|
||||
assertEquals(klass, outbound.getClass());
|
||||
return (T) outbound;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void autoRescanOnKeyExhaustion() throws Exception {
|
||||
// Check that if the last key that was inserted into the bloom filter is seen in some requested blocks,
|
||||
// that the exhausting block is discarded, a new filter is calculated and sent, and then the download resumes.
|
||||
|
||||
final int NUM_KEYS = 9;
|
||||
|
||||
// First, grab a load of keys from the wallet, and then recreate it so it forgets that those keys were issued.
|
||||
Wallet shadow = Wallet.fromSeed(wallet.getParams(), wallet.getKeyChainSeed());
|
||||
List<ECKey> keys = new ArrayList<ECKey>(NUM_KEYS);
|
||||
for (int i = 0; i < NUM_KEYS; i++) {
|
||||
keys.add(shadow.freshReceiveKey());
|
||||
}
|
||||
// Reduce the number of keys we need to work with to speed up this test.
|
||||
wallet.setKeychainLookaheadSize(4);
|
||||
wallet.setKeychainLookaheadThreshold(2);
|
||||
|
||||
peerGroup.start();
|
||||
InboundMessageQueuer p1 = connectPeer(1);
|
||||
assertTrue(p1.lastReceivedFilter.contains(keys.get(0).getPubKey()));
|
||||
assertTrue(p1.lastReceivedFilter.contains(keys.get(5).getPubKeyHash()));
|
||||
assertFalse(p1.lastReceivedFilter.contains(keys.get(keys.size() - 1).getPubKey()));
|
||||
peerGroup.startBlockChainDownload(null);
|
||||
assertNextMessageIs(p1, GetBlocksMessage.class);
|
||||
|
||||
// Make some transactions and blocks that send money to the wallet thus using up all the keys.
|
||||
List<Block> blocks = Lists.newArrayList();
|
||||
Coin expectedBalance = Coin.ZERO;
|
||||
Block prev = blockStore.getChainHead().getHeader();
|
||||
for (ECKey key1 : keys) {
|
||||
Address addr = key1.toAddress(params);
|
||||
Block next = FakeTxBuilder.makeSolvedTestBlock(prev, FakeTxBuilder.createFakeTx(params, Coin.FIFTY_COINS, addr));
|
||||
expectedBalance = expectedBalance.add(next.getTransactions().get(2).getOutput(0).getValue());
|
||||
blocks.add(next);
|
||||
prev = next;
|
||||
}
|
||||
|
||||
// Send the chain that doesn't have all the transactions in it. The blocks after the exhaustion point should all
|
||||
// be ignored.
|
||||
int epoch = wallet.keychain.getCombinedKeyLookaheadEpochs();
|
||||
BloomFilter filter = new BloomFilter(params, p1.lastReceivedFilter.bitcoinSerialize());
|
||||
filterAndSend(p1, blocks, filter);
|
||||
Block exhaustionPoint = blocks.get(3);
|
||||
pingAndWait(p1);
|
||||
|
||||
assertNotEquals(epoch, wallet.keychain.getCombinedKeyLookaheadEpochs());
|
||||
// 4th block was end of the lookahead zone and thus was discarded, so we got 3 blocks worth of money (50 each).
|
||||
assertEquals(Coin.FIFTY_COINS.multiply(3), wallet.getBalance());
|
||||
assertEquals(exhaustionPoint.getPrevBlockHash(), blockChain.getChainHead().getHeader().getHash());
|
||||
|
||||
// Await the new filter.
|
||||
peerGroup.waitForJobQueue();
|
||||
BloomFilter newFilter = assertNextMessageIs(p1, BloomFilter.class);
|
||||
assertNotEquals(filter, newFilter);
|
||||
assertNextMessageIs(p1, MemoryPoolMessage.class);
|
||||
Ping ping = assertNextMessageIs(p1, Ping.class);
|
||||
inbound(p1, new Pong(ping.getNonce()));
|
||||
|
||||
// Await restart of the chain download.
|
||||
GetDataMessage getdata = assertNextMessageIs(p1, GetDataMessage.class);
|
||||
assertEquals(exhaustionPoint.getHash(), getdata.getHashOf(0));
|
||||
assertEquals(InventoryItem.Type.FilteredBlock, getdata.getItems().get(0).type);
|
||||
List<Block> newBlocks = blocks.subList(3, blocks.size());
|
||||
filterAndSend(p1, newBlocks, newFilter);
|
||||
assertNextMessageIs(p1, Ping.class);
|
||||
|
||||
// It happened again.
|
||||
peerGroup.waitForJobQueue();
|
||||
newFilter = assertNextMessageIs(p1, BloomFilter.class);
|
||||
assertNextMessageIs(p1, MemoryPoolMessage.class);
|
||||
inbound(p1, new Pong(assertNextMessageIs(p1, Ping.class).getNonce()));
|
||||
assertNextMessageIs(p1, GetDataMessage.class);
|
||||
newBlocks = blocks.subList(6, blocks.size());
|
||||
filterAndSend(p1, newBlocks, newFilter);
|
||||
// Send a non-tx message so the peer knows the filtered block is over and force processing.
|
||||
inbound(p1, new Ping());
|
||||
pingAndWait(p1);
|
||||
|
||||
assertEquals(expectedBalance, wallet.getBalance());
|
||||
assertEquals(blocks.get(blocks.size() - 1).getHash(), blockChain.getChainHead().getHeader().getHash());
|
||||
}
|
||||
|
||||
private void filterAndSend(InboundMessageQueuer p1, List<Block> blocks, BloomFilter filter) {
|
||||
for (Block block : blocks) {
|
||||
FilteredBlock fb = filter.applyAndUpdate(block);
|
||||
inbound(p1, fb);
|
||||
for (Transaction tx : fb.getAssociatedTransactions().values())
|
||||
inbound(p1, tx);
|
||||
}
|
||||
}
|
||||
}
|
||||
231
src/test/java/org/altcoinj/core/TransactionBroadcastTest.java
Normal file
231
src/test/java/org/altcoinj/core/TransactionBroadcastTest.java
Normal file
@@ -0,0 +1,231 @@
|
||||
/**
|
||||
* Copyright 2013 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.UnitTestParams;
|
||||
import com.dogecoin.dogecoinj.testing.FakeTxBuilder;
|
||||
import com.dogecoin.dogecoinj.testing.InboundMessageQueuer;
|
||||
import com.dogecoin.dogecoinj.testing.TestWithPeerGroup;
|
||||
import com.dogecoin.dogecoinj.utils.Threading;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import static com.dogecoin.dogecoinj.core.Coin.*;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
@RunWith(value = Parameterized.class)
|
||||
public class TransactionBroadcastTest extends TestWithPeerGroup {
|
||||
static final NetworkParameters params = UnitTestParams.get();
|
||||
|
||||
@Parameterized.Parameters
|
||||
public static Collection<ClientType[]> parameters() {
|
||||
return Arrays.asList(new ClientType[] {ClientType.NIO_CLIENT_MANAGER},
|
||||
new ClientType[] {ClientType.BLOCKING_CLIENT_MANAGER});
|
||||
}
|
||||
|
||||
public TransactionBroadcastTest(ClientType clientType) {
|
||||
super(clientType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
Utils.setMockClock(); // Use mock clock
|
||||
super.setUp();
|
||||
// Fix the random permutation that TransactionBroadcast uses to shuffle the peers.
|
||||
TransactionBroadcast.random = new Random(0);
|
||||
peerGroup.setMinBroadcastConnections(2);
|
||||
peerGroup.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() {
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fourPeers() throws Exception {
|
||||
InboundMessageQueuer[] channels = { connectPeer(1), connectPeer(2), connectPeer(3), connectPeer(4) };
|
||||
Transaction tx = new Transaction(params);
|
||||
TransactionBroadcast broadcast = new TransactionBroadcast(peerGroup, blockChain.getContext(), tx);
|
||||
ListenableFuture<Transaction> future = broadcast.broadcast();
|
||||
assertFalse(future.isDone());
|
||||
// We expect two peers to receive a tx message, and at least one of the others must announce for the future to
|
||||
// complete successfully.
|
||||
Message[] messages = {
|
||||
(Message) outbound(channels[0]),
|
||||
(Message) outbound(channels[1]),
|
||||
(Message) outbound(channels[2]),
|
||||
(Message) outbound(channels[3])
|
||||
};
|
||||
// 0 and 3 are randomly selected to receive the broadcast.
|
||||
assertEquals(tx, messages[0]);
|
||||
assertEquals(tx, messages[3]);
|
||||
assertNull(messages[1]);
|
||||
assertNull(messages[2]);
|
||||
Threading.waitForUserCode();
|
||||
assertFalse(future.isDone());
|
||||
inbound(channels[1], InventoryMessage.with(tx));
|
||||
pingAndWait(channels[1]);
|
||||
Threading.waitForUserCode();
|
||||
// FIXME flaky test - future is not handled on user thread
|
||||
assertTrue(future.isDone());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rejectHandling() throws Exception {
|
||||
InboundMessageQueuer[] channels = { connectPeer(0), connectPeer(1), connectPeer(2), connectPeer(3), connectPeer(4) };
|
||||
Transaction tx = new Transaction(params);
|
||||
TransactionBroadcast broadcast = new TransactionBroadcast(peerGroup, blockChain.getContext(), tx);
|
||||
ListenableFuture<Transaction> future = broadcast.broadcast();
|
||||
// 0 and 3 are randomly selected to receive the broadcast.
|
||||
assertEquals(tx, outbound(channels[1]));
|
||||
assertEquals(tx, outbound(channels[2]));
|
||||
assertEquals(tx, outbound(channels[4]));
|
||||
RejectMessage reject = new RejectMessage(params, RejectMessage.RejectCode.DUST, tx.getHash(), "tx", "dust");
|
||||
inbound(channels[1], reject);
|
||||
inbound(channels[4], reject);
|
||||
try {
|
||||
future.get();
|
||||
fail();
|
||||
} catch (ExecutionException e) {
|
||||
assertEquals(RejectedTransactionException.class, e.getCause().getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void retryFailedBroadcast() throws Exception {
|
||||
// If we create a spend, it's sent to a peer that swallows it, and the peergroup is removed/re-added then
|
||||
// the tx should be broadcast again.
|
||||
InboundMessageQueuer p1 = connectPeer(1);
|
||||
connectPeer(2);
|
||||
|
||||
// Send ourselves a bit of money.
|
||||
Block b1 = FakeTxBuilder.makeSolvedTestBlock(blockStore, address);
|
||||
inbound(p1, b1);
|
||||
assertNull(outbound(p1));
|
||||
assertEquals(FIFTY_COINS, wallet.getBalance());
|
||||
|
||||
// Now create a spend, and expect the announcement on p1.
|
||||
Address dest = new ECKey().toAddress(params);
|
||||
Wallet.SendResult sendResult = wallet.sendCoins(peerGroup, dest, COIN);
|
||||
assertFalse(sendResult.broadcastComplete.isDone());
|
||||
Transaction t1;
|
||||
{
|
||||
Message m;
|
||||
while (!((m = outbound(p1)) instanceof Transaction));
|
||||
t1 = (Transaction) m;
|
||||
}
|
||||
assertFalse(sendResult.broadcastComplete.isDone());
|
||||
|
||||
// p1 eats it :( A bit later the PeerGroup is taken down.
|
||||
peerGroup.removeWallet(wallet);
|
||||
peerGroup.addWallet(wallet);
|
||||
|
||||
// We want to hear about it again. Now, because we've disabled the randomness for the unit tests it will
|
||||
// re-appear on p1 again. Of course in the real world it would end up with a different set of peers and
|
||||
// select randomly so we get a second chance.
|
||||
Transaction t2 = (Transaction) outbound(p1);
|
||||
assertEquals(t1, t2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void peerGroupWalletIntegration() throws Exception {
|
||||
// Make sure we can create spends, and that they are announced. Then do the same with offline mode.
|
||||
|
||||
// Set up connections and block chain.
|
||||
VersionMessage ver = new VersionMessage(params, 2);
|
||||
ver.localServices = VersionMessage.NODE_NETWORK;
|
||||
InboundMessageQueuer p1 = connectPeer(1, ver);
|
||||
InboundMessageQueuer p2 = connectPeer(2);
|
||||
|
||||
// Send ourselves a bit of money.
|
||||
Block b1 = FakeTxBuilder.makeSolvedTestBlock(blockStore, address);
|
||||
inbound(p1, b1);
|
||||
pingAndWait(p1);
|
||||
assertNull(outbound(p1));
|
||||
assertEquals(FIFTY_COINS, wallet.getBalance());
|
||||
|
||||
// Check that the wallet informs us of changes in confidence as the transaction ripples across the network.
|
||||
final Transaction[] transactions = new Transaction[1];
|
||||
wallet.addEventListener(new AbstractWalletEventListener() {
|
||||
@Override
|
||||
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) {
|
||||
transactions[0] = tx;
|
||||
}
|
||||
});
|
||||
|
||||
// Now create a spend, and expect the announcement on p1.
|
||||
Address dest = new ECKey().toAddress(params);
|
||||
Wallet.SendResult sendResult = wallet.sendCoins(peerGroup, dest, COIN);
|
||||
assertNotNull(sendResult.tx);
|
||||
Threading.waitForUserCode();
|
||||
assertFalse(sendResult.broadcastComplete.isDone());
|
||||
assertEquals(transactions[0], sendResult.tx);
|
||||
assertEquals(0, transactions[0].getConfidence().numBroadcastPeers());
|
||||
transactions[0] = null;
|
||||
Transaction t1;
|
||||
{
|
||||
peerGroup.waitForJobQueue();
|
||||
Message m = outbound(p1);
|
||||
// Hack: bloom filters are recalculated asynchronously to sending transactions to avoid lock
|
||||
// inversion, so we might or might not get the filter/mempool message first or second.
|
||||
while (!(m instanceof Transaction)) m = outbound(p1);
|
||||
t1 = (Transaction) m;
|
||||
}
|
||||
assertNotNull(t1);
|
||||
// 49 BTC in change.
|
||||
assertEquals(valueOf(49, 0), t1.getValueSentToMe(wallet));
|
||||
// The future won't complete until it's heard back from the network on p2.
|
||||
InventoryMessage inv = new InventoryMessage(params);
|
||||
inv.addTransaction(t1);
|
||||
inbound(p2, inv);
|
||||
pingAndWait(p2);
|
||||
Threading.waitForUserCode();
|
||||
assertTrue(sendResult.broadcastComplete.isDone());
|
||||
assertEquals(transactions[0], sendResult.tx);
|
||||
assertEquals(1, transactions[0].getConfidence().numBroadcastPeers());
|
||||
// Confirm it.
|
||||
Block b2 = FakeTxBuilder.createFakeBlock(blockStore, t1).block;
|
||||
inbound(p1, b2);
|
||||
pingAndWait(p1);
|
||||
assertNull(outbound(p1));
|
||||
|
||||
// Do the same thing with an offline transaction.
|
||||
peerGroup.removeWallet(wallet);
|
||||
Wallet.SendRequest req = Wallet.SendRequest.to(dest, valueOf(2, 0));
|
||||
req.ensureMinRequiredFee = false;
|
||||
Transaction t3 = checkNotNull(wallet.sendCoinsOffline(req));
|
||||
assertNull(outbound(p1)); // Nothing sent.
|
||||
// Add the wallet to the peer group (simulate initialization). Transactions should be announced.
|
||||
peerGroup.addWallet(wallet);
|
||||
// Transaction announced to the first peer. No extra Bloom filter because no change address was needed.
|
||||
assertEquals(t3.getHash(), ((Transaction) outbound(p1)).getHash());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright 2014 BitcoinJ Project
|
||||
*
|
||||
* 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.dogecoin.dogecoinj.params.TestNet3Params;
|
||||
import org.junit.Test;
|
||||
|
||||
import static com.dogecoin.dogecoinj.core.Utils.HEX;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class VersionedChecksummedBytesTest {
|
||||
static final NetworkParameters testParams = TestNet3Params.get();
|
||||
static final NetworkParameters mainParams = MainNetParams.get();
|
||||
|
||||
@Test
|
||||
public void stringification() throws Exception {
|
||||
// Test a testnet address.
|
||||
VersionedChecksummedBytes a = new VersionedChecksummedBytes(testParams.getAddressHeader(), HEX.decode("fda79a24e50ff70ff42f7d89585da5bd19d9e5cc"));
|
||||
assertEquals("n4eA2nbYqErp7H6jebchxAN59DmNpksexv", a.toString());
|
||||
|
||||
VersionedChecksummedBytes b = new VersionedChecksummedBytes(mainParams.getAddressHeader(), HEX.decode("4a22c3c4cbb31e4d03b15550636762bda0baf85a"));
|
||||
assertEquals("17kzeh4N8g49GFvdDzSf8PjaPfyoD1MndL", b.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cloning() throws Exception {
|
||||
VersionedChecksummedBytes a = new VersionedChecksummedBytes(testParams.getAddressHeader(), HEX.decode("fda79a24e50ff70ff42f7d89585da5bd19d9e5cc"));
|
||||
VersionedChecksummedBytes b = a.clone();
|
||||
|
||||
assertEquals(a, b);
|
||||
assertNotSame(a, b);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void comparisonCloneEqualTo() throws Exception {
|
||||
VersionedChecksummedBytes a = new VersionedChecksummedBytes(testParams.getAddressHeader(), HEX.decode("fda79a24e50ff70ff42f7d89585da5bd19d9e5cc"));
|
||||
VersionedChecksummedBytes b = a.clone();
|
||||
|
||||
assertTrue(a.compareTo(b) == 0);
|
||||
}
|
||||
}
|
||||
3122
src/test/java/org/altcoinj/core/WalletTest.java
Normal file
3122
src/test/java/org/altcoinj/core/WalletTest.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2015 J. Ross Nicoll
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.altcoinj.params;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jrn
|
||||
*/
|
||||
public class AbstractDogecoinParamsTest {
|
||||
private static final AbstractDogecoinParams params = DogecoinMainNetParams.get();
|
||||
|
||||
@Test
|
||||
public void shouldCalculateBitcoinLikeDifficulty() {
|
||||
int previousHeight = 239;
|
||||
long previousBlockTime = 1386475638; // Block 239
|
||||
long lastRetargetDifficulty = 0x1e0ffff0;
|
||||
long lastRetargetTime = 1386474927; // Block 1
|
||||
long newDifficulty = params.getNewDifficultyTarget(previousHeight, previousBlockTime, lastRetargetDifficulty, lastRetargetTime);
|
||||
assertEquals(newDifficulty, 0x1e00ffff);
|
||||
|
||||
previousHeight = 479;
|
||||
previousBlockTime = 1386475840;
|
||||
lastRetargetDifficulty = 0x1e0fffff;
|
||||
lastRetargetTime = 1386475638; // Block 239
|
||||
newDifficulty = params.getNewDifficultyTarget(previousHeight, previousBlockTime, lastRetargetDifficulty, lastRetargetTime);
|
||||
assertEquals(newDifficulty, 0x1e00ffff);
|
||||
|
||||
previousHeight = 9599;
|
||||
previousBlockTime = 1386954113;
|
||||
lastRetargetDifficulty = 0x1c1a1206;
|
||||
lastRetargetTime = 1386942008; // Block 9359
|
||||
newDifficulty = params.getNewDifficultyTarget(previousHeight, previousBlockTime, lastRetargetDifficulty, lastRetargetTime);
|
||||
assertEquals(newDifficulty, 0x1c15ea59);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCalculateDigishieldDifficulty() {
|
||||
int previousHeight = 145000;
|
||||
long previousBlockTime = 1395094679;
|
||||
long lastRetargetDifficulty = 0x1b499dfd;
|
||||
long lastRetargetTime = 1395094427;
|
||||
long newDifficulty = params.getNewDifficultyTarget(previousHeight, previousBlockTime, lastRetargetDifficulty, lastRetargetTime);
|
||||
assertEquals(newDifficulty, 0x1b671062);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCalculateDigishieldDifficultyRounding() {
|
||||
// Test case for correct rounding of modulated time
|
||||
int previousHeight = 145001;
|
||||
long previousBlockTime = 1395094727;
|
||||
long lastRetargetDifficulty = 0x1b671062;
|
||||
long lastRetargetTime = 1395094679;
|
||||
long newDifficulty = params.getNewDifficultyTarget(previousHeight, previousBlockTime, lastRetargetDifficulty, lastRetargetTime);
|
||||
assertEquals(newDifficulty, 0x1b6558a4);
|
||||
}
|
||||
}
|
||||
92
src/test/java/org/bitcoinj/core/DogecoinBlockTest.java
Normal file
92
src/test/java/org/bitcoinj/core/DogecoinBlockTest.java
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.bitcoinj.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.altcoinj.params.DogecoinMainNetParams;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jrn
|
||||
*/
|
||||
public class DogecoinBlockTest {
|
||||
private final NetworkParameters params = DogecoinMainNetParams.get();
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
Context context = new Context(params);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldParseBlock1() throws IOException {
|
||||
byte[] payload = Util.getBytes(getClass().getResourceAsStream("dogecoin_block1.bin"));
|
||||
final AltcoinBlock block = new AltcoinBlock(params, payload);
|
||||
assertEquals("82bc68038f6034c0596b6e313729793a887fded6e92a31fbdf70863f89d9bea2", block.getHashAsString());
|
||||
assertEquals(1, block.getTransactions().size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the first hardfork block.
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void shouldParseBlock250000() throws IOException {
|
||||
byte[] payload = Util.getBytes(getClass().getResourceAsStream("dogecoin_block250000.bin"));
|
||||
final AltcoinBlock block = new AltcoinBlock(params, payload);
|
||||
assertEquals(2469341065L, block.getNonce());
|
||||
final AuxPoW auxpow = block.getAuxPoW();
|
||||
assertNull(auxpow);
|
||||
|
||||
assertEquals(6, block.getTransactions().size());
|
||||
assertEquals("0e4bcfe8d970979f7e30e2809ab51908d435677998cf759169407824d4f36460", block.getHashAsString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm parsing of the first merged-mine block.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void shouldParseBlock371337() throws IOException {
|
||||
byte[] payload = Util.getBytes(getClass().getResourceAsStream("dogecoin_block371337.bin"));
|
||||
final AltcoinBlock block = new AltcoinBlock(params, payload);
|
||||
assertEquals("60323982f9c5ff1b5a954eac9dc1269352835f47c2c5222691d80f0d50dcf053", block.getHashAsString());
|
||||
assertEquals(0, block.getNonce());
|
||||
final AuxPoW auxpow = block.getAuxPoW();
|
||||
assertNotNull(auxpow);
|
||||
final Transaction auxpowCoinbase = auxpow.getCoinbase();
|
||||
assertEquals("e5422732b20e9e7ecc243427abbe296e9528d308bb111aae8d30c3465e442de8", auxpowCoinbase.getHashAsString());
|
||||
final Block parentBlock = auxpow.getParentBlockHeader();
|
||||
assertEquals("45df41e40aba5b2a03d08bd1202a1c02ef3954d8aa22ea6c5ae62fd00f290ea9", parentBlock.getHashAsString());
|
||||
assertNull(parentBlock.getTransactions());
|
||||
|
||||
final MerkleBranch blockchainMerkleBranch = auxpow.getBlockchainBranch();
|
||||
Sha256Hash[] expected = new Sha256Hash[] {
|
||||
new Sha256Hash("b541c848bc001d07d2bdf8643abab61d2c6ae50d5b2495815339a4b30703a46f"),
|
||||
new Sha256Hash("78d6abe48cee514cf3496f4042039acb7e27616dcfc5de926ff0d6c7e5987be7"),
|
||||
new Sha256Hash("a0469413ce64d67c43902d54ee3a380eff12ded22ca11cbd3842e15d48298103")
|
||||
};
|
||||
|
||||
assertArrayEquals(expected, blockchainMerkleBranch.getHashes().toArray(new Sha256Hash[blockchainMerkleBranch.getSize()]));
|
||||
|
||||
final MerkleBranch coinbaseMerkleBranch = auxpow.getCoinbaseBranch();
|
||||
expected = new Sha256Hash[] {
|
||||
new Sha256Hash("cd3947cd5a0c26fde01b05a3aa3d7a38717be6ae11d27239365024db36a679a9"),
|
||||
new Sha256Hash("48f9e8fef3411944e27f49ec804462c9e124dca0954c71c8560e8a9dd218a452"),
|
||||
new Sha256Hash("d11293660392e7c51f69477a6130237c72ecee2d0c1d3dc815841734c370331a")
|
||||
};
|
||||
assertArrayEquals(expected, coinbaseMerkleBranch.getHashes().toArray(new Sha256Hash[coinbaseMerkleBranch.getSize()]));
|
||||
|
||||
System.out.println(block.toString());
|
||||
assertEquals(6, block.getTransactions().size());
|
||||
}
|
||||
}
|
||||
BIN
src/test/resources/com/dogecoin/dogecoinj/core/block169482.dat
Normal file
BIN
src/test/resources/com/dogecoin/dogecoinj/core/block169482.dat
Normal file
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,7 @@
|
||||
[
|
||||
"300602010002010001",
|
||||
"3008020200ff020200ff01",
|
||||
"304402203932c892e2e550f3af8ee4ce9c215a87f9bb831dcac87b2838e2c2eaa891df0c022030b61dd36543125d56b9f9f3a1f9353189e5af33cdda8d77a5209aec03978fa001",
|
||||
"30450220076045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01",
|
||||
"3046022100876045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01"
|
||||
]
|
||||
@@ -0,0 +1,22 @@
|
||||
[
|
||||
"non-hex strings are ignored",
|
||||
|
||||
"too short:", "30050201FF020001",
|
||||
"too long:", "30470221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105022200002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"hashtype:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed11",
|
||||
"type:", "314402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"total length:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"S len oob:", "301F01205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb101",
|
||||
"R+S:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed0001",
|
||||
|
||||
"R type:", "304401205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"R len = 0:", "3024020002202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"R<0:", "304402208990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"R padded:", "30450221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
|
||||
|
||||
"S type:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610501202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"S len = 0:", "302402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105020001",
|
||||
"S<0:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61050220fd5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"S padded:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61050221002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01"
|
||||
]
|
||||
@@ -0,0 +1,30 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFMTCCBBmgAwIBAgIQV2O4gJQ5NHgn/PPvDsU1djANBgkqhkiG9w0BAQUFADCB
|
||||
kzELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
||||
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxOTA3BgNV
|
||||
BAMTMENPTU9ETyBDbGllbnQgQXV0aGVudGljYXRpb24gYW5kIFNlY3VyZSBFbWFp
|
||||
bCBDQTAeFw0xNDAzMjkwMDAwMDBaFw0xNTAzMjkyMzU5NTlaMCkxJzAlBgkqhkiG
|
||||
9w0BCQEWGGNvbW9kby5jb21Ac2NoaWxkYmFjaC5kZTCCASIwDQYJKoZIhvcNAQEB
|
||||
BQADggEPADCCAQoCggEBAM61nbZo3ZN0Ojzn7UzoHBf07ZyTDm3KnwK4BdLKLgNS
|
||||
NbGAJtgaYN91qKRbXf97VAFIN6FGhoXT+7MXSzlHgQHn7RkForMyREsD6F32TtyV
|
||||
ZY9RuMGWjmPtABPRgeCVfNJNh9Hu87Uhhkj3Ma+H//ykfkJdDiOyBWIOJdjBFSZZ
|
||||
M6bsZnyH8JCHqmxvK2qHpk+qNqpsNOZV83GYPA2gTFWd1AHjo5+A7W1Bo/qyJMrz
|
||||
tpab0i+ieJPJdi6eJkMt3+nfr57Q2o4A3ZxH0Axq2D1a2dElhMK/JQilh2D+IDUp
|
||||
VjoKkHgV9yji9UGOc3VHq+Sx8bNTumL7OFLCFYky9J8CAwEAAaOCAegwggHkMB8G
|
||||
A1UdIwQYMBaAFHoTTgB0W8Z4Y2QnwS/ioFu8ecV7MB0GA1UdDgQWBBRWUNGbH8V3
|
||||
av0ESrIUwnvmq4aEEDAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAgBgNV
|
||||
HSUEGTAXBggrBgEFBQcDBAYLKwYBBAGyMQEDBQIwEQYJYIZIAYb4QgEBBAQDAgUg
|
||||
MEYGA1UdIAQ/MD0wOwYMKwYBBAGyMQECAQEBMCswKQYIKwYBBQUHAgEWHWh0dHBz
|
||||
Oi8vc2VjdXJlLmNvbW9kby5uZXQvQ1BTMFcGA1UdHwRQME4wTKBKoEiGRmh0dHA6
|
||||
Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET0NsaWVudEF1dGhlbnRpY2F0aW9uYW5k
|
||||
U2VjdXJlRW1haWxDQS5jcmwwgYgGCCsGAQUFBwEBBHwwejBSBggrBgEFBQcwAoZG
|
||||
aHR0cDovL2NydC5jb21vZG9jYS5jb20vQ09NT0RPQ2xpZW50QXV0aGVudGljYXRp
|
||||
b25hbmRTZWN1cmVFbWFpbENBLmNydDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au
|
||||
Y29tb2RvY2EuY29tMCMGA1UdEQQcMBqBGGNvbW9kby5jb21Ac2NoaWxkYmFjaC5k
|
||||
ZTANBgkqhkiG9w0BAQUFAAOCAQEAMFhmP1Zy16m5L9gaGCDy847tJI3btBFFZMu/
|
||||
MMqamC5515QayLfwf9K2nmu1W63nehEAKqNw+PR1xTYnhPT4fopw5zFndiNg0L5u
|
||||
blEbRgSdQYBh1I2dkzzPRDRJig4LfxVzRzL66FbllLEiJ6oR/XgdsH+JFgyjhk3Y
|
||||
uJt+29sXoZ+ZR29d7l07OikQGI0HWCmp/UiwBcQ4dcTrDB72JYLHyli+OTAkcu9I
|
||||
rBpsIbWJq+7NjaQ/8CJjvQ2neTgDS1Dq5DzMqqRlhxQwRl4dhfCSCcF81Vf0as4S
|
||||
vVDNR8vJ9puGlYyGVJHhQ6mEoFEIvpetS7E9ELHnybSC9ev8CA==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,41 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIHPjCCBiagAwIBAgICH8wwDQYJKoZIhvcNAQEFBQAwgYwxCzAJBgNVBAYTAklM
|
||||
MRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMSswKQYDVQQLEyJTZWN1cmUgRGlnaXRh
|
||||
bCBDZXJ0aWZpY2F0ZSBTaWduaW5nMTgwNgYDVQQDEy9TdGFydENvbSBDbGFzcyAx
|
||||
IFByaW1hcnkgSW50ZXJtZWRpYXRlIENsaWVudCBDQTAeFw0wODA2MjIyMzA4MTJa
|
||||
Fw0wOTA2MjIyMzA4MTJaMIHEMQswCQYDVQQGEwJERTEPMA0GA1UECBMGQmF5ZXJu
|
||||
MREwDwYDVQQHEwhNdWVuY2hlbjEbMBkGA1UEChMSQW5kcmVhcyBTY2hpbGRiYWNo
|
||||
MR4wHAYDVQQLExVQZXJzb25hIG5vdCB2YWxpZGF0ZWQxKTAnBgNVBAMTIFN0YXJ0
|
||||
Q29tIEZyZWUgQ2VydGlmaWNhdGUgTWVtYmVyMSkwJwYJKoZIhvcNAQkBFhpzdGFy
|
||||
dHNzbC5jb21Ac2NoaWxkYmFjaC5kZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
||||
AQoCggEBAOhtSryPHR3gB5E48JZS9y8R3A9I2gRGGon+kRLNh+LCAJJ1hm28Lr41
|
||||
leH0uApWs1WP//qzkXaFUoLlilu/XzkDU48J6HCeUq+7zkxFhq7UxK2lq7J1P8fH
|
||||
tbKYSBWMfzZuVmwhrbaurggfCmq/o5/angbhN7Pn+aV1aPegjAKd8n94HVvVgzkp
|
||||
DDYTA5vFbX/3241MIeKRU5InYw9KzXAC1aE0BYVM21f5Z/UQ+V4PEfXrSH9OHPVW
|
||||
3GWasmjzR9h+/u1omJzejkXY6Ygd15tnmatqMoxRRVMWhWS9Hg7D+AgeiZNlEQZV
|
||||
NTZxIiPA8618x51Wlq0XAiV5UvkMImECAwEAAaOCA24wggNqMAwGA1UdEwQFMAMC
|
||||
AQAwCwYDVR0PBAQDAgSwMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDAd
|
||||
BgNVHQ4EFgQUeMIc15HHtjl2TDpGnc9X2UkUV2EwgagGA1UdIwSBoDCBnYAUU3Lt
|
||||
kpzg2ssBXHx+ljVO8tS4UYKhgYGkfzB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN
|
||||
U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNh
|
||||
dGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRo
|
||||
b3JpdHmCAQ0wggFHBgNVHSAEggE+MIIBOjCCATYGCysGAQQBgbU3AQEFMIIBJTAu
|
||||
BggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNzbC5jb20vcG9saWN5LnBkZjA0
|
||||
BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFydHNzbC5jb20vaW50ZXJtZWRpYXRl
|
||||
LnBkZjCBvAYIKwYBBQUHAgIwga8wFBYNU3RhcnRDb20gTHRkLjADAgEBGoGWTGlt
|
||||
aXRlZCBMaWFiaWxpdHksIHJlYWQgdGhlIHNlY3Rpb24gKkxlZ2FsIExpbWl0YXRp
|
||||
b25zKiBvZiB0aGUgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUG9s
|
||||
aWN5IGF2YWlsYWJsZSBhdCBodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3ku
|
||||
cGRmMGMGA1UdHwRcMFowK6ApoCeGJWh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2Ny
|
||||
dHUxLWNybC5jcmwwK6ApoCeGJWh0dHA6Ly9jcmwuc3RhcnRzc2wuY29tL2NydHUx
|
||||
LWNybC5jcmwwgY4GCCsGAQUFBwEBBIGBMH8wOQYIKwYBBQUHMAGGLWh0dHA6Ly9v
|
||||
Y3NwLnN0YXJ0c3NsLmNvbS9zdWIvY2xhc3MxL2NsaWVudC9jYTBCBggrBgEFBQcw
|
||||
AoY2aHR0cDovL3d3dy5zdGFydHNzbC5jb20vY2VydHMvc3ViLmNsYXNzMS5jbGll
|
||||
bnQuY2EuY3J0MCMGA1UdEgQcMBqGGGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tLzAN
|
||||
BgkqhkiG9w0BAQUFAAOCAQEAIsKaduVCShmIKRsUCqTSeJSDIjgSdRiRmvDig+vT
|
||||
NkRrfhZhtpkp03lfe71agFlaV6UWtFF2nrgFaoUmq2KxMnCD1gkQPQu01TqrDDwi
|
||||
+dKFkh4tSGyj++BRCX4jpYgY7pDzh0Dtb261ovpzYB3e36mMO4AiLHby10VHir+k
|
||||
AUI87JVffsgsKCEEEkywA//KcXqyVfgW3FgicNczCiwXdWCLJcnBAq8aundebdIH
|
||||
hTFoWB/5BuRRCY2Je9XFR8vb1EUC5SuTL+wT0mGdx2T+qNskNtbZKyHLQSp9fCoD
|
||||
yupR1THhr7iqF4zRI6r5r8tRuu8jr55NgN5ZA+LCisEJ7A==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,40 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIHFDCCBfygAwIBAgIDAILwMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
|
||||
TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0
|
||||
YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg
|
||||
MSBQcmltYXJ5IEludGVybWVkaWF0ZSBDbGllbnQgQ0EwHhcNMDkwNjA5MDAwMDAx
|
||||
WhcNMTAwNjA5MjM1OTU5WjB2MR4wHAYDVQQKExVQZXJzb25hIE5vdCBWYWxpZGF0
|
||||
ZWQxKTAnBgNVBAMTIFN0YXJ0Q29tIEZyZWUgQ2VydGlmaWNhdGUgTWVtYmVyMSkw
|
||||
JwYJKoZIhvcNAQkBFhpzdGFydHNzbC5jb21Ac2NoaWxkYmFjaC5kZTCCASIwDQYJ
|
||||
KoZIhvcNAQEBBQADggEPADCCAQoCggEBALA4dtu1FlTbhZQ+M9pyTFte40zotk3J
|
||||
fqvEkDpWLBz3orN4SkMAUDOgTWdvNm+PakX2tEsZGD+nnWzkO3NI8x5ZhrOF3HwW
|
||||
zeCaYzaDjhhRw4G1K2FKVBHK6TUkZ/LoLimVMsV8AbsAWWlmxTCXB1vyoiOMISiK
|
||||
rMFsRFAQdtB5wHVuZdtVnO1++yLfQo+ckuTT35RBztpcP63GkVyo0ucFC8DxNQOA
|
||||
+k8cEIVrfsr9PrLUlhTx+P5jQAaURqcVf0IAR6bNV7WdJmli7yjlWeQm7ymh8YFE
|
||||
6xsy16TO24GQWR5waBFRqGaJPqRnpAdhiUc+1nbNGuaOYYCD6kATVycCAwEAAaOC
|
||||
A5IwggOOMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdJQQWMBQGCCsGAQUF
|
||||
BwMCBggrBgEFBQcDBDAdBgNVHQ4EFgQUY819Gv9zSrHpLGP3e9WbCJfzEgAwJQYD
|
||||
VR0RBB4wHIEac3RhcnRzc2wuY29tQHNjaGlsZGJhY2guZGUwgagGA1UdIwSBoDCB
|
||||
nYAUU3Ltkpzg2ssBXHx+ljVO8tS4UYKhgYGkfzB9MQswCQYDVQQGEwJJTDEWMBQG
|
||||
A1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2Vy
|
||||
dGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlv
|
||||
biBBdXRob3JpdHmCAQ0wggFHBgNVHSAEggE+MIIBOjCCATYGCysGAQQBgbU3AQIA
|
||||
MIIBJTAuBggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNzbC5jb20vcG9saWN5
|
||||
LnBkZjA0BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFydHNzbC5jb20vaW50ZXJt
|
||||
ZWRpYXRlLnBkZjCBvAYIKwYBBQUHAgIwga8wFBYNU3RhcnRDb20gTHRkLjADAgEB
|
||||
GoGWTGltaXRlZCBMaWFiaWxpdHksIHJlYWQgdGhlIHNlY3Rpb24gKkxlZ2FsIExp
|
||||
bWl0YXRpb25zKiBvZiB0aGUgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3Jp
|
||||
dHkgUG9saWN5IGF2YWlsYWJsZSBhdCBodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9w
|
||||
b2xpY3kucGRmMGMGA1UdHwRcMFowK6ApoCeGJWh0dHA6Ly93d3cuc3RhcnRzc2wu
|
||||
Y29tL2NydHUxLWNybC5jcmwwK6ApoCeGJWh0dHA6Ly9jcmwuc3RhcnRzc2wuY29t
|
||||
L2NydHUxLWNybC5jcmwwgY4GCCsGAQUFBwEBBIGBMH8wOQYIKwYBBQUHMAGGLWh0
|
||||
dHA6Ly9vY3NwLnN0YXJ0c3NsLmNvbS9zdWIvY2xhc3MxL2NsaWVudC9jYTBCBggr
|
||||
BgEFBQcwAoY2aHR0cDovL3d3dy5zdGFydHNzbC5jb20vY2VydHMvc3ViLmNsYXNz
|
||||
MS5jbGllbnQuY2EuY3J0MCMGA1UdEgQcMBqGGGh0dHA6Ly93d3cuc3RhcnRzc2wu
|
||||
Y29tLzANBgkqhkiG9w0BAQUFAAOCAQEAaJgOEPjkRcKMVbbofA+GVlc1iMR+kJHk
|
||||
bQNmojAmgDL1pXabFuNZqx7FVUBk7MQQOUaC1vd3RbyOE+AzdXaq7/pFk5/Zxalv
|
||||
xn4gSA/wGHDB0oAi+efWQy7ZsskIOWkjg7tKqy0KCRlA6ZlQhL0aTFZe2X6fu/fI
|
||||
eebFb6gQ3vhOwIgAGz7CZMjRBqPjiqpPrD/Uac2LORUdLw/wowTV1YBnNwsZGnzJ
|
||||
/WquZB7n/yJjaSqhSL0s37AOg3TvXEXYS2GpoA02lQKfq3Lo86piAxSh7aJf7dpT
|
||||
JMVnE6/+5FyjpP8Hpl8FARv1m51c9n788cDzS4/qFibKf9s6yt1/0A==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,6 @@
|
||||
# Create key store for CA certificate
|
||||
keytool -keystore test-cacerts -importcert -file test-cacert.pem -alias test-cacert -deststorepass password
|
||||
|
||||
# Create key store for certificate and private key
|
||||
openssl pkcs12 -export -in test-valid-cert.pem -inkey test-valid-key.pem -passin pass:password -out test-valid.p12 -passout pass:password -name test-valid
|
||||
keytool -importkeystore -deststorepass password -destkeypass password -destkeystore test-valid-cert -srckeystore test-valid.p12 -srcstoretype PKCS12 -srcstorepass password -alias test-valid
|
||||
Binary file not shown.
@@ -0,0 +1,54 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
Proc-Type: 4,ENCRYPTED
|
||||
DEK-Info: DES-EDE3-CBC,621C9B6A0E9C192A
|
||||
|
||||
zj5A0/qeYJ5rmvJqcNoQxaUyEonVZQgLj9Jxw76Wvc1kIMNXsT7MGq2jHaDaUMVd
|
||||
LZDhRgNtirGVdfMFvsNGMB+F1SDq3Dftn/w1jKsNRwCXR958r7ciYp37ohldTEuX
|
||||
0rPQfltHQHkwpCDfi7xOQa06wdSA+Ke8Sek9u77RRhT+nEWOLwJHaIyIbSQr835q
|
||||
bcdW7oTFpAj7OQnEgpKMi2fU9t89N4X+F3foarfSwWGP+e8o9J7/UKKmrWGkB30Q
|
||||
H3U4CbZTXP07ti+ALh86/UaBdaZdDp/pXcJK9OyRSUw693NutSRFw5bXcbobessG
|
||||
lRcgJ5lrKy3F4WhyZMCQNTgr3LzymVn4DkBI3aNCI3a3hbIUi6BRyLF2zUZan5Pl
|
||||
IhsTQM4HLGpuq1AfbWwPvSWoTh+uI9qM9Fenc9kwZvkiMYDf+7kiY6Pt0e8gg16j
|
||||
QQoemZeI+TivyBVerUPV1j+0eBru6ogdxiWoBmZFTFjwpqObV05Zm1BxVAjp3x3+
|
||||
q2gzaYdV/Gca0IaHnmqlZQHwWv5Z0+79bGFta2ThiUR+7Ofgteh0ojlAmAvpHp0n
|
||||
cy6NNr4T81z6QpsHM1zeKbiuUgLlCchwEH0fCsHl0u/EJ7i+4bbugyTdAUiULqxH
|
||||
OpHU2FpuNvSS6BZc2fCmdPflG9yP1jOoAEKb7bcdPRfiJoyMf/ngNaSXsrjzs7NA
|
||||
Z2fZyKC45wtmfpfcQuHP+svWafDx3DCNhQ7Wo7YFBFacV242cjLaYnkgy8XHFHjM
|
||||
KW1Wct5Xg5FEnEcyhczLTZbylSwap9vTAk65cUjLmp/7fE8pLKGfvdRA6VLfbJQ/
|
||||
lnJvBI8valjtCfEMC8s5dNcsn7ISFyTzKMaxjs8DxBRg5eKwr/BPVeXkP21Cf+sO
|
||||
OUAZcgOBJxhb/MQ68Rx2pcjTbmOG81LINkCrwfNGez1gVg3CELneIZGi2ZSn2s5r
|
||||
tFXVJvCrUpSGvx3IC4xKXJ6R6euBE7JdxG0J8aizytlorEhSk294ksupEQUjdeEW
|
||||
RPHqp3LqVlRO1tFYZQrwZs26vgXa15LYXq63EewUCIM4TjNTm3FuovW1d11mCiFl
|
||||
dljkCMGYN+14YnHzd3G96JGxkZUlOCFN+y5Xa2I1x4jkUCvdD3gfMXBxGptkyT+K
|
||||
DlJJQ8JMrRMhRu2K/t8LVorPyHGoYRUoaXLgx/x8xgazLiA8vY8sCJ9A+YM78Bjd
|
||||
ytGQeuUzt5syAXuW3s6AStuMH0Scos674i0qcsd2j5TY4Td6+svuCluvKvsmWW4/
|
||||
pDPNW5c/TXMVU3J9H1AnuHoNQ7rX9++qbptOQHXsf2MY9HtgzYDuY4i/vmJFtTVe
|
||||
zbUqh3trTJ/ihvzq6to6b/AZqsljit7PzLBkXlmQozvlAqy3ycWvyFnVjPgjyEm5
|
||||
9C3uwnD4hiXfmf46nMv+YkaAhYESavLKkbcdQ+cONYnQ2zTJJaKLMHbl+TI5Tjph
|
||||
azuTmQKG72/V8aQBbIVgppoN7FtlIAvZl+k48uZAj2uN7/15ceIBP9Vh0O07EmNa
|
||||
birsXDWm2naQNKYBGrbMCRol8NSnqT3MvG075uZ0mXcyKO39YNxJmdfYgQohTosC
|
||||
dYD20mqdYKbygtvjfucXJoEUJKcB2I795XeZoZl32JgoE0h7q7gLtnUrSnyw8YVo
|
||||
C4s4DL9wXaxuReXQVGczHwPtW9X1Hjm07iuBbkb10Adbl03bd+5J4XbVtdjlshOw
|
||||
YVXHXLY5NfS+hu6jErxNNDjHY0lT+rwif4S9eBjepnpXyZWQRwoJ3SooyK9D6YR4
|
||||
4wpxc4JEglXOPtzqjErGBYxZZdZSD04eVjDV22+Hf6GVcFyEjEFqaEMl0NzOyi+n
|
||||
Svf7ixeo6x3xfUnx9T0mv4YqP62t/RkM9nkFcwKQkZ59cNw+/7XD6DgxO6ev5/25
|
||||
DemqP83feR2MEgwwfh2txi9N5WM0/zJhfxbyv3hImfKa6Br2UoC3O57uKyRVEQ+7
|
||||
dP6wOjJ5swe6kCvk4yj60V/Vr0urVW8xC6IN+2FIfiocJS8mIY5NZRd0CbNkiuZP
|
||||
ntVJwgQ2xwbIOp/+4Od3vBI6ujWmXyaR8k9EpnhM5wP7fb38PprxKdLjRLuGEPNP
|
||||
Z+Cov09oh6cR1GrBqM/gH3mggLZgO4h4WD8gKFkmepXit9Xcigd0ytXfDWE2jgx8
|
||||
du41SrDqYOwVwbkarRA9NDf5Db9dm/vNnw31/cVwUq10Mb7QD/wXPwSIpQbvyJBt
|
||||
1tYcH983hNFKQddNRm+hBP9Vz+nhHPneGjTKU6SxDMcQ3Baep3DwRPl9r9x09z0Y
|
||||
xkBUcCUZ5q+wgFepXYCB9lOBtATnFViFnTdvQuXqvLeOWDjAHBT3TDxzaB+vJMal
|
||||
qD+S4x3BSO64ZIxepl4CHa1Zajp8qzVWYh1rBlTL/Uqjg3O5MuvfO0DGpRCn/6t0
|
||||
CpJF/bcmRBogOvNM7zjMcDSRtIMOVgsfCqqIyXpvA5yZqocwd2o8tdiG0hKQxASV
|
||||
qxvTNTXQZut/xD0enHtDaoYYTHj2c6Ayu7DZfPHvcx40mdYjGI9ZKvXcSrYkfTqc
|
||||
mugXa29jah+1abRWfokV/0S9xuFTkBGPt8/Byw4oT7e8nkJGFQorObqj4gSJhCOf
|
||||
/+wTqhkappSHM0mkF72mNqJLWqMPGFnUq/5x5hws3qNgDbk48TDMWKyM3UEn8IUb
|
||||
zQViQNNVRxtZGTXO8Yhpqv/LgD3I9nk99xFALcBncrkrBIK121pVVM1Yf4TjsdCx
|
||||
zqykQY0cghi6zVE8wkDj6f7Sh8uYe5fP1gorp0rzxyKQh1RwsI6po3GmAA12aIiX
|
||||
3Z5XHE3qL7zeaiN0Mc8EkA7zVVI5Id8Wssdmf3TWRG36J99qzUWxiMsL3lKvgi9d
|
||||
X5Bbxo5l+3hdC31jqrt1w2vemr4bSs5SyBQMnBL2HEsbk7PWzbxD/NdKWYecyYAz
|
||||
OtFy7vAtURxYvS0IbX4uRoeAehyJ7+Ak7tulM4MG9O+w/WseBV7VS1beI9NLZg3S
|
||||
tLLTc/EyLsR9us5AMjDeuIoOSN4mEtFzlq72nyVbUGELN7fXl8Hv75QYh7/SUZt4
|
||||
nH+DbSxMon0SybKTywuwuSoFo/K2lwfyZvNb4R0ImlPpJobANG0knKgzKCTA+m5P
|
||||
-----END RSA PRIVATE KEY-----
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
107
src/test/resources/com/dogecoin/dogecoinj/script/tx_invalid.json
Normal file
107
src/test/resources/com/dogecoin/dogecoinj/script/tx_invalid.json
Normal file
@@ -0,0 +1,107 @@
|
||||
[
|
||||
["The following are deserialized transactions which are invalid."],
|
||||
["They are in the form"],
|
||||
["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"],
|
||||
["serializedTransaction, verifyFlags]"],
|
||||
["Objects that are only a single string (like this one) are ignored"],
|
||||
|
||||
["0e1b5688cf179cd9f7cbda1fac0090f6e684bbf8cd946660120197c3f3681809 but with extra junk appended to the end of the scriptPubKey"],
|
||||
[[["6ca7ec7b1847f6bdbd737176050e6a08d66ccd55bb94ad24f4018024107a5827", 0, "0x41 0x043b640e983c9690a14c039a2037ecc3467b27a0dcd58f19d76c7bc118d09fec45adc5370a1c5bf8067ca9f5557a4cf885fdb0fe0dcc9c3a7137226106fbc779a5 CHECKSIG VERIFY 1"]],
|
||||
"010000000127587a10248001f424ad94bb55cd6cd6086a0e05767173bdbdf647187beca76c000000004948304502201b822ad10d6adc1a341ae8835be3f70a25201bbff31f59cbb9c5353a5f0eca18022100ea7b2f7074e9aa9cf70aa8d0ffee13e6b45dddabf1ab961bda378bcdb778fa4701ffffffff0100f2052a010000001976a914fc50c5907d86fed474ba5ce8b12a66e0a4c139d888ac00000000", "P2SH"],
|
||||
|
||||
["This is the nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG from tx_valid.json"],
|
||||
["but with the signature duplicated in the scriptPubKey with a non-standard pushdata prefix"],
|
||||
["See FindAndDelete, which will only remove if it uses the same pushdata prefix as is standard"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x4c 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]],
|
||||
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"],
|
||||
|
||||
["Same as above, but with the sig in the scriptSig also pushed with the same non-standard OP_PUSHDATA"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x4c 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]],
|
||||
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006b4c473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"],
|
||||
|
||||
["An invalid P2SH Transaction"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", "P2SH"],
|
||||
|
||||
["Tests for CheckTransaction()"],
|
||||
["No inputs"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]],
|
||||
"0100000000010000000000000000015100000000", "P2SH"],
|
||||
|
||||
["No outputs"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x05ab9e14d983742513f0f451e105ffb4198d1dd4 EQUAL"]],
|
||||
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022100f16703104aab4e4088317c862daec83440242411b039d14280e03dd33b487ab802201318a7be236672c5c56083eb7a5a195bc57a40af7923ff8545016cd3b571e2a601232103c40e5d339df3f30bf753e7e04450ae4ef76c9e45587d1d993bdc4cd06f0651c7acffffffff0000000000", "P2SH"],
|
||||
|
||||
["Negative output"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xae609aca8061d77c5e111f6bb62501a6bbe2bfdb EQUAL"]],
|
||||
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d4830450220063222cbb128731fc09de0d7323746539166544d6c1df84d867ccea84bcc8903022100bf568e8552844de664cd41648a031554327aa8844af34b4f27397c65b92c04de0123210243ec37dee0e2e053a9c976f43147e79bc7d9dc606ea51010af1ac80db6b069e1acffffffff01ffffffffffffffff015100000000", "P2SH"],
|
||||
|
||||
["MAX_MONEY + 1 output"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL"]],
|
||||
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010140075af0750700015100000000", "P2SH"],
|
||||
|
||||
["MAX_MONEY output + 1 output"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xb558cbf4930954aa6a344363a15668d7477ae716 EQUAL"]],
|
||||
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510001000000000000015100000000", "P2SH"],
|
||||
|
||||
["Duplicate inputs"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x236d0639db62b0773fd8ac34dc85ae19e9aba80a EQUAL"]],
|
||||
"01000000020001000000000000000000000000000000000000000000000000000000000000000000006c47304402204bb1197053d0d7799bf1b30cd503c44b58d6240cccbdc85b6fe76d087980208f02204beeed78200178ffc6c74237bb74b3f276bbb4098b5605d814304fe128bf1431012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0deaacffffffff0001000000000000000000000000000000000000000000000000000000000000000000006c47304402202306489afef52a6f62e90bf750bbcdf40c06f5c6b138286e6b6b86176bb9341802200dba98486ea68380f47ebb19a7df173b99e6bc9c681d6ccf3bde31465d1f16b3012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0deaacffffffff010000000000000000015100000000", "P2SH"],
|
||||
|
||||
["Coinbase of size 1"],
|
||||
["Note the input is just required to make the tester happy"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]],
|
||||
"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0151ffffffff010000000000000000015100000000", "P2SH"],
|
||||
|
||||
["Coinbase of size 101"],
|
||||
["Note the input is just required to make the tester happy"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]],
|
||||
"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff655151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", "P2SH"],
|
||||
|
||||
["Null txin"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "HASH160 0x14 0x02dae7dbbda56097959cba59b1989dd3e47937bf EQUAL"]],
|
||||
"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6e49304602210086f39e028e46dafa8e1e3be63906465f4cf038fbe5ed6403dc3e74ae876e6431022100c4625c675cfc5c7e3a0e0d7eaec92ac24da20c73a88eb40d09253e51ac6def5201232103a183ddc41e84753aca47723c965d1b5c8b0e2b537963518355e6dd6cf8415e50acffffffff010000000000000000015100000000", "P2SH"],
|
||||
|
||||
["Same as the transactions in valid with one input SIGHASH_ALL and one SIGHASH_ANYONECANPAY, but we set the _ANYONECANPAY sequence number, invalidating the SIGHASH_ALL signature"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"],
|
||||
["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]],
|
||||
"01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df10101000000000200000000000000000000000000000000000000000000000000000000000000000000484730440220201dc2d030e380e8f9cfb41b442d930fa5a685bb2c8db5906671f865507d0670022018d9e7a8d4c8d86a73c2a724ee38ef983ec249827e0e464841735955c707ece98101000000010100000000000000015100000000", "P2SH"],
|
||||
|
||||
["CHECKMULTISIG with incorrect signature order"],
|
||||
["Note the input is just required to make the tester happy"],
|
||||
[[["b3da01dd4aae683c7aee4d5d8b52a540a508e1115f77cd7fa9a291243f501223", 0, "HASH160 0x14 0xb1ce99298d5f07364b57b1e5c9cc00be0b04a954 EQUAL"]],
|
||||
"01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe000048304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f401483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000", "P2SH"],
|
||||
|
||||
|
||||
["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"],
|
||||
["It is an OP_CHECKMULTISIG with the dummy value missing"],
|
||||
[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
|
||||
"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004847304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"],
|
||||
|
||||
|
||||
["CHECKMULTISIG SCRIPT_VERIFY_NULLDUMMY tests:"],
|
||||
|
||||
["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"],
|
||||
["It is an OP_CHECKMULTISIG with the dummy value set to something other than an empty string"],
|
||||
[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
|
||||
"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a010047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"],
|
||||
|
||||
["As above, but using a OP_1"],
|
||||
[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
|
||||
"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000495147304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"],
|
||||
|
||||
["As above, but using a OP_1NEGATE"],
|
||||
[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
|
||||
"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000494f47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"],
|
||||
|
||||
["As above, but with the dummy byte missing"],
|
||||
[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
|
||||
"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004847304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"],
|
||||
|
||||
|
||||
["Empty stack when we try to run CHECKSIG"],
|
||||
[[["ad503f72c18df5801ee64d76090afe4c607fb2b822e9b7b63c5826c50e22fc3b", 0, "0x21 0x027c3a97665bf283a102a587a62a30a0c102d4d3b141015e2cae6f64e2543113e5 CHECKSIG NOT"]],
|
||||
"01000000013bfc220ec526583cb6b7e922b8b27f604cfe0a09764de61e80f58dc1723f50ad0000000000ffffffff0101000000000000002321027c3a97665bf283a102a587a62a30a0c102d4d3b141015e2cae6f64e2543113e5ac00000000", "P2SH"],
|
||||
|
||||
["Make diffs cleaner by leaving a comment here without comma at the end"]
|
||||
]
|
||||
182
src/test/resources/com/dogecoin/dogecoinj/script/tx_valid.json
Normal file
182
src/test/resources/com/dogecoin/dogecoinj/script/tx_valid.json
Normal file
@@ -0,0 +1,182 @@
|
||||
[
|
||||
["The following are deserialized transactions which are valid."],
|
||||
["They are in the form"],
|
||||
["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"],
|
||||
["serializedTransaction, verifyFlags]"],
|
||||
["Objects that are only a single string (like this one) are ignored"],
|
||||
|
||||
["The following is 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"],
|
||||
["It is of particular interest because it contains an invalidly-encoded signature which OpenSSL accepts"],
|
||||
["See http://r6.ca/blog/20111119T211504Z.html"],
|
||||
["It is also the first OP_CHECKMULTISIG transaction in standard form"],
|
||||
[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
|
||||
"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"],
|
||||
|
||||
["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"],
|
||||
["It is an OP_CHECKMULTISIG with an arbitrary extra byte stuffed into the signature at pos length - 2"],
|
||||
["The dummy byte is fine however, so the NULLDUMMY flag should be happy"],
|
||||
[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
|
||||
"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a0048304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2bab01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"],
|
||||
|
||||
["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"],
|
||||
["It is an OP_CHECKMULTISIG with the dummy value set to something other than an empty string"],
|
||||
[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
|
||||
"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a01ff47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"],
|
||||
|
||||
["As above, but using a OP_1"],
|
||||
[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
|
||||
"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000495147304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"],
|
||||
|
||||
["As above, but using a OP_1NEGATE"],
|
||||
[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
|
||||
"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000494f47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"],
|
||||
|
||||
["The following is c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73"],
|
||||
["It is of interest because it contains a 0-sequence as well as a signature of SIGHASH type 0 (which is not a real type)"],
|
||||
[[["406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602", 0, "DUP HASH160 0x14 0xdc44b1164188067c3a32d4780f5996fa14a4f2d9 EQUALVERIFY CHECKSIG"]],
|
||||
"01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3bc062b6b40000000008c493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5000000000100093d00000000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac00000000", "P2SH"],
|
||||
|
||||
["A nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1"]],
|
||||
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"],
|
||||
|
||||
["Same as above, but with the signature duplicated in the scriptPubKey with the proper pushdata prefix"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]],
|
||||
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"],
|
||||
|
||||
["The following is f7fdd091fa6d8f5e7a8c2458f5c38faffff2d3f1406b6e4fe2c99dcc0d2d1cbb"],
|
||||
["It caught a bug in the workaround for 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63 in an overly simple implementation"],
|
||||
[[["b464e85df2a238416f8bdae11d120add610380ea07f4ef19c5f9dfd472f96c3d", 0, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"],
|
||||
["b7978cc96e59a8b13e0865d3f95657561a7f725be952438637475920bac9eb21", 1, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"]],
|
||||
"01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000", "P2SH"],
|
||||
|
||||
["The following tests for the presence of a bug in the handling of SIGHASH_SINGLE"],
|
||||
["It results in signing the constant 1, instead of something generated based on the transaction,"],
|
||||
["when the input doing the signing has an index greater than the maximum output index"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0xe52b482f2faa8ecbf0db344f93c84ac908557f33 EQUALVERIFY CHECKSIG"], ["0000000000000000000000000000000000000000000000000000000000000200", 0, "1"]],
|
||||
"01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000", "P2SH"],
|
||||
|
||||
["An invalid P2SH Transaction"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", "NONE"],
|
||||
|
||||
["A valid P2SH Transaction using the standard transaction type put forth in BIP 16"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x8febbed40483661de6958d957412f82deed8e2f7 EQUAL"]],
|
||||
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000", "P2SH"],
|
||||
|
||||
["Tests for CheckTransaction()"],
|
||||
["MAX_MONEY output"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL"]],
|
||||
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010040075af0750700015100000000", "P2SH"],
|
||||
|
||||
["MAX_MONEY output + 0 output"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xb558cbf4930954aa6a344363a15668d7477ae716 EQUAL"]],
|
||||
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510000000000000000015100000000", "P2SH"],
|
||||
|
||||
["Coinbase of size 2"],
|
||||
["Note the input is just required to make the tester happy"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]],
|
||||
"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff025151ffffffff010000000000000000015100000000", "P2SH"],
|
||||
|
||||
["Coinbase of size 100"],
|
||||
["Note the input is just required to make the tester happy"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]],
|
||||
"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6451515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", "P2SH"],
|
||||
|
||||
["Simple transaction with first input is signed with SIGHASH_ALL, second with SIGHASH_ANYONECANPAY"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"],
|
||||
["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]],
|
||||
"010000000200010000000000000000000000000000000000000000000000000000000000000000000049483045022100d180fd2eb9140aeb4210c9204d3f358766eb53842b2a9473db687fa24b12a3cc022079781799cd4f038b85135bbe49ec2b57f306b2bb17101b17f71f000fcab2b6fb01ffffffff0002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", "P2SH"],
|
||||
|
||||
["Same as above, but we change the sequence number of the first input to check that SIGHASH_ANYONECANPAY is being followed"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"],
|
||||
["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]],
|
||||
"01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df101010000000002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", "P2SH"],
|
||||
|
||||
["afd9c17f8913577ec3509520bd6e5d63e9c0fd2a5f70c787993b097ba6ca9fae which has several SIGHASH_SINGLE signatures"],
|
||||
[[["63cfa5a09dc540bf63e53713b82d9ea3692ca97cd608c384f2aa88e51a0aac70", 0, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"],
|
||||
["04e8d0fcf3846c6734477b98f0f3d4badfb78f020ee097a0be5fe347645b817d", 1, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"],
|
||||
["ee1377aff5d0579909e11782e1d2f5f7b84d26537be7f5516dd4e43373091f3f", 1, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"]],
|
||||
"010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000", "P2SH"],
|
||||
|
||||
["ddc454a1c0c35c188c98976b17670f69e586d9c0f3593ea879928332f0a069e7, which spends an input that pushes using a PUSHDATA1 that is negative when read as signed"],
|
||||
[[["c5510a5dd97a25f43175af1fe649b707b1df8e1a41489bac33a23087027a2f48", 0, "0x4c 0xae 0x606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e207460 DROP DUP HASH160 0x14 0xbfd7436b6265aa9de506f8a994f881ff08cc2872 EQUALVERIFY CHECKSIG"]],
|
||||
"0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c5000000008b483045022100bf0bbae9bde51ad2b222e87fbf67530fbafc25c903519a1e5dcc52a32ff5844e022028c4d9ad49b006dd59974372a54291d5764be541574bb0c4dc208ec51f80b7190141049dd4aad62741dc27d5f267f7b70682eee22e7e9c1923b9c0957bdae0b96374569b460eb8d5b40d972e8c7c0ad441de3d94c4a29864b212d56050acb980b72b2bffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac00000000", "P2SH"],
|
||||
|
||||
["Correct signature order"],
|
||||
["Note the input is just required to make the tester happy"],
|
||||
[[["b3da01dd4aae683c7aee4d5d8b52a540a508e1115f77cd7fa9a291243f501223", 0, "HASH160 0x14 0xb1ce99298d5f07364b57b1e5c9cc00be0b04a954 EQUAL"]],
|
||||
"01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe0000483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa0148304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f4014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000", "P2SH"],
|
||||
|
||||
["cc60b1f899ec0a69b7c3f25ddf32c4524096a9c5b01cbd84c6d0312a0c478984, which is a fairly strange transaction which relies on OP_CHECKSIG returning 0 when checking a completely invalid sig of length 0"],
|
||||
[[["cbebc4da731e8995fe97f6fadcd731b36ad40e5ecb31e38e904f6e5982fa09f7", 0, "0x2102085c6600657566acc2d6382a47bc3f324008d2aa10940dd7705a48aa2a5a5e33ac7c2103f5d0fb955f95dd6be6115ce85661db412ec6a08abcbfce7da0ba8297c6cc0ec4ac7c5379a820d68df9e32a147cffa36193c6f7c43a1c8c69cda530e1c6db354bfabdcfefaf3c875379a820f531f3041d3136701ea09067c53e7159c8f9b2746a56c3d82966c54bbc553226879a5479827701200122a59a5379827701200122a59a6353798277537982778779679a68"]],
|
||||
"0100000001f709fa82596e4f908ee331cb5e0ed46ab331d7dcfaf697fe95891e73dac4ebcb000000008c20ca42095840735e89283fec298e62ac2ddea9b5f34a8cbb7097ad965b87568100201b1b01dc829177da4a14551d2fc96a9db00c6501edfa12f22cd9cefd335c227f483045022100a9df60536df5733dd0de6bc921fab0b3eee6426501b43a228afa2c90072eb5ca02201c78b74266fac7d1db5deff080d8a403743203f109fbcabf6d5a760bf87386d20100ffffffff01c075790000000000232103611f9a45c18f28f06f19076ad571c344c82ce8fcfe34464cf8085217a2d294a6ac00000000", "P2SH"],
|
||||
|
||||
["Empty pubkey"],
|
||||
[[["229257c295e7f555421c1bfec8538dd30a4b5c37c1c8810bbe83cafa7811652c", 0, "0x00 CHECKSIG NOT"]],
|
||||
"01000000012c651178faca83be0b81c8c1375c4b0ad38d53c8fe1b1c4255f5e795c25792220000000049483045022100d6044562284ac76c985018fc4a90127847708c9edb280996c507b28babdc4b2a02203d74eca3f1a4d1eea7ff77b528fde6d5dc324ec2dbfdb964ba885f643b9704cd01ffffffff010100000000000000232102c2410f8891ae918cab4ffc4bb4a3b0881be67c7a1e7faa8b5acf9ab8932ec30cac00000000", "P2SH"],
|
||||
|
||||
["Empty signature"],
|
||||
[[["9ca93cfd8e3806b9d9e2ba1cf64e3cc6946ee0119670b1796a09928d14ea25f7", 0, "0x21 0x028a1d66975dbdf97897e3a4aef450ebeb5b5293e4a0b4a6d3a2daaa0b2b110e02 CHECKSIG NOT"]],
|
||||
"0100000001f725ea148d92096a79b1709611e06e94c63c4ef61cbae2d9b906388efd3ca99c000000000100ffffffff0101000000000000002321028a1d66975dbdf97897e3a4aef450ebeb5b5293e4a0b4a6d3a2daaa0b2b110e02ac00000000", "P2SH"],
|
||||
|
||||
[[["444e00ed7840d41f20ecd9c11d3f91982326c731a02f3c05748414a4fa9e59be", 0, "1 0x00 0x21 0x02136b04758b0b6e363e7a6fbe83aaf527a153db2b060d36cc29f7f8309ba6e458 2 CHECKMULTISIG"]],
|
||||
"0100000001be599efaa4148474053c2fa031c7262398913f1dc1d9ec201fd44078ed004e44000000004900473044022022b29706cb2ed9ef0cb3c97b72677ca2dfd7b4160f7b4beb3ba806aa856c401502202d1e52582412eba2ed474f1f437a427640306fd3838725fab173ade7fe4eae4a01ffffffff010100000000000000232103ac4bba7e7ca3e873eea49e08132ad30c7f03640b6539e9b59903cf14fd016bbbac00000000", "P2SH"],
|
||||
|
||||
[[["e16abbe80bf30c080f63830c8dbf669deaef08957446e95940227d8c5e6db612", 0, "1 0x21 0x03905380c7013e36e6e19d305311c1b81fce6581f5ee1c86ef0627c68c9362fc9f 0x00 2 CHECKMULTISIG"]],
|
||||
"010000000112b66d5e8c7d224059e946749508efea9d66bf8d0c83630f080cf30be8bb6ae100000000490047304402206ffe3f14caf38ad5c1544428e99da76ffa5455675ec8d9780fac215ca17953520220779502985e194d84baa36b9bd40a0dbd981163fa191eb884ae83fc5bd1c86b1101ffffffff010100000000000000232103905380c7013e36e6e19d305311c1b81fce6581f5ee1c86ef0627c68c9362fc9fac00000000", "P2SH"],
|
||||
|
||||
[[["ebbcf4bfce13292bd791d6a65a2a858d59adbf737e387e40370d4e64cc70efb0", 0, "2 0x21 0x033bcaa0a602f0d44cc9d5637c6e515b0471db514c020883830b7cefd73af04194 0x21 0x03a88b326f8767f4f192ce252afe33c94d25ab1d24f27f159b3cb3aa691ffe1423 2 CHECKMULTISIG NOT"]],
|
||||
"0100000001b0ef70cc644e0d37407e387e73bfad598d852a5aa6d691d72b2913cebff4bceb000000004a00473044022068cd4851fc7f9a892ab910df7a24e616f293bcb5c5fbdfbc304a194b26b60fba022078e6da13d8cb881a22939b952c24f88b97afd06b4c47a47d7f804c9a352a6d6d0100ffffffff0101000000000000002321033bcaa0a602f0d44cc9d5637c6e515b0471db514c020883830b7cefd73af04194ac00000000", "P2SH"],
|
||||
|
||||
[[["ba4cd7ae2ad4d4d13ebfc8ab1d93a63e4a6563f25089a18bf0fc68f282aa88c1", 0, "2 0x21 0x037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe1 0x21 0x02edc823cd634f2c4033d94f5755207cb6b60c4b1f1f056ad7471c47de5f2e4d50 2 CHECKMULTISIG NOT"]],
|
||||
"0100000001c188aa82f268fcf08ba18950f263654a3ea6931dabc8bf3ed1d4d42aaed74cba000000004b0000483045022100940378576e069aca261a6b26fb38344e4497ca6751bb10905c76bb689f4222b002204833806b014c26fd801727b792b1260003c55710f87c5adbd7a9cb57446dbc9801ffffffff0101000000000000002321037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe1ac00000000", "P2SH"],
|
||||
|
||||
|
||||
["OP_CODESEPARATOR tests"],
|
||||
|
||||
["Test that SignatureHash() removes OP_CODESEPARATOR with FindAndDelete()"],
|
||||
[[["bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224", 0, "CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIG"]],
|
||||
"01000000012432b60dc72cebc1a27ce0969c0989c895bdd9e62e8234839117f8fc32d17fbc000000004a493046022100a576b52051962c25e642c0fd3d77ee6c92487048e5d90818bcf5b51abaccd7900221008204f8fb121be4ec3b24483b1f92d89b1b0548513a134e345c5442e86e8617a501ffffffff010000000000000000016a00000000", "P2SH"],
|
||||
[[["83e194f90b6ef21fa2e3a365b63794fb5daa844bdc9b25de30899fcfe7b01047", 0, "CODESEPARATOR CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIG"]],
|
||||
"01000000014710b0e7cf9f8930de259bdc4b84aa5dfb9437b665a3e3a21ff26e0bf994e183000000004a493046022100a166121a61b4eeb19d8f922b978ff6ab58ead8a5a5552bf9be73dc9c156873ea02210092ad9bc43ee647da4f6652c320800debcf08ec20a094a0aaf085f63ecb37a17201ffffffff010000000000000000016a00000000", "P2SH"],
|
||||
|
||||
["Hashed data starts at the CODESEPARATOR"],
|
||||
[[["326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e", 0, "0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CODESEPARATOR CHECKSIG"]],
|
||||
"01000000015ebaa001d8e4ec7a88703a3bcf69d98c874bca6299cca0f191512bf2a7826832000000004948304502203bf754d1c6732fbf87c5dcd81258aefd30f2060d7bd8ac4a5696f7927091dad1022100f5bcb726c4cf5ed0ed34cc13dadeedf628ae1045b7cb34421bc60b89f4cecae701ffffffff010000000000000000016a00000000", "P2SH"],
|
||||
|
||||
["But only if execution has reached it"],
|
||||
[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIGVERIFY CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIGVERIFY CODESEPARATOR 1"]],
|
||||
"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a900000000924830450221009c0a27f886a1d8cb87f6f595fbc3163d28f7a81ec3c4b252ee7f3ac77fd13ffa02203caa8dfa09713c8c4d7ef575c75ed97812072405d932bd11e6a1593a98b679370148304502201e3861ef39a526406bad1e20ecad06be7375ad40ddb582c9be42d26c3a0d7b240221009d0a3985e96522e59635d19cc4448547477396ce0ef17a58e7d74c3ef464292301ffffffff010000000000000000016a00000000", "P2SH"],
|
||||
|
||||
["CHECKSIG is legal in scriptSigs"],
|
||||
[[["ccf7f4053a02e653c36ac75c891b7496d0dc5ce5214f6c913d9cf8f1329ebee0", 0, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
|
||||
"0100000001e0be9e32f1f89c3d916c4f21e55cdcd096741b895cc76ac353e6023a05f4f7cc00000000d86149304602210086e5f736a2c3622ebb62bd9d93d8e5d76508b98be922b97160edc3dcca6d8c47022100b23c312ac232a4473f19d2aeb95ab7bdf2b65518911a0d72d50e38b5dd31dc820121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac4730440220508fa761865c8abd81244a168392876ee1d94e8ed83897066b5e2df2400dad24022043f5ee7538e87e9c6aef7ef55133d3e51da7cc522830a9c4d736977a76ef755c0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
|
||||
|
||||
["Same semantics for OP_CODESEPARATOR"],
|
||||
[[["10c9f0effe83e97f80f067de2b11c6a00c3088a4bce42c5ae761519af9306f3c", 1, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
|
||||
"01000000013c6f30f99a5161e75a2ce4bca488300ca0c6112bde67f0807fe983feeff0c91001000000e608646561646265656675ab61493046022100ce18d384221a731c993939015e3d1bcebafb16e8c0b5b5d14097ec8177ae6f28022100bcab227af90bab33c3fe0a9abfee03ba976ee25dc6ce542526e9b2e56e14b7f10121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac493046022100c3b93edcc0fd6250eb32f2dd8a0bba1754b0f6c3be8ed4100ed582f3db73eba2022100bf75b5bd2eff4d6bf2bda2e34a40fcc07d4aa3cf862ceaa77b47b81eff829f9a01ab21038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
|
||||
|
||||
["Signatures are removed from the script they are in by FindAndDelete() in the CHECKSIG code; even multiple instances of one signature can be removed."],
|
||||
[[["6056ebd549003b10cbbd915cea0d82209fe40b8617104be917a26fa92cbe3d6f", 0, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
|
||||
"01000000016f3dbe2ca96fa217e94b1017860be49f20820dea5c91bdcb103b0049d5eb566000000000fd1d0147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac47304402203757e937ba807e4a5da8534c17f9d121176056406a6465054bdd260457515c1a02200f02eccf1bec0f3a0d65df37889143c2e88ab7acec61a7b6f5aa264139141a2b0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
|
||||
|
||||
["That also includes ahead of the opcode being executed."],
|
||||
[[["5a6b0021a6042a686b6b94abc36b387bef9109847774e8b1e51eb8cc55c53921", 1, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
|
||||
"01000000012139c555ccb81ee5b1e87477840991ef7b386bc3ab946b6b682a04a621006b5a01000000fdb40148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f2204148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390175ac4830450220646b72c35beeec51f4d5bc1cbae01863825750d7f490864af354e6ea4f625e9c022100f04b98432df3a9641719dbced53393022e7249fb59db993af1118539830aab870148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a580039017521038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
|
||||
|
||||
["Finally CHECKMULTISIG removes all signatures prior to hashing the script containing those signatures. In conjunction with the SIGHASH_SINGLE bug this lets us test whether or not FindAndDelete() is actually present in scriptPubKey/redeemScript evaluation by including a signature of the digest 0x01 We can compute in advance for our pubkey, embed it it in the scriptPubKey, and then also using a normal SIGHASH_ALL signature. If FindAndDelete() wasn't run, the 'bugged' signature would still be in the hashed script, and the normal signature would fail."],
|
||||
|
||||
["Here's an example on mainnet within a P2SH redeemScript. Remarkably it's a standard transaction in <0.9"],
|
||||
[[["b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9", 0, "DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG"],
|
||||
["ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742", 0, "HASH160 0x14 0xd8dacdadb7462ae15cd906f1878706d0da8660e6 EQUAL"]],
|
||||
"0100000002f9cbafc519425637ba4227f8d0a0b7160b4e65168193d5af39747891de98b5b5000000006b4830450221008dd619c563e527c47d9bd53534a770b102e40faa87f61433580e04e271ef2f960220029886434e18122b53d5decd25f1f4acb2480659fea20aabd856987ba3c3907e0121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffff42e7988254800876b69f24676b3e0205b77be476512ca4d970707dd5c60598ab00000000fd260100483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a53034930460221008431bdfa72bc67f9d41fe72e94c88fb8f359ffa30b33c72c121c5a877d922e1002210089ef5fc22dd8bfc6bf9ffdb01a9862d27687d424d1fefbab9e9c7176844a187a014c9052483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c7153aeffffffff01a08601000000000017a914d8dacdadb7462ae15cd906f1878706d0da8660e68700000000", "P2SH"],
|
||||
|
||||
["Same idea, but with bare CHECKMULTISIG"],
|
||||
[[["ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db", 0, "DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG"],
|
||||
["ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db", 1, "2 0x48 0x3045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 3 CHECKMULTISIG"]],
|
||||
"0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce000000006b4830450221009627444320dc5ef8d7f68f35010b4c050a6ed0d96b67a84db99fda9c9de58b1e02203e4b4aaa019e012e65d69b487fdf8719df72f488fa91506a80c49a33929f1fd50121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce010000009300483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303ffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac00000000", "P2SH"],
|
||||
|
||||
|
||||
["Make diffs cleaner by leaving a comment here without comma at the end"]
|
||||
]
|
||||
@@ -0,0 +1,278 @@
|
||||
type: DETERMINISTIC_MNEMONIC
|
||||
secret_bytes: "aerobic toe save section draw warm cute upon raccoon mother priority pilot taste sweet next traffic fatal sword dentist original crisp team caution rebel"
|
||||
creation_timestamp: 1389353062000
|
||||
deterministic_seed: "E\032\356\206\230,\275\263\364=\334^f\307\037\350\321X7R\262z\205\3564\371tp\2639R\342\027 J\266\253\250\320\022\031\233\271~O$\330\260\214\fz\231tI\353\215*\037\355\205\213.\224?"
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
secret_bytes: "\270E0\202(\362b\023\276\264\347\226E2\360\221\347\325\233L\203\3276\272\213\2436&\304\373\221\025"
|
||||
public_key: "\002\342$\253\332\031\352\324q\316M\251}\274\267\370X$\366>Q\316\005\330\376\353f!WHLL\a"
|
||||
creation_timestamp: 1389353062000
|
||||
deterministic_key {
|
||||
chain_code: "XL\240FW\203\316\230\334\374J\003\357=\215\001\206\365\207Z\006m\334X`\236,;_\304\000^"
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
secret_bytes: "\354B\331\275;\000\254?\3428\006\220G\365\243\333s\260s\213R\313\307\377f\331B\351\327=\001\333"
|
||||
public_key: "\002\357\\\252\376]\023\315\'\316`\317\362\032@\232\"\360\331\335\221] `\016,\351<\b\300\225\032m"
|
||||
deterministic_key {
|
||||
chain_code: "\370\017\223\021O?.@gZ|\233j\3437\317q-\241!J \323\'\264s\203\314\321\v\346"
|
||||
path: 2147483648
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
secret_bytes: "<M\020I\364\276\336Z\255\341\330\257\337 \366E_\027\2433w\325\263\"$\350\f\244\006\251u\021"
|
||||
public_key: "\002\361V\216\001\371p\270\212\272\236%\216\356o\025g\r\035>a\305j\001P\217Q\242\261.\353\367\315"
|
||||
deterministic_key {
|
||||
chain_code: "\231B\211S[\216\237\277q{a\365\216\325\250\223s\v\n(\364\257@3c\312rix\260c\217"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
issued_subkeys: 2
|
||||
lookahead_size: 10
|
||||
sigsRequiredToSpend: 1
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
secret_bytes: "\f0\266\235\272\205\212:\265\372\214P\226\344\a{S0\354\250\210\316L\256;W\036\200t\347\343\246"
|
||||
public_key: "\0022\n\252\267NDr.7i7\332\232x\367\204G-|\204\301\333G\033g\300O\241\006\217\366\370"
|
||||
deterministic_key {
|
||||
chain_code: "\213\237\327\245a\273\274\310\377\360\351\352<\211k\033g\0251>y\236\345Jb\244[\b\fO\0311"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
issued_subkeys: 1
|
||||
lookahead_size: 10
|
||||
sigsRequiredToSpend: 1
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002O_Q\223\337\360\245\234\322b_op\b?\030\364\255l\206\344`w\274\204\"\257\235U<}\377"
|
||||
deterministic_key {
|
||||
chain_code: "\331\233\342\227\336r\212>\021\022p\347* +\220\021{\206\310Z\314\335\322\230\331\365\221}\321\036\035"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 0
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003\270\311\006\363\375\002{\310\254n\301\366\303\315\255\3462\004/\251\'\205+\341~d\275\350\"\313\204\313"
|
||||
deterministic_key {
|
||||
chain_code: "5\037!\360\335\017\276\231\273\3531\020\253\223 \312\240M+\250\2520e\006\034\214{\331\376\201\004\306"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 1
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003\000\n\256n\324$.\324\365\231\f\224\001\376\266\341\036Q\212\374>\245\324\\8*\342\370\251x\b-"
|
||||
deterministic_key {
|
||||
chain_code: "5\202n|A\251$y+t\005\365\231\357\323\264E\266l\220\367\211dA\306\370\247<\'\034\323\324"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 2
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002\313/\026\020\254\240\3455\216\342E\300\316\353m.\270\204\264\327\220H\326E9\310\227 \023~\204\215"
|
||||
deterministic_key {
|
||||
chain_code: "\342\263a\033~\374\234UN\034\302\300\370\232\347B#L\251\267\035\255\210\356\vE\264\210\317\030]t"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 3
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002\217\n\021GL\354\214\354WhX\254\351\337w.\211&q1o\003\033\330\352**\351\356\210\264m"
|
||||
deterministic_key {
|
||||
chain_code: "\036\216\345\320e\267p\241\000\204\254\370\251d\000\253\354\316RH\275RS\221\016\343=T\236\335\222P"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 4
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003\325\n\347\346\3273\312J\211e\335?\227\236\304i\227\377J\222;\253\017\213\371\235d\220\231\026aV"
|
||||
deterministic_key {
|
||||
chain_code: "YSn>5\364i(j\b\326\212,\f,\322\3200\230\210)\366g\201\274\232\356\027\212O\345\215"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 5
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003\264\331\220\207*\342T\277\323\363\210\266\335\300\245?\024d\002\021\263|\253\035\253\244D\023\004\200\212X"
|
||||
deterministic_key {
|
||||
chain_code: "yP\342|\327\364\034\f\302}\236\032\031\t\345h(q7\346?wR\221\325\370\021\225\334\317Bg"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 6
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002HX\261\035\270!\263\2232-F\334\226n=<\0178\270^\202\225\264PF\v#\bdP/\355"
|
||||
deterministic_key {
|
||||
chain_code: "Z#\227\222\225\303\203\006q\206\321\v\355\353\220#Oh\360]\001IQD\333\025\356\276\342\270\021\313"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 7
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002\020C\2310\227\302\342\274u\217\021h\270\235\356\326_\365\321\261\272\340\267\n\335~\360\343\"Ow\b"
|
||||
deterministic_key {
|
||||
chain_code: "\232\000\3117\235\003`)\021g}/\203tk\201\021\364\247\245;\253\321\202\207\342\265\267_<\206\224"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 8
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002\276\211n\305\3339[D\337+\034\263\267U0\263\3039}/\376\207\030\364K\335\301\245\311\241\3419"
|
||||
deterministic_key {
|
||||
chain_code: "B\232\f\')\277\034\316HOdn\213\b\204\361\030\357YS \365zY\2749e\260)\233.-"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 9
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002h\356\202\222P\204x\345\226\017\256/E\304\273{)\272\034\375\2451\321\257\233\372?\320\352\356\271K"
|
||||
deterministic_key {
|
||||
chain_code: "\035\222\325\fY\221(\006\tf#7\370\355el\377\276\245\354\002\327\320\247\315V\004\016v\367\351\225"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 10
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002\325\313@\"\320\035\277(\245\222\342{\374g\235\203\347\217\035\204j\027\034\244\021bY0\247P`\323"
|
||||
deterministic_key {
|
||||
chain_code: "\226~!\327\210.\033\214\251\2367\205<\226`UF\354\234/\365\267E\317\202\354\211P\244\221\336\200"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 11
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003\000\334\035\2400n\26636x\316\327\3666\271\375K\031\366\307\221J@\331@dL\232Bv\324\262"
|
||||
deterministic_key {
|
||||
chain_code: "\207^n\317\370\t\207\341*\\\360\026iBRTQ#\252Z\237\373{\315\333\004\340nA9\252\352"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 12
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002\225b\3515\202\233\335\320.7\265\274uh\230N\242\254\317J\364\331\2345\220)\362\334\216\202\\"
|
||||
deterministic_key {
|
||||
chain_code: "\202:\344\3109?\350\345\001\314(\244q\370\233Rk\261}\302(\275\326\305R\342:\246\036\nV\330"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 0
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003>K!8\222VEL\371\305 z\aD8\020\233\330S\251T\330\201V\026-k2\227\266;"
|
||||
deterministic_key {
|
||||
chain_code: "\223\265.\200\316\361\241{\223\342c\212\0213ym+\032=#\360\333X\003\2770Z\311\335\267\342\313"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 1
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003\331t\251d\023\355w\221\266\301\264\306T\252\350\200\260A\220\363\212\345\021\222\236\003\210\215\342\r\251\000"
|
||||
deterministic_key {
|
||||
chain_code: "\276\262\033\030\227\271&e\254\377\346\031\2112\344[\234Z\221-\033\306P,Mi\021\313r\031\317\341"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 2
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002D\374\231\027\306\310\251\261\200\350@\ro\314\216\037>rp\017\276Q\203\027\016\213\320\206VqO\237"
|
||||
deterministic_key {
|
||||
chain_code: "_K4\n\356\235\036\243O\261\200\004\367\324\305;1\247I\350*\353`\204\004d\202\302\335\200/#"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 3
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003\370\352\3530]|\262\270]5\361\263\255)\027f\342\262\272a-\275\006\302\266\236\344\332\364\r\260\321"
|
||||
deterministic_key {
|
||||
chain_code: "o!GH\357\030\264\003_S\305\204\234wO\344.\215\377\232\025\206\351\030\227,\303%U2x\225"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 4
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002\221\021\370a[\205\267\036\021\366`\036\371\253Yk\r\303\025\f\255\2768\310\212\234\221\333\344\340t"
|
||||
deterministic_key {
|
||||
chain_code: "\370~\245F\n\307\377Q:\v\207\245\336F\376\2443R\034\346\b\372\b\\o\303\204D#}\266"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 5
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002c\034w@c\225\257n~G\330\002\241^\264\231\030\025\220gr\202`u\b\262\361\312\246\202J\341"
|
||||
deterministic_key {
|
||||
chain_code: "\\\2542\003\022\254\361*\a/4\307\3430\322\303\v\205\351\027\260 l\332\326\235<\363v\020\232"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 6
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003\266\304\006g\244l\271>\364\357G8B\374\026w\316\022\205\313\220\274\273>$\350\212o!\rt\230"
|
||||
deterministic_key {
|
||||
chain_code: "6]\325WN\017o\255\314\213\344\201f\204\361\235\'\343\217\341m\327\326=T\2018g\324\261`\335"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 7
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003X\331\344\227G\366//<V\226\b\352#\315\307j\263\232\273d\236)\004\225fk\304\000XM\305"
|
||||
deterministic_key {
|
||||
chain_code: "&\025?\264\a\2334-\203\217\240R\221[{8)9\221\346bv=ut\346\226KVj\2659"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 8
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003\307\273B\334\212\303\025r\212\264|\250c\204\\=\360w\335\300\353\266\273\3209\260nl3\271+"
|
||||
deterministic_key {
|
||||
chain_code: "\345\365\034\261\316\2121R\226/+\267K\326C&\236\246],\224\001\220\347\334\351\223K\023\252\360\023"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 9
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002+[\230[E\225\225R2\350X=\366\343\244\237\260\220J\311\376\200@\\\334\312y\212\276\223\350\267"
|
||||
deterministic_key {
|
||||
chain_code: "\250W]}O:@\t\016\311\016\335\016\271\260\327\261\237\030G\334\246\233\352t\266\\S\311\333m*"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 10
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003-\221uJ\237\240\320\025\031w\001V\276\030j\217Z\222 \330\253\332\330F\216\377D\311\211\277\351\230"
|
||||
deterministic_key {
|
||||
chain_code: "\241\363\245\033W\f*J\026\021\210Ic\2318a\"\036\302\005+\220\003\3364\211o\362\225R~\340"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 11
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002V\3212\255\n\367\226%]0\342\003\317\031\350\265K\247\035\005}\004[N\262\262\376Ed\261j\377"
|
||||
deterministic_key {
|
||||
chain_code: "0\236\330H\354\237\016\367-/E\344\311\024\353\307\331\367n\017\250n\351\000\204\233\224\242L\343&;"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 12
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002\357\\\252\376]\023\315\'\316`\317\362\032@\232\"\360\331\335\221] `\016,\351<\b\300\225\032m"
|
||||
creation_timestamp: 100000000
|
||||
deterministic_key {
|
||||
chain_code: "\370\017\223\021O?.@gZ|\233j\3437\317q-\241!J \323\'\264s\203\314\321\v\346"
|
||||
path: 2147483648
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002\361V\216\001\371p\270\212\272\236%\216\356o\025g\r\035>a\305j\001P\217Q\242\261.\353\367\315"
|
||||
deterministic_key {
|
||||
chain_code: "\231B\211S[\216\237\277q{a\365\216\325\250\223s\v\n(\364\257@3c\312rix\260c\217"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
issued_subkeys: 2
|
||||
lookahead_size: 10
|
||||
sigsRequiredToSpend: 1
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\0022\n\252\267NDr.7i7\332\232x\367\204G-|\204\301\333G\033g\300O\241\006\217\366\370"
|
||||
deterministic_key {
|
||||
chain_code: "\213\237\327\245a\273\274\310\377\360\351\352<\211k\033g\0251>y\236\345Jb\244[\b\fO\0311"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
issued_subkeys: 1
|
||||
lookahead_size: 10
|
||||
sigsRequiredToSpend: 1
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002O_Q\223\337\360\245\234\322b_op\b?\030\364\255l\206\344`w\274\204\"\257\235U<}\377"
|
||||
deterministic_key {
|
||||
chain_code: "\331\233\342\227\336r\212>\021\022p\347* +\220\021{\206\310Z\314\335\322\230\331\365\221}\321\036\035"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 0
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003\270\311\006\363\375\002{\310\254n\301\366\303\315\255\3462\004/\251\'\205+\341~d\275\350\"\313\204\313"
|
||||
deterministic_key {
|
||||
chain_code: "5\037!\360\335\017\276\231\273\3531\020\253\223 \312\240M+\250\2520e\006\034\214{\331\376\201\004\306"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 1
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003\000\n\256n\324$.\324\365\231\f\224\001\376\266\341\036Q\212\374>\245\324\\8*\342\370\251x\b-"
|
||||
deterministic_key {
|
||||
chain_code: "5\202n|A\251$y+t\005\365\231\357\323\264E\266l\220\367\211dA\306\370\247<\'\034\323\324"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 2
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002\313/\026\020\254\240\3455\216\342E\300\316\353m.\270\204\264\327\220H\326E9\310\227 \023~\204\215"
|
||||
deterministic_key {
|
||||
chain_code: "\342\263a\033~\374\234UN\034\302\300\370\232\347B#L\251\267\035\255\210\356\vE\264\210\317\030]t"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 3
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002\217\n\021GL\354\214\354WhX\254\351\337w.\211&q1o\003\033\330\352**\351\356\210\264m"
|
||||
deterministic_key {
|
||||
chain_code: "\036\216\345\320e\267p\241\000\204\254\370\251d\000\253\354\316RH\275RS\221\016\343=T\236\335\222P"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 4
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003\325\n\347\346\3273\312J\211e\335?\227\236\304i\227\377J\222;\253\017\213\371\235d\220\231\026aV"
|
||||
deterministic_key {
|
||||
chain_code: "YSn>5\364i(j\b\326\212,\f,\322\3200\230\210)\366g\201\274\232\356\027\212O\345\215"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 5
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003\264\331\220\207*\342T\277\323\363\210\266\335\300\245?\024d\002\021\263|\253\035\253\244D\023\004\200\212X"
|
||||
deterministic_key {
|
||||
chain_code: "yP\342|\327\364\034\f\302}\236\032\031\t\345h(q7\346?wR\221\325\370\021\225\334\317Bg"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 6
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002HX\261\035\270!\263\2232-F\334\226n=<\0178\270^\202\225\264PF\v#\bdP/\355"
|
||||
deterministic_key {
|
||||
chain_code: "Z#\227\222\225\303\203\006q\206\321\v\355\353\220#Oh\360]\001IQD\333\025\356\276\342\270\021\313"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 7
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002\020C\2310\227\302\342\274u\217\021h\270\235\356\326_\365\321\261\272\340\267\n\335~\360\343\"Ow\b"
|
||||
deterministic_key {
|
||||
chain_code: "\232\000\3117\235\003`)\021g}/\203tk\201\021\364\247\245;\253\321\202\207\342\265\267_<\206\224"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 8
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002\276\211n\305\3339[D\337+\034\263\267U0\263\3039}/\376\207\030\364K\335\301\245\311\241\3419"
|
||||
deterministic_key {
|
||||
chain_code: "B\232\f\')\277\034\316HOdn\213\b\204\361\030\357YS \365zY\2749e\260)\233.-"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 9
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002h\356\202\222P\204x\345\226\017\256/E\304\273{)\272\034\375\2451\321\257\233\372?\320\352\356\271K"
|
||||
deterministic_key {
|
||||
chain_code: "\035\222\325\fY\221(\006\tf#7\370\355el\377\276\245\354\002\327\320\247\315V\004\016v\367\351\225"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 10
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002\325\313@\"\320\035\277(\245\222\342{\374g\235\203\347\217\035\204j\027\034\244\021bY0\247P`\323"
|
||||
deterministic_key {
|
||||
chain_code: "\226~!\327\210.\033\214\251\2367\205<\226`UF\354\234/\365\267E\317\202\354\211P\244\221\336\200"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 11
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003\000\334\035\2400n\26636x\316\327\3666\271\375K\031\366\307\221J@\331@dL\232Bv\324\262"
|
||||
deterministic_key {
|
||||
chain_code: "\207^n\317\370\t\207\341*\\\360\026iBRTQ#\252Z\237\373{\315\333\004\340nA9\252\352"
|
||||
path: 2147483648
|
||||
path: 0
|
||||
path: 12
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002\225b\3515\202\233\335\320.7\265\274uh\230N\242\254\317J\364\331\2345\220)\362\334\216\202\\"
|
||||
deterministic_key {
|
||||
chain_code: "\202:\344\3109?\350\345\001\314(\244q\370\233Rk\261}\302(\275\326\305R\342:\246\036\nV\330"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 0
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003>K!8\222VEL\371\305 z\aD8\020\233\330S\251T\330\201V\026-k2\227\266;"
|
||||
deterministic_key {
|
||||
chain_code: "\223\265.\200\316\361\241{\223\342c\212\0213ym+\032=#\360\333X\003\2770Z\311\335\267\342\313"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 1
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003\331t\251d\023\355w\221\266\301\264\306T\252\350\200\260A\220\363\212\345\021\222\236\003\210\215\342\r\251\000"
|
||||
deterministic_key {
|
||||
chain_code: "\276\262\033\030\227\271&e\254\377\346\031\2112\344[\234Z\221-\033\306P,Mi\021\313r\031\317\341"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 2
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002D\374\231\027\306\310\251\261\200\350@\ro\314\216\037>rp\017\276Q\203\027\016\213\320\206VqO\237"
|
||||
deterministic_key {
|
||||
chain_code: "_K4\n\356\235\036\243O\261\200\004\367\324\305;1\247I\350*\353`\204\004d\202\302\335\200/#"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 3
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003\370\352\3530]|\262\270]5\361\263\255)\027f\342\262\272a-\275\006\302\266\236\344\332\364\r\260\321"
|
||||
deterministic_key {
|
||||
chain_code: "o!GH\357\030\264\003_S\305\204\234wO\344.\215\377\232\025\206\351\030\227,\303%U2x\225"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 4
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002\221\021\370a[\205\267\036\021\366`\036\371\253Yk\r\303\025\f\255\2768\310\212\234\221\333\344\340t"
|
||||
deterministic_key {
|
||||
chain_code: "\370~\245F\n\307\377Q:\v\207\245\336F\376\2443R\034\346\b\372\b\\o\303\204D#}\266"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 5
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002c\034w@c\225\257n~G\330\002\241^\264\231\030\025\220gr\202`u\b\262\361\312\246\202J\341"
|
||||
deterministic_key {
|
||||
chain_code: "\\\2542\003\022\254\361*\a/4\307\3430\322\303\v\205\351\027\260 l\332\326\235<\363v\020\232"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 6
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003\266\304\006g\244l\271>\364\357G8B\374\026w\316\022\205\313\220\274\273>$\350\212o!\rt\230"
|
||||
deterministic_key {
|
||||
chain_code: "6]\325WN\017o\255\314\213\344\201f\204\361\235\'\343\217\341m\327\326=T\2018g\324\261`\335"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 7
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003X\331\344\227G\366//<V\226\b\352#\315\307j\263\232\273d\236)\004\225fk\304\000XM\305"
|
||||
deterministic_key {
|
||||
chain_code: "&\025?\264\a\2334-\203\217\240R\221[{8)9\221\346bv=ut\346\226KVj\2659"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 8
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003\307\273B\334\212\303\025r\212\264|\250c\204\\=\360w\335\300\353\266\273\3209\260nl3\271+"
|
||||
deterministic_key {
|
||||
chain_code: "\345\365\034\261\316\2121R\226/+\267K\326C&\236\246],\224\001\220\347\334\351\223K\023\252\360\023"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 9
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002+[\230[E\225\225R2\350X=\366\343\244\237\260\220J\311\376\200@\\\334\312y\212\276\223\350\267"
|
||||
deterministic_key {
|
||||
chain_code: "\250W]}O:@\t\016\311\016\335\016\271\260\327\261\237\030G\334\246\233\352t\266\\S\311\333m*"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 10
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\003-\221uJ\237\240\320\025\031w\001V\276\030j\217Z\222 \330\253\332\330F\216\377D\311\211\277\351\230"
|
||||
deterministic_key {
|
||||
chain_code: "\241\363\245\033W\f*J\026\021\210Ic\2318a\"\036\302\005+\220\003\3364\211o\362\225R~\340"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 11
|
||||
}
|
||||
|
||||
type: DETERMINISTIC_KEY
|
||||
public_key: "\002V\3212\255\n\367\226%]0\342\003\317\031\350\265K\247\035\005}\004[N\262\262\376Ed\261j\377"
|
||||
deterministic_key {
|
||||
chain_code: "0\236\330H\354\237\016\367-/E\344\311\024\353\307\331\367n\017\250n\351\000\204\233\224\242L\343&;"
|
||||
path: 2147483648
|
||||
path: 1
|
||||
path: 12
|
||||
}
|
||||
BIN
src/test/resources/org/bitcoinj/core/auxpow_merkle_branch.bin
Normal file
BIN
src/test/resources/org/bitcoinj/core/auxpow_merkle_branch.bin
Normal file
Binary file not shown.
BIN
src/test/resources/org/bitcoinj/core/auxpow_merkle_branch2.bin
Normal file
BIN
src/test/resources/org/bitcoinj/core/auxpow_merkle_branch2.bin
Normal file
Binary file not shown.
BIN
src/test/resources/org/bitcoinj/core/dogecoin_block1.bin
Normal file
BIN
src/test/resources/org/bitcoinj/core/dogecoin_block1.bin
Normal file
Binary file not shown.
BIN
src/test/resources/org/bitcoinj/core/dogecoin_block250000.bin
Normal file
BIN
src/test/resources/org/bitcoinj/core/dogecoin_block250000.bin
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
src/test/resources/org/bitcoinj/core/dogecoin_block371337.bin
Normal file
BIN
src/test/resources/org/bitcoinj/core/dogecoin_block371337.bin
Normal file
Binary file not shown.
@@ -0,0 +1 @@
|
||||
020162000d6f03470d329026cd1fc720c0609cd378ca8691a117bd1aa46f01fb09b1a8468a15bf6f0b0e83f2e5036684169eafb9406468d4f075c999fb5b2a78fbb827ee41fb11548441361b0000000001000000010000000000000000000000000000000000000000000000000000000000000000ffffffff380345bf09fabe6d6d980ba42120410de0554d42a5b5ee58167bcd86bf7591f429005f24da45fb51cf0800000000000000cdb1f1ff0e000000ffffffff01800c0c2a010000001976a914aa3750aa18b8a0f3f0590731e1fab934856680cf88ac00000000b3e64e02fff596209c498f1b18f798d62f216f11c8462bf3922319000000000003a979a636db2450363972d211aee67b71387a3daaa3051be0fd260c5acd4739cd52a418d29d8a0e56c8714c95a0dc24e1c9624480ec497fe2441941f3fee8f9481a3370c334178415c83d1d0c2deeec727c2330617a47691fc5e79203669312d100000000036fa40307b3a439538195245b0de56a2c1db6ba3a64f8bdd2071d00bc48c841b5e77b98e5c7d6f06f92dec5cf6d61277ecb9a0342406f49f34c51ee8ce4abd678038129485de14238bd1ca12cd2de12ff0e383aee542d90437cd664ce139446a00000000002000000d2ec7dfeb7e8f43fe77aba3368df95ac2088034420402730ee0492a2084217083411b3fc91033bfdeea339bc11b9efc986e161c703e07a9045338c165673f09940fb11548b54021b58cc9ae50601000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0d0389aa050101062f503253482fffffffff010066f33caf050000232102b73438165461b826b30a46078f211aa005d1e7e430b1e0ed461678a5fe516c73ac000000000100000001ef2e86aa5f027e13d7fc1f0bd4a1fc677d698e42850680634ccd1834668ff320010000006b483045022100fcf5dc43afa85978a71e76a9f4c11cd6bf2a7d5677212f9001ad085d420a5d3a022068982e1e53e94fc6007cf8b60ff3919bcaf7f0b70fefb79112cb840777d8c7cf0121022b050b740dd02c1b4e1e7cdbffe6d836d987c9db4c4db734b58526f08942193bffffffff02004e7253000000001976a91435cb1f77e88e96fb3094d84e8d3b7789a092636d88ac00d4b7e8b00700001976a9146ca1f634daa4efc7871abab945c7cefd282b481f88ac0000000001000000010a6c24bbc92fd0ec32bb5b0a051c44eba0c1325f0b24d9523c109f8bb1281f49000000006a4730440220608577619fb3a0b826f09df5663ffbf121c8e0164f43b73d9affe2f9e4576bd0022040782c9a7df0a20afe1a7e3578bf27e1331c862253af21ced4fde5ef1b44b787012103e4f91ad831a87cc532249944bc7138a355f7d0aac25dc4737a8701181ce680a5ffffffff010019813f0d0000001976a91481db1aa49ebc6a71cad96949eb28e22af85eb0bd88ac0000000001000000017b82db0f644ecff378217d9b8dc0de8817eaf85ceefacab23bf344e2e495dca5010000006b483045022100f07ced6bfdbd6cdeb8b2c8fc92b9803f5798754b5b6c454c8f084198bea303f402205616f84d7ec882af9c34a3fd2457ca3fb81ec5a463a963a6e684edee427d4525012102c056b10494520dbd7b37e2e6bb8f72f98d73a609a926901221bfb114fa1d5a80ffffffff02f0501a22000000001976a914ca63ded8b23d0252158a3bdc816747ef89fb438988ac80b65ea1350700001976a914fb26a7c16ace531a8e7bbd925e46c67c3150c1c888ac000000000100000001c9bdba900e1579ebf4e44415fe8b9abec57a763f8c70a30604bea7fbe7c55d42000000006a47304402204ccbeeace0630e72102fdaf0836e41f8f6dcdde6a178f0fbc2d96a4d17a1df8f02207e4a91203a2abd87fdddee96510482ef96535741b6c17a1acae93c977ad248e5012103e0747583a342b76a5de9c21db138b9640d49b4f3b67a306d3b3f217416d49b55ffffffff020058850c020000001976a9144417c63a91208a02a5f46a0f7a2b806adc7d19a788ac0042dc06030000001976a9147b61c5adef0d559e5acf2901c2989294624b651988ac0000000001000000017c1423b198dfc3da37ae9a5fc11a3720e4343b3049d3b289b8285eb04595c04b000000006b483045022100b0c1cb9608bf644d7a8916bf61f36ced95bd045e97612804ca774f60e05e7bde022017c12255eecc474c8d8b05d0910013b2df8703af68212cf0962b6b8ee0e101ee01210341e154088c23b8ea943bca94c1d4f65361668a242b168522f00199365414b46affffffff01019891ad000000001976a91481db1aa49ebc6a71cad96949eb28e22af85eb0bd88ac00000000
|
||||
400
src/wallet.proto
Normal file
400
src/wallet.proto
Normal file
@@ -0,0 +1,400 @@
|
||||
/** Copyright 2013 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Authors: Jim Burton, Miron Cuperman, Andreas Schildbach
|
||||
*/
|
||||
|
||||
/* Notes:
|
||||
* - Endianness: All byte arrays that represent numbers (such as hashes and private keys) are Big Endian
|
||||
* - To regenerate after editing, run: mvn generate-sources -DupdateProtobuf
|
||||
*/
|
||||
|
||||
package wallet;
|
||||
|
||||
option java_package = "com.dogecoin.dogecoinj.wallet";
|
||||
option java_outer_classname = "Protos";
|
||||
|
||||
message PeerAddress {
|
||||
required bytes ip_address = 1;
|
||||
required uint32 port = 2;
|
||||
required uint64 services = 3;
|
||||
}
|
||||
|
||||
message EncryptedData {
|
||||
required bytes initialisation_vector = 1; // The initialisation vector for the AES encryption (16 bytes)
|
||||
required bytes encrypted_private_key = 2; // The encrypted private key
|
||||
}
|
||||
|
||||
/**
|
||||
* Data attached to a Key message that defines the data needed by the BIP32 deterministic key hierarchy algorithm.
|
||||
*/
|
||||
message DeterministicKey {
|
||||
// Random data that allows us to extend a key. Without this, we can't figure out the next key in the chain and
|
||||
// should just treat it as a regular ORIGINAL type key.
|
||||
required bytes chain_code = 1;
|
||||
|
||||
// The path through the key tree. Each number is encoded in the standard form: high bit set for private derivation
|
||||
// and high bit unset for public derivation.
|
||||
repeated uint32 path = 2;
|
||||
|
||||
// How many children of this key have been issued, that is, given to the user when they requested a fresh key?
|
||||
// For the parents of keys being handed out, this is always less than the true number of children: the difference is
|
||||
// called the lookahead zone. These keys are put into Bloom filters so we can spot transactions made by clones of
|
||||
// this wallet - for instance when restoring from backup or if the seed was shared between devices.
|
||||
//
|
||||
// If this field is missing it means we're not issuing subkeys of this key to users.
|
||||
optional uint32 issued_subkeys = 3;
|
||||
optional uint32 lookahead_size = 4;
|
||||
|
||||
/**
|
||||
* Flag indicating that this key is a root of a following chain. This chain is following the next non-following chain.
|
||||
* Following/followed chains concept is used for married keychains, where the set of keys combined together to produce
|
||||
* a single P2SH multisignature address
|
||||
*/
|
||||
optional bool isFollowing = 5;
|
||||
|
||||
// Number of signatures required to spend. This field is needed only for married keychains to reconstruct KeyChain
|
||||
// and represents the N value from N-of-M CHECKMULTISIG script. For regular single keychains it will always be 1.
|
||||
optional uint32 sigsRequiredToSpend = 6 [default = 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* A key used to control Bitcoin spending.
|
||||
*
|
||||
* Either the private key, the public key or both may be present. It is recommended that
|
||||
* if the private key is provided that the public key is provided too because deriving it is slow.
|
||||
*
|
||||
* If only the public key is provided, the key can only be used to watch the blockchain and verify
|
||||
* transactions, and not for spending.
|
||||
*/
|
||||
message Key {
|
||||
enum Type {
|
||||
/** Unencrypted - Original bitcoin secp256k1 curve */
|
||||
ORIGINAL = 1;
|
||||
|
||||
/** Encrypted with Scrypt and AES - Original bitcoin secp256k1 curve */
|
||||
ENCRYPTED_SCRYPT_AES = 2;
|
||||
|
||||
/**
|
||||
* Not really a key, but rather contains the mnemonic phrase for a deterministic key hierarchy in the private_key field.
|
||||
* The label and public_key fields are missing. Creation timestamp will exist.
|
||||
*/
|
||||
DETERMINISTIC_MNEMONIC = 3;
|
||||
|
||||
/**
|
||||
* A key that was derived deterministically. Note that the root seed that created it may NOT be present in the
|
||||
* wallet, for the case of watching wallets. A deterministic key may or may not have the private key bytes present.
|
||||
* However the public key bytes and the deterministic_key field are guaranteed to exist. In a wallet where there
|
||||
* is a path from this key up to a key that has (possibly encrypted) private bytes, it's expected that the private
|
||||
* key can be rederived on the fly.
|
||||
*/
|
||||
DETERMINISTIC_KEY = 4;
|
||||
}
|
||||
required Type type = 1;
|
||||
|
||||
// Either the private EC key bytes (without any ASN.1 wrapping), or the deterministic root seed.
|
||||
// If the secret is encrypted, or this is a "watching entry" then this is missing.
|
||||
optional bytes secret_bytes = 2;
|
||||
|
||||
// If the secret data is encrypted, then secret_bytes is missing and this field is set.
|
||||
optional EncryptedData encrypted_data = 6;
|
||||
|
||||
// The public EC key derived from the private key. We allow both to be stored to avoid mobile clients having to
|
||||
// do lots of slow EC math on startup. For DETERMINISTIC_MNEMONIC entries this is missing.
|
||||
optional bytes public_key = 3;
|
||||
|
||||
// User-provided label associated with the key.
|
||||
optional string label = 4;
|
||||
|
||||
// Timestamp stored as millis since epoch. Useful for skipping block bodies before this point. Only reason it's
|
||||
// optional is that some very old wallets don't have this data.
|
||||
optional int64 creation_timestamp = 5;
|
||||
|
||||
optional DeterministicKey deterministic_key = 7;
|
||||
|
||||
// The seed for a deterministic key hierarchy. Derived from the mnemonic,
|
||||
// but cached here for quick startup. Only applicable to a DETERMINISTIC_MNEMONIC key entry.
|
||||
optional bytes deterministic_seed = 8;
|
||||
|
||||
// Encrypted version of the seed
|
||||
optional EncryptedData encrypted_deterministic_seed = 9;
|
||||
}
|
||||
|
||||
message Script {
|
||||
required bytes program = 1;
|
||||
|
||||
// Timestamp stored as millis since epoch. Useful for skipping block bodies before this point
|
||||
// when watching for scripts on the blockchain.
|
||||
required int64 creation_timestamp = 2;
|
||||
}
|
||||
|
||||
message TransactionInput {
|
||||
// Hash of the transaction this input is using.
|
||||
required bytes transaction_out_point_hash = 1;
|
||||
// Index of transaction output used by this input.
|
||||
required uint32 transaction_out_point_index = 2;
|
||||
// Script that contains the signatures/pubkeys.
|
||||
required bytes script_bytes = 3;
|
||||
// Sequence number. Currently unused, but intended for contracts in future.
|
||||
optional uint32 sequence = 4;
|
||||
// Value of connected output, if known
|
||||
optional int64 value = 5;
|
||||
}
|
||||
|
||||
message TransactionOutput {
|
||||
required int64 value = 1;
|
||||
required bytes script_bytes = 2; // script of transaction output
|
||||
// If spent, the hash of the transaction doing the spend.
|
||||
optional bytes spent_by_transaction_hash = 3;
|
||||
// If spent, the index of the transaction input of the transaction doing the spend.
|
||||
optional int32 spent_by_transaction_index = 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* A description of the confidence we have that a transaction cannot be reversed in the future.
|
||||
*
|
||||
* Parsing should be lenient, since this could change for different applications yet we should
|
||||
* maintain backward compatibility.
|
||||
*/
|
||||
message TransactionConfidence {
|
||||
enum Type {
|
||||
UNKNOWN = 0;
|
||||
BUILDING = 1; // In best chain. If and only if appeared_at_height is present.
|
||||
PENDING = 2; // Unconfirmed and sitting in the networks memory pools, waiting to be included in the chain.
|
||||
NOT_IN_BEST_CHAIN = 3; // Deprecated: equivalent to PENDING.
|
||||
DEAD = 4; // Either if overriding_transaction is present or transaction is dead coinbase
|
||||
}
|
||||
|
||||
// This is optional in case we add confidence types to prevent parse errors - backwards compatible.
|
||||
optional Type type = 1;
|
||||
|
||||
// If type == BUILDING then this is the chain height at which the transaction was included.
|
||||
optional int32 appeared_at_height = 2;
|
||||
|
||||
// If set, hash of the transaction that double spent this one into oblivion. A transaction can be double spent by
|
||||
// multiple transactions in the case of several inputs being re-spent by several transactions but we don't
|
||||
// bother to track them all, just the first. This only makes sense if type = DEAD.
|
||||
optional bytes overriding_transaction = 3;
|
||||
|
||||
// If type == BUILDING then this is the depth of the transaction in the blockchain.
|
||||
// Zero confirmations: depth = 0, one confirmation: depth = 1 etc.
|
||||
optional int32 depth = 4;
|
||||
|
||||
// deprecated - do not recycle this numeric identifier
|
||||
// optional int64 work_done = 5;
|
||||
|
||||
repeated PeerAddress broadcast_by = 6;
|
||||
|
||||
// Where did we get this transaction from? Knowing the source may help us to risk analyze pending transactions.
|
||||
enum Source {
|
||||
SOURCE_UNKNOWN = 0; // We don't know where it came from, or this is a wallet from the future.
|
||||
SOURCE_NETWORK = 1; // We received it from a network broadcast. This is the normal way to get payments.
|
||||
SOURCE_SELF = 2; // We made it ourselves, so we know it should be valid.
|
||||
// In future:
|
||||
// - direct from trusted counterparty, eg via bluetooth/wifi direct
|
||||
// - direct from untrusted counterparty
|
||||
// - from a wallet that uses trusted computing/secure hardware that won't create double spends
|
||||
}
|
||||
optional Source source = 7;
|
||||
}
|
||||
|
||||
/** A bitcoin transaction */
|
||||
|
||||
message Transaction {
|
||||
/**
|
||||
* This is a bitfield oriented enum, with the following bits:
|
||||
*
|
||||
* bit 0 - spent
|
||||
* bit 1 - appears in alt chain
|
||||
* bit 2 - appears in best chain
|
||||
* bit 3 - double-spent
|
||||
* bit 4 - pending (we would like the tx to go into the best chain)
|
||||
*
|
||||
* Not all combinations are interesting, just the ones actually used in the enum.
|
||||
*/
|
||||
enum Pool {
|
||||
UNSPENT = 4; // In best chain, not all outputs spent
|
||||
SPENT = 5; // In best chain, all outputs spent
|
||||
INACTIVE = 2; // In non-best chain, not our transaction
|
||||
DEAD = 10; // Double-spent by a transaction in the best chain
|
||||
PENDING = 16; // Our transaction, not in any chain
|
||||
PENDING_INACTIVE = 18; // In non-best chain, our transaction
|
||||
}
|
||||
|
||||
// See Wallet.java for detailed description of pool semantics
|
||||
required int32 version = 1;
|
||||
required bytes hash = 2;
|
||||
|
||||
// If pool is not present, that means either:
|
||||
// - This Transaction is either not in a wallet at all (the proto is re-used elsewhere)
|
||||
// - Or it is stored but for other purposes, for example, because it is the overriding transaction of a double spend.
|
||||
// - Or the Pool enum got a new value which your software is too old to parse.
|
||||
optional Pool pool = 3;
|
||||
|
||||
optional uint32 lock_time = 4; // The nLockTime field is useful for contracts.
|
||||
optional int64 updated_at = 5; // millis since epoch the transaction was last updated
|
||||
|
||||
repeated TransactionInput transaction_input = 6;
|
||||
repeated TransactionOutput transaction_output = 7;
|
||||
|
||||
// A list of blocks in which the transaction has been observed (on any chain). Also, a number used to disambiguate
|
||||
// ordering within a block.
|
||||
repeated bytes block_hash = 8;
|
||||
repeated int32 block_relativity_offsets = 11;
|
||||
|
||||
// Data describing where the transaction is in the chain.
|
||||
optional TransactionConfidence confidence = 9;
|
||||
|
||||
// For what purpose the transaction was created.
|
||||
enum Purpose {
|
||||
// Old wallets or the purpose genuinely is a mystery (e.g. imported from some external source).
|
||||
UNKNOWN = 0;
|
||||
// Created in response to a user request for payment. This is the normal case.
|
||||
USER_PAYMENT = 1;
|
||||
// Created automatically to move money from rotated keys.
|
||||
KEY_ROTATION = 2;
|
||||
// Stuff used by Lighthouse.
|
||||
ASSURANCE_CONTRACT_CLAIM = 3;
|
||||
ASSURANCE_CONTRACT_PLEDGE = 4;
|
||||
ASSURANCE_CONTRACT_STUB = 5;
|
||||
// In future: de/refragmentation, privacy boosting/mixing, child-pays-for-parent fees, etc.
|
||||
}
|
||||
optional Purpose purpose = 10 [default = UNKNOWN];
|
||||
|
||||
// Exchange rate that was valid when the transaction was sent.
|
||||
optional ExchangeRate exchange_rate = 12;
|
||||
|
||||
// Memo of the transaction. It can be used to record the memo of the payment request that initiated the
|
||||
// transaction.
|
||||
optional string memo = 13;
|
||||
|
||||
// Next tag: 14
|
||||
}
|
||||
|
||||
/** The parameters used in the scrypt key derivation function.
|
||||
* The default values are taken from http://www.tarsnap.com/scrypt/scrypt-slides.pdf.
|
||||
* They can be increased - n is the number of iterations performed and
|
||||
* r and p can be used to tweak the algorithm - see:
|
||||
* http://stackoverflow.com/questions/11126315/what-are-optimal-scrypt-work-factors
|
||||
*/
|
||||
message ScryptParameters {
|
||||
required bytes salt = 1; // Salt to use in generation of the wallet password (8 bytes)
|
||||
optional int64 n = 2 [default = 16384]; // CPU/ memory cost parameter
|
||||
optional int32 r = 3 [default = 8]; // Block size parameter
|
||||
optional int32 p = 4 [default = 1]; // Parallelisation parameter
|
||||
}
|
||||
|
||||
/** An extension to the wallet */
|
||||
message Extension {
|
||||
required string id = 1; // like org.whatever.foo.bar
|
||||
required bytes data = 2;
|
||||
// If we do not understand a mandatory extension, abort to prevent data loss.
|
||||
// For example, this could be applied to a new type of holding, such as a contract, where
|
||||
// dropping of an extension in a read/write cycle could cause loss of value.
|
||||
required bool mandatory = 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple key->value mapping that has no interpreted content at all. A bit like the extensions mechanism except
|
||||
* an extension is keyed by the ID of a piece of code that's loaded with the given data, and has the concept of
|
||||
* being mandatory if that code isn't found. Whereas this is just a blind key/value store.
|
||||
*/
|
||||
message Tag {
|
||||
required string tag = 1;
|
||||
required bytes data = 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data required to reconstruct TransactionSigner.
|
||||
*/
|
||||
message TransactionSigner {
|
||||
// fully qualified class name of TransactionSigner implementation
|
||||
required string class_name = 1;
|
||||
// arbitrary data required for signer to function
|
||||
optional bytes data = 2;
|
||||
}
|
||||
|
||||
/** A bitcoin wallet */
|
||||
message Wallet {
|
||||
/**
|
||||
* The encryption type of the wallet.
|
||||
*
|
||||
* The encryption type is UNENCRYPTED for wallets where the wallet does not support encryption - wallets prior to
|
||||
* encryption support are grandfathered in as this wallet type.
|
||||
* When a wallet is ENCRYPTED_SCRYPT_AES the keys are either encrypted with the wallet password or are unencrypted.
|
||||
*/
|
||||
enum EncryptionType {
|
||||
UNENCRYPTED = 1; // All keys in the wallet are unencrypted
|
||||
ENCRYPTED_SCRYPT_AES = 2; // All keys are encrypted with a passphrase based KDF of scrypt and AES encryption
|
||||
}
|
||||
|
||||
required string network_identifier = 1; // the network used by this wallet
|
||||
// org.bitcoin.production = main, production network (Satoshi genesis block)
|
||||
// org.bitcoin.test = test network (Andresen genesis block)
|
||||
|
||||
// The SHA256 hash of the head of the best chain seen by this wallet.
|
||||
optional bytes last_seen_block_hash = 2;
|
||||
// The height in the chain of the last seen block.
|
||||
optional uint32 last_seen_block_height = 12;
|
||||
optional int64 last_seen_block_time_secs = 14;
|
||||
|
||||
repeated Key key = 3;
|
||||
repeated Transaction transaction = 4;
|
||||
repeated Script watched_script = 15;
|
||||
|
||||
optional EncryptionType encryption_type = 5 [default=UNENCRYPTED];
|
||||
optional ScryptParameters encryption_parameters = 6;
|
||||
|
||||
// The version number of the wallet - used to detect wallets that were produced in the future
|
||||
// (i.e. the wallet may contain some future format this protobuf or parser code does not know about).
|
||||
// A version that's higher than the default is considered from the future.
|
||||
optional int32 version = 7 [default = 1];
|
||||
|
||||
// deprecated - do not recycle this numeric identifier
|
||||
// optional int32 minor_version = 8;
|
||||
|
||||
repeated Extension extension = 10;
|
||||
|
||||
// A UTF8 encoded text description of the wallet that is intended for end user provided text.
|
||||
optional string description = 11;
|
||||
|
||||
// (The field number 12 is used by last_seen_block_height)
|
||||
|
||||
// UNIX time in seconds since the epoch. If set, then any keys created before this date are assumed to be no longer
|
||||
// wanted. Money sent to them will be re-spent automatically to the first key that was created after this time. It
|
||||
// can be used to recover a compromised wallet, or just as part of preventative defence-in-depth measures.
|
||||
optional uint64 key_rotation_time = 13;
|
||||
|
||||
repeated Tag tags = 16;
|
||||
|
||||
// transaction signers added to the wallet
|
||||
repeated TransactionSigner transaction_signers = 17;
|
||||
|
||||
// Next tag: 18
|
||||
}
|
||||
|
||||
/** An exchange rate between Bitcoin and some fiat currency. */
|
||||
message ExchangeRate {
|
||||
// This much of satoshis (1E-8 fractions)…
|
||||
required int64 coin_value = 1;
|
||||
// …is worth this much of fiat (1E-4 fractions).
|
||||
required int64 fiat_value = 2;
|
||||
// ISO 4217 currency code (if available) of the fiat currency.
|
||||
required string fiat_currency_code = 3;
|
||||
|
||||
// Next tag: 4
|
||||
}
|
||||
Reference in New Issue
Block a user