diff --git a/core/src/main/java/org/bitcoinj/core/AddressMessage.java b/core/src/main/java/org/bitcoinj/core/AddressMessage.java index 380e980c..e9ef386f 100644 --- a/core/src/main/java/org/bitcoinj/core/AddressMessage.java +++ b/core/src/main/java/org/bitcoinj/core/AddressMessage.java @@ -1,3 +1,20 @@ +/* + * 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.bitcoinj.core; import java.io.IOException; @@ -20,7 +37,6 @@ public class AddressMessage extends Message { * Contruct a new 'addr' message. * @param params NetworkParameters object. * @param offset The location of the first payload byte within the array. - * @param parseLazy Whether to perform a full parse immediately or delay until a read is requested. * @param parseRetain Whether to retain the backing byte array for quick reserialization. * If true and the backing byte array is invalidated due to modification of a field then * the cached bytes may be repopulated and retained if the message is serialized again in the future. @@ -53,11 +69,7 @@ public class AddressMessage extends Message { } @Override - protected void parseLite() throws ProtocolException { - } - - @Override - void parse() throws ProtocolException { + protected void parse() throws ProtocolException { long numAddresses = readVarInt(); // Guard against ultra large messages that will crash us. if (numAddresses > MAX_ADDRESSES) @@ -68,7 +80,9 @@ public class AddressMessage extends Message { addresses.add(addr); cursor += addr.getMessageSize(); } - length = cursor - offset; + length = new VarInt(addresses.size()).getSizeInBytes(); + // The 4 byte difference is the uint32 timestamp that was introduced in version 31402 + length += addresses.size() * (protocolVersion > 31402 ? PeerAddress.MESSAGE_SIZE : PeerAddress.MESSAGE_SIZE - 4); } /* (non-Javadoc) @@ -84,29 +98,15 @@ public class AddressMessage extends Message { } } - @Override - public int getMessageSize() { - if (length != UNKNOWN_LENGTH) - return length; - if (addresses != null) { - length = new VarInt(addresses.size()).getSizeInBytes(); - // The 4 byte difference is the uint32 timestamp that was introduced in version 31402 - length += addresses.size() * (protocolVersion > 31402 ? PeerAddress.MESSAGE_SIZE : PeerAddress.MESSAGE_SIZE - 4); - } - return length; - } - /** * @return An unmodifiableList view of the backing List of addresses. Addresses contained within the list may be safely modified. */ public List getAddresses() { - maybeParse(); return Collections.unmodifiableList(addresses); } public void addAddress(PeerAddress address) { unCache(); - maybeParse(); address.setParent(this); addresses.add(address); if (length == UNKNOWN_LENGTH) @@ -129,5 +129,4 @@ public class AddressMessage extends Message { public String toString() { return "addr: " + Utils.join(addresses); } - } diff --git a/core/src/main/java/org/bitcoinj/core/AlertMessage.java b/core/src/main/java/org/bitcoinj/core/AlertMessage.java index 3418680b..23d8e43e 100644 --- a/core/src/main/java/org/bitcoinj/core/AlertMessage.java +++ b/core/src/main/java/org/bitcoinj/core/AlertMessage.java @@ -1,5 +1,6 @@ /* * Copyright 2011 Google Inc. + * Copyright 2015 Andreas Schildbach * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -61,7 +62,7 @@ public class AlertMessage extends Message { } @Override - void parse() throws ProtocolException { + protected void parse() throws ProtocolException { // Alerts are formatted in two levels. The top level contains two byte arrays: a signature, and a serialized // data structure containing the actual alert data. int startPos = cursor; @@ -115,11 +116,6 @@ public class AlertMessage extends Message { return ECKey.verify(Sha256Hash.hashTwice(content), signature, params.getAlertSigningKey()); } - @Override - protected void parseLite() throws ProtocolException { - // Do nothing, lazy parsing isn't useful for alerts. - } - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Field accessors. diff --git a/core/src/main/java/org/bitcoinj/core/BitcoinSerializer.java b/core/src/main/java/org/bitcoinj/core/BitcoinSerializer.java index 19fb58fb..aa93681d 100644 --- a/core/src/main/java/org/bitcoinj/core/BitcoinSerializer.java +++ b/core/src/main/java/org/bitcoinj/core/BitcoinSerializer.java @@ -46,7 +46,6 @@ public class BitcoinSerializer implements MessageSerializer { private static final int COMMAND_LEN = 12; private final NetworkParameters params; - private final boolean parseLazy; private final boolean parseRetain; private static final Map, String> names = new HashMap, String>(); @@ -74,32 +73,14 @@ public class BitcoinSerializer implements MessageSerializer { names.put(UTXOsMessage.class, "utxos"); } - /** - * Constructs a partial BitcoinSerializer with the given behavior. This is - * intended for use by messages which do not understand the network they - * belong to. - * - * @param parseLazy deserialize messages in lazy mode. - * @param parseRetain retain the backing byte array of a message for fast reserialization. - * @deprecated use BitcoinSerializer(NetworkParameters, boolean, boolean) instead. - */ - @Deprecated - BitcoinSerializer(boolean parseLazy, boolean parseRetain) { - this.params = null; - this.parseLazy = parseLazy; - this.parseRetain = parseRetain; - } - /** * Constructs a BitcoinSerializer with the given behavior. * * @param params networkParams used to create Messages instances and termining packetMagic - * @param parseLazy deserialize messages in lazy mode. * @param parseRetain retain the backing byte array of a message for fast reserialization. */ - public BitcoinSerializer(NetworkParameters params, boolean parseLazy, boolean parseRetain) { + public BitcoinSerializer(NetworkParameters params, boolean parseRetain) { this.params = params; - this.parseLazy = parseLazy; this.parseRetain = parseRetain; } @@ -370,14 +351,6 @@ public class BitcoinSerializer implements MessageSerializer { } } - /** - * Whether the serializer will produce lazy parse mode Messages - */ - @Override - public boolean isParseLazyMode() { - return parseLazy; - } - /** * Whether the serializer will produce cached mode Messages */ diff --git a/core/src/main/java/org/bitcoinj/core/Block.java b/core/src/main/java/org/bitcoinj/core/Block.java index 2ab94e1d..16d273de 100644 --- a/core/src/main/java/org/bitcoinj/core/Block.java +++ b/core/src/main/java/org/bitcoinj/core/Block.java @@ -93,9 +93,6 @@ public class Block extends Message { /** Stores the hash of the block. If null, getHash() will recalculate it. */ private Sha256Hash hash; - protected boolean headerParsed; - protected boolean transactionsParsed; - protected boolean headerBytesValid; protected boolean transactionBytesValid; @@ -195,28 +192,6 @@ public class Block extends Message { return FIFTY_COINS.shiftRight(height / params.getSubsidyDecreaseBlockCount()); } - protected void parseHeader() throws ProtocolException { - if (headerParsed) - return; - - cursor = offset; - version = readUint32(); - prevBlockHash = readHash(); - merkleRoot = readHash(); - time = readUint32(); - difficultyTarget = readUint32(); - nonce = readUint32(); - - hash = Sha256Hash.wrapReversed(Sha256Hash.hashTwice(payload, offset, cursor)); - - headerParsed = true; - headerBytesValid = serializer.isParseRetainMode(); - } - - protected void parseTransactions() throws ProtocolException { - parseTransactions(offset + HEADER_SIZE); - } - /** * Parse transactions from the block. * @@ -225,14 +200,10 @@ public class Block extends Message { * size. */ protected void parseTransactions(final int transactionsOffset) throws ProtocolException { - if (transactionsParsed) - return; - cursor = transactionsOffset; optimalEncodingMessageSize = HEADER_SIZE; if (payload.length == cursor) { // This message is just a header, it has no transactions. - transactionsParsed = true; transactionBytesValid = false; return; } @@ -248,160 +219,36 @@ public class Block extends Message { cursor += tx.getMessageSize(); optimalEncodingMessageSize += tx.getOptimalEncodingMessageSize(); } - // No need to set length here. If length was not provided then it should be set at the end of parseLight(). - // If this is a genuine lazy parse then length must have been provided to the constructor. - transactionsParsed = true; transactionBytesValid = serializer.isParseRetainMode(); } @Override - void parse() throws ProtocolException { - parseHeader(); - parseTransactions(); + protected void parse() throws ProtocolException { + // header + cursor = offset; + version = readUint32(); + prevBlockHash = readHash(); + merkleRoot = readHash(); + time = readUint32(); + difficultyTarget = readUint32(); + nonce = readUint32(); + hash = Sha256Hash.wrapReversed(Sha256Hash.hashTwice(payload, offset, cursor)); + headerBytesValid = serializer.isParseRetainMode(); + + // transactions + parseTransactions(offset + HEADER_SIZE); length = cursor - offset; } public int getOptimalEncodingMessageSize() { if (optimalEncodingMessageSize != 0) return optimalEncodingMessageSize; - maybeParseTransactions(); if (optimalEncodingMessageSize != 0) return optimalEncodingMessageSize; optimalEncodingMessageSize = bitcoinSerialize().length; return optimalEncodingMessageSize; } - @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(serializer.isParseLazyMode(), - "Performing lite parse of block transaction as block was initialised from byte array " + - "without providing length. This should never need to happen."); - parseTransactions(); - length = cursor - offset; - } else { - transactionBytesValid = !transactionsParsed || serializer.isParseRetainMode() && length > HEADER_SIZE; - } - headerBytesValid = !headerParsed || serializer.isParseRetainMode() && length >= HEADER_SIZE; - } - - /* - * Block uses some special handling for lazy parsing and retention of cached bytes. Parsing and serializing the - * block header and the transaction list are both non-trivial so there are good efficiency gains to be had by - * separating them. There are many cases where a user may need to access or change one or the other but not both. - * - * With this in mind we ignore the inherited checkParse() and unCache() methods and implement a separate version - * of them for both header and transactions. - * - * Serializing methods are also handled in their own way. Whilst they deal with separate parts of the block structure - * there are some interdependencies. For example altering a tx requires invalidating the Merkle root and therefore - * the cached header bytes. - */ - private void maybeParseHeader() { - if (headerParsed || payload == null) - return; - try { - parseHeader(); - if (!(headerBytesValid || transactionBytesValid)) - payload = null; - } catch (ProtocolException e) { - throw new LazyParseException( - "ProtocolException caught during lazy parse. For safe access to fields call ensureParsed before attempting read or write access", - e); - } - } - - private void maybeParseTransactions() { - if (transactionsParsed || payload == null) - return; - try { - parseTransactions(); - if (!serializer.isParseRetainMode()) { - transactionBytesValid = false; - if (headerParsed) - payload = null; - } - } catch (ProtocolException e) { - throw new LazyParseException( - "ProtocolException caught during lazy parse. For safe access to fields call ensureParsed before attempting read or write access", - e); - } - } - - /** - * Ensure the object is parsed if needed. This should be called in every getter before returning a value. If the - * lazy parse flag is not set this is a method returns immediately. - */ - @Override - protected void maybeParse() { - throw new LazyParseException( - "checkParse() should never be called on a Block. Instead use checkParseHeader() and checkParseTransactions()"); - } - - /** - * In lazy parsing mode access to getters and setters may throw an unchecked LazyParseException. If guaranteed - * safe access is required this method will force parsing to occur immediately thus ensuring LazyParseExeption will - * never be thrown from this Message. If the Message contains child messages (e.g. a Block containing Transaction - * messages) this will not force child messages to parse. - * - * This method ensures parsing of both headers and transactions. - * - * @throws ProtocolException - */ - @Override - public void ensureParsed() throws ProtocolException { - try { - maybeParseHeader(); - maybeParseTransactions(); - } catch (LazyParseException e) { - if (e.getCause() instanceof ProtocolException) - throw (ProtocolException) e.getCause(); - throw new ProtocolException(e); - } - } - - /** - * In lazy parsing mode access to getters and setters may throw an unchecked LazyParseException. If guaranteed - * safe access is required this method will force parsing to occur immediately thus ensuring LazyParseExeption - * will never be thrown from this Message. If the Message contains child messages (e.g. a Block containing - * Transaction messages) this will not force child messages to parse. - * - * This method ensures parsing of headers only. - * - * @throws ProtocolException - */ - public void ensureParsedHeader() throws ProtocolException { - try { - maybeParseHeader(); - } catch (LazyParseException e) { - if (e.getCause() instanceof ProtocolException) - throw (ProtocolException) e.getCause(); - throw new ProtocolException(e); - } - } - - /** - * In lazy parsing mode access to getters and setters may throw an unchecked LazyParseException. If guaranteed - * safe access is required this method will force parsing to occur immediately thus ensuring LazyParseExeption will - * never be thrown from this Message. If the Message contains child messages (e.g. a Block containing Transaction - * messages) this will not force child messages to parse. - * - * This method ensures parsing of transactions only. - * - * @throws ProtocolException - */ - public void ensureParsedTransactions() throws ProtocolException { - try { - maybeParseTransactions(); - } catch (LazyParseException e) { - if (e.getCause() instanceof ProtocolException) - throw (ProtocolException) e.getCause(); - throw new ProtocolException(e); - } - } - // default for testing void writeHeader(OutputStream stream) throws IOException { // try for cached write first @@ -410,7 +257,6 @@ public class Block extends Message { return; } // fall back to manual write - maybeParseHeader(); Utils.uint32ToByteStreamLE(version, stream); stream.write(prevBlockHash.getReversedBytes()); stream.write(getMerkleRoot().getReversedBytes()); @@ -422,7 +268,7 @@ public class Block extends Message { private void writeTransactions(OutputStream stream) throws IOException { // check for no transaction conditions first // must be a more efficient way to do this but I'm tired atm. - if (transactions == null && transactionsParsed) { + if (transactions == null) { return; } @@ -509,7 +355,6 @@ public class Block extends Message { } private void unCacheHeader() { - maybeParseHeader(); headerBytesValid = false; if (!transactionBytesValid) payload = null; @@ -517,7 +362,6 @@ public class Block extends Message { } private void unCacheTransactions() { - maybeParseTransactions(); transactionBytesValid = false; if (!headerBytesValid) payload = null; @@ -584,7 +428,6 @@ public class Block extends Message { /** Returns a copy of the block, but without any transactions. */ public Block cloneAsHeader() { - maybeParseHeader(); Block block = new Block(params, BLOCK_VERSION_GENESIS); copyBitcoinHeaderTo(block); return block; @@ -633,7 +476,6 @@ public class Block extends Message { * extraNonce.

*/ public void solve() { - maybeParseHeader(); while (true) { try { // Is our proof of work valid yet? @@ -653,7 +495,6 @@ public class Block extends Message { * is thrown. */ public BigInteger getDifficultyTargetAsInteger() throws VerificationException { - maybeParseHeader(); BigInteger target = Utils.decodeCompactBits(difficultyTarget); if (target.signum() <= 0 || target.compareTo(params.maxTarget) > 0) throw new VerificationException("Difficulty target is bad: " + target.toString()); @@ -685,7 +526,6 @@ public class Block extends Message { } private void checkTimestamp() throws VerificationException { - maybeParseHeader(); // Allow injection of a fake clock to allow unit testing. long currentTime = Utils.currentTimeSeconds(); if (time > currentTime + ALLOWED_TIME_DRIFT) @@ -747,7 +587,6 @@ public class Block extends Message { // 2 3 4 4 // / \ / \ / \ // t1 t2 t3 t4 t5 t5 - maybeParseTransactions(); ArrayList tree = new ArrayList(); // Start by adding all the hashes of the transactions as leaves of the tree. for (Transaction t : transactions) { @@ -796,7 +635,6 @@ public class Block extends Message { // // Firstly we need to ensure this block does in fact represent real work done. If the difficulty is high // enough, it's probably been done by the network. - maybeParseHeader(); checkProofOfWork(true); checkTimestamp(); } @@ -813,7 +651,6 @@ public class Block extends Message { // transactions that reference spent or non-existant inputs. if (transactions.isEmpty()) throw new VerificationException("Block had no transactions"); - maybeParseTransactions(); if (this.getOptimalEncodingMessageSize() > MAX_BLOCK_SIZE) throw new VerificationException("Block larger than MAX_BLOCK_SIZE"); checkTransactions(); @@ -847,7 +684,6 @@ public class Block extends Message { * Returns the merkle root in big endian form, calculating it from transactions if necessary. */ public Sha256Hash getMerkleRoot() { - maybeParseHeader(); if (merkleRoot == null) { //TODO check if this is really necessary. unCacheHeader(); @@ -888,7 +724,6 @@ public class Block extends Message { /** Returns the version of the block data structure as defined by the Bitcoin protocol. */ public long getVersion() { - maybeParseHeader(); return version; } @@ -896,7 +731,6 @@ public class Block extends Message { * Returns the hash of the previous block in the chain, as defined by the block header. */ public Sha256Hash getPrevBlockHash() { - maybeParseHeader(); return prevBlockHash; } @@ -911,7 +745,6 @@ public class Block extends Message { * is measured in seconds since the UNIX epoch (midnight Jan 1st 1970). */ public long getTimeSeconds() { - maybeParseHeader(); return time; } @@ -938,7 +771,6 @@ public class Block extends Message { * Calculating the difficulty that way is currently unsupported. */ public long getDifficultyTarget() { - maybeParseHeader(); return difficultyTarget; } @@ -954,7 +786,6 @@ public class Block extends Message { * difficulty target. */ public long getNonce() { - maybeParseHeader(); return nonce; } @@ -968,7 +799,6 @@ public class Block extends Message { /** Returns an immutable list of transactions held in this block, or null if this object represents just a header. */ @Nullable public List getTransactions() { - maybeParseTransactions(); return transactions == null ? null : ImmutableList.copyOf(transactions); } @@ -1087,16 +917,6 @@ public class Block extends Message { return createNextBlock(null, 1, null, Utils.currentTimeSeconds(), pubKey, FIFTY_COINS); } - @VisibleForTesting - boolean isParsedHeader() { - return headerParsed; - } - - @VisibleForTesting - boolean isParsedTransactions() { - return transactionsParsed; - } - @VisibleForTesting boolean isHeaderBytesValid() { return headerBytesValid; diff --git a/core/src/main/java/org/bitcoinj/core/BloomFilter.java b/core/src/main/java/org/bitcoinj/core/BloomFilter.java index 447e89a2..c1d62391 100644 --- a/core/src/main/java/org/bitcoinj/core/BloomFilter.java +++ b/core/src/main/java/org/bitcoinj/core/BloomFilter.java @@ -1,5 +1,6 @@ /* * Copyright 2012 Matt Corallo + * Copyright 2015 Andreas Schildbach * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -130,7 +131,7 @@ public class BloomFilter extends Message { } @Override - void parse() throws ProtocolException { + protected void parse() throws ProtocolException { data = readByteArray(); if (data.length > MAX_FILTER_SIZE) throw new ProtocolException ("Bloom filter out of size range."); @@ -154,11 +155,6 @@ public class BloomFilter extends Message { stream.write(nFlags); } - @Override - protected void parseLite() throws ProtocolException { - // Do nothing, lazy parsing isn't useful for bloom filters. - } - private static int rotateLeft32(int x, int r) { return (x << r) | (x >>> (32 - r)); } diff --git a/core/src/main/java/org/bitcoinj/core/DummySerializer.java b/core/src/main/java/org/bitcoinj/core/DummySerializer.java index efef9959..7d426619 100644 --- a/core/src/main/java/org/bitcoinj/core/DummySerializer.java +++ b/core/src/main/java/org/bitcoinj/core/DummySerializer.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.bitcoinj.core; import java.io.IOException; @@ -47,11 +48,6 @@ class DummySerializer implements MessageSerializer { throw new UnsupportedOperationException(DEFAULT_EXCEPTION_MESSAGE); } - @Override - public boolean isParseLazyMode() { - return false; - } - @Override public boolean isParseRetainMode() { return false; diff --git a/core/src/main/java/org/bitcoinj/core/EmptyMessage.java b/core/src/main/java/org/bitcoinj/core/EmptyMessage.java index 5a24ef21..2186a98a 100644 --- a/core/src/main/java/org/bitcoinj/core/EmptyMessage.java +++ b/core/src/main/java/org/bitcoinj/core/EmptyMessage.java @@ -1,5 +1,6 @@ /* * Copyright 2011 Steve Coughlan. + * Copyright 2015 Andreas Schildbach * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,6 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.bitcoinj.core; import java.io.IOException; @@ -43,31 +45,7 @@ public abstract class EmptyMessage extends Message { } @Override - public int getMessageSize() { - return 0; - } - - /* (non-Javadoc) - * @see Message#parse() - */ - @Override - void parse() throws ProtocolException { - } - - /* (non-Javadoc) - * @see Message#parseLite() - */ - @Override - protected void parseLite() throws ProtocolException { - length = 0; - } - - /* (non-Javadoc) - * @see Message#ensureParsed() - */ - @Override - public void ensureParsed() throws ProtocolException { - parsed = true; + protected void parse() throws ProtocolException { } /* (non-Javadoc) @@ -77,6 +55,4 @@ public abstract class EmptyMessage extends Message { public byte[] bitcoinSerialize() { return new byte[0]; } - - } diff --git a/core/src/main/java/org/bitcoinj/core/FilteredBlock.java b/core/src/main/java/org/bitcoinj/core/FilteredBlock.java index e34fb8e9..73b261fb 100644 --- a/core/src/main/java/org/bitcoinj/core/FilteredBlock.java +++ b/core/src/main/java/org/bitcoinj/core/FilteredBlock.java @@ -1,5 +1,6 @@ /** * Copyright 2012 Matt Corallo + * Copyright 2015 Andreas Schildbach * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -57,7 +58,7 @@ public class FilteredBlock extends Message { } @Override - void parse() throws ProtocolException { + protected void parse() throws ProtocolException { byte[] headerBytes = new byte[Block.HEADER_SIZE]; System.arraycopy(payload, 0, headerBytes, 0, Block.HEADER_SIZE); header = params.getDefaultSerializer().makeBlock(headerBytes); @@ -67,11 +68,6 @@ public class FilteredBlock extends Message { length = Block.HEADER_SIZE + merkleTree.getMessageSize(); } - @Override - protected void parseLite() throws ProtocolException { - - } - /** * Gets a list of leaf hashes which are contained in the partial merkle tree in this filtered block * diff --git a/core/src/main/java/org/bitcoinj/core/GetBlocksMessage.java b/core/src/main/java/org/bitcoinj/core/GetBlocksMessage.java index a8cbf401..66d464d1 100644 --- a/core/src/main/java/org/bitcoinj/core/GetBlocksMessage.java +++ b/core/src/main/java/org/bitcoinj/core/GetBlocksMessage.java @@ -1,5 +1,6 @@ /* * Copyright 2011 Google Inc. + * Copyright 2015 Andreas Schildbach * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,22 +44,13 @@ public class GetBlocksMessage extends Message { } @Override - protected void parseLite() throws ProtocolException { + protected void parse() throws ProtocolException { cursor = offset; version = readUint32(); int startCount = (int) readVarInt(); if (startCount > 500) throw new ProtocolException("Number of locators cannot be > 500, received: " + startCount); length = cursor - offset + ((startCount + 1) * 32); - } - - @Override - public void parse() throws ProtocolException { - cursor = offset; - version = readUint32(); - int startCount = (int) readVarInt(); - if (startCount > 500) - throw new ProtocolException("Number of locators cannot be > 500, received: " + startCount); locator = new ArrayList(startCount); for (int i = 0; i < startCount; i++) { locator.add(readHash()); diff --git a/core/src/main/java/org/bitcoinj/core/GetUTXOsMessage.java b/core/src/main/java/org/bitcoinj/core/GetUTXOsMessage.java index da177603..70aafe47 100644 --- a/core/src/main/java/org/bitcoinj/core/GetUTXOsMessage.java +++ b/core/src/main/java/org/bitcoinj/core/GetUTXOsMessage.java @@ -78,11 +78,6 @@ public class GetUTXOsMessage extends Message { return outPoints; } - @Override - protected void parseLite() throws ProtocolException { - // Not needed. - } - @Override void bitcoinSerializeToStream(OutputStream stream) throws IOException { stream.write(new byte[]{includeMempool ? (byte) 1 : 0}); // include mempool. diff --git a/core/src/main/java/org/bitcoinj/core/HeadersMessage.java b/core/src/main/java/org/bitcoinj/core/HeadersMessage.java index 213a3874..a6b3e1a5 100644 --- a/core/src/main/java/org/bitcoinj/core/HeadersMessage.java +++ b/core/src/main/java/org/bitcoinj/core/HeadersMessage.java @@ -1,5 +1,6 @@ /* * Copyright 2011 Google Inc. + * Copyright 2015 Andreas Schildbach * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -62,7 +63,7 @@ public class HeadersMessage extends Message { } @Override - protected void parseLite() throws ProtocolException { + protected void parse() throws ProtocolException { if (length == UNKNOWN_LENGTH) { int saveCursor = cursor; long numHeaders = readVarInt(); @@ -71,10 +72,7 @@ public class HeadersMessage extends Message { // Each header has 80 bytes and one more byte for transactions number which is 00. length = 81 * (int)numHeaders; } - } - @Override - void parse() throws ProtocolException { long numHeaders = readVarInt(); if (numHeaders > MAX_HEADERS) throw new ProtocolException("Too many headers: got " + numHeaders + " which is larger than " + @@ -88,7 +86,7 @@ public class HeadersMessage extends Message { byte[] blockHeader = readBytes(81); if (blockHeader[80] != 0) throw new ProtocolException("Block header does not end with a null byte"); - Block newBlockHeader = this.params.getSerializer(true, true) + Block newBlockHeader = this.params.getSerializer(true) .makeBlock(blockHeader, 81); blockHeaders.add(newBlockHeader); } @@ -100,7 +98,6 @@ public class HeadersMessage extends Message { } } - public List getBlockHeaders() { return blockHeaders; } diff --git a/core/src/main/java/org/bitcoinj/core/ListMessage.java b/core/src/main/java/org/bitcoinj/core/ListMessage.java index e209c725..2c278142 100644 --- a/core/src/main/java/org/bitcoinj/core/ListMessage.java +++ b/core/src/main/java/org/bitcoinj/core/ListMessage.java @@ -1,5 +1,6 @@ /* * Copyright 2011 Google Inc. + * Copyright 2015 Andreas Schildbach * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,7 +50,6 @@ public abstract class ListMessage extends Message { } public List getItems() { - maybeParse(); return Collections.unmodifiableList(items); } @@ -68,15 +68,12 @@ public abstract class ListMessage extends Message { } @Override - protected void parseLite() throws ProtocolException { + protected void parse() throws ProtocolException { arrayLen = readVarInt(); if (arrayLen > MAX_INVENTORY_ITEMS) throw new ProtocolException("Too many items in INV message: " + arrayLen); length = (int) (cursor - offset + (arrayLen * InventoryItem.MESSAGE_LENGTH)); - } - @Override - public void parse() throws ProtocolException { // An inv is vector where CInv is int+hash. The int is either 1 or 2 for tx or block. items = new ArrayList((int) arrayLen); for (int i = 0; i < arrayLen; i++) { diff --git a/core/src/main/java/org/bitcoinj/core/MemoryPoolMessage.java b/core/src/main/java/org/bitcoinj/core/MemoryPoolMessage.java index c52a172f..33a44a77 100644 --- a/core/src/main/java/org/bitcoinj/core/MemoryPoolMessage.java +++ b/core/src/main/java/org/bitcoinj/core/MemoryPoolMessage.java @@ -1,5 +1,6 @@ /* * Copyright 2012 Google Inc. + * Copyright 2015 Andreas Schildbach * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,10 +29,7 @@ import java.io.OutputStream; */ public class MemoryPoolMessage extends Message { @Override - void parse() throws ProtocolException {} - - @Override - protected void parseLite() throws ProtocolException {} + protected void parse() throws ProtocolException {} @Override void bitcoinSerializeToStream(OutputStream stream) throws IOException {} diff --git a/core/src/main/java/org/bitcoinj/core/Message.java b/core/src/main/java/org/bitcoinj/core/Message.java index 90e84166..1b34a374 100644 --- a/core/src/main/java/org/bitcoinj/core/Message.java +++ b/core/src/main/java/org/bitcoinj/core/Message.java @@ -52,7 +52,6 @@ public abstract class Message { // The raw message payload bytes themselves. protected byte[] payload; - protected boolean parsed = false; protected boolean recached = false; protected MessageSerializer serializer; @@ -61,17 +60,15 @@ public abstract class Message { protected NetworkParameters params; protected Message() { - parsed = true; serializer = DummySerializer.DEFAULT; } - Message(NetworkParameters params) { + protected Message(NetworkParameters params) { this.params = params; - parsed = true; serializer = params.getDefaultSerializer(); } - Message(NetworkParameters params, byte[] payload, int offset, int protocolVersion) throws ProtocolException { + protected Message(NetworkParameters params, byte[] payload, int offset, int protocolVersion) throws ProtocolException { this(params, payload, offset, protocolVersion, params.getDefaultSerializer(), UNKNOWN_LENGTH); } @@ -86,38 +83,30 @@ public abstract class Message { * as the length will be provided as part of the header. If unknown then set to Message.UNKNOWN_LENGTH * @throws ProtocolException */ - Message(NetworkParameters params, byte[] payload, int offset, int protocolVersion, MessageSerializer serializer, int length) throws ProtocolException { + protected Message(NetworkParameters params, byte[] payload, int offset, int protocolVersion, MessageSerializer serializer, int length) throws ProtocolException { this.serializer = serializer; this.protocolVersion = protocolVersion; this.params = params; this.payload = payload; this.cursor = this.offset = offset; this.length = length; - if (serializer.isParseLazyMode()) { - parseLite(); - } else { - parseLite(); - parse(); - parsed = true; - } + + parse(); if (this.length == UNKNOWN_LENGTH) - checkState(false, "Length field has not been set in constructor for %s after %s parse. " + - "Refer to Message.parseLite() for detail of required Length field contract.", - getClass().getSimpleName(), serializer.isParseLazyMode() ? "lite" : "full"); + checkState(false, "Length field has not been set in constructor for %s after parse.", + getClass().getSimpleName()); if (SELF_CHECK) { selfCheck(payload, offset); } - if (serializer.isParseRetainMode() || !parsed) - return; - this.payload = null; + if (!serializer.isParseRetainMode()) + this.payload = null; } private void selfCheck(byte[] payload, int offset) { if (!(this instanceof VersionMessage)) { - maybeParse(); byte[] payloadBytes = new byte[cursor - offset]; System.arraycopy(payload, offset, payloadBytes, 0, cursor - offset); byte[] reserialized = bitcoinSerialize(); @@ -138,68 +127,15 @@ public abstract class Message { // These methods handle the serialization/deserialization using the custom Bitcoin protocol. - abstract void parse() throws ProtocolException; + protected abstract void parse() throws ProtocolException; /** - * Perform the most minimal parse possible to calculate the length of the message payload. - * This is only required for subclasses of ChildMessage as root level messages will have their length passed - * into the constructor. - *

- * Implementations should adhere to the following contract: If parseLazy = true the 'length' - * field must be set before returning. If parseLazy = false the length field must be set either - * within the parseLite() method OR the parse() method. The overriding requirement is that length - * must be set to non UNKNOWN_MESSAGE value by the time the constructor exits. - * - * @return - * @throws ProtocolException - */ - protected abstract void parseLite() throws ProtocolException; - - /** - * Ensure the object is parsed if needed. This should be called in every getter before returning a value. - * If the lazy parse flag is not set this is a method returns immediately. - */ - protected synchronized void maybeParse() { - if (parsed || payload == null) - return; - try { - parse(); - parsed = true; - if (!serializer.isParseRetainMode()) - payload = null; - } catch (ProtocolException e) { - throw new LazyParseException("ProtocolException caught during lazy parse. For safe access to fields call ensureParsed before attempting read or write access", e); - } - } - - /** - * In lazy parsing mode access to getters and setters may throw an unchecked LazyParseException. If guaranteed safe access is required - * this method will force parsing to occur immediately thus ensuring LazyParseExeption will never be thrown from this Message. - * If the Message contains child messages (e.g. a Block containing Transaction messages) this will not force child messages to parse. - *

- * This could be overidden for Transaction and it's child classes to ensure the entire tree of Message objects is parsed. - * - * @throws ProtocolException - */ - public void ensureParsed() throws ProtocolException { - try { - maybeParse(); - } catch (LazyParseException e) { - if (e.getCause() instanceof ProtocolException) - throw (ProtocolException) e.getCause(); - throw new ProtocolException(e); - } - } - - /** - * To be called before any change of internal values including any setters. This ensures any cached byte array is - * removed after performing a lazy parse if necessary to ensure the object is fully populated. - *

- * Child messages of this object(e.g. Transactions belonging to a Block) will not have their internal byte caches - * invalidated unless they are also modified internally. + *

To be called before any change of internal values including any setters. This ensures any cached byte array is + * removed.

+ *

Child messages of this object(e.g. Transactions belonging to a Block) will not have their internal byte caches + * invalidated unless they are also modified internally.

*/ protected void unCache() { - maybeParse(); payload = null; recached = false; } @@ -220,13 +156,6 @@ public abstract class Message { length += VarInt.sizeOf(newArraySize) - VarInt.sizeOf(newArraySize - 1); } - /** - * used for unit testing - */ - public boolean isParsed() { - return parsed; - } - /** * used for unit testing */ @@ -346,17 +275,11 @@ public abstract class Message { } /** - * This should be overridden to extract correct message size in the case of lazy parsing. Until this method is - * implemented in a subclass of ChildMessage lazy parsing may have no effect. - * - * This default implementation is a safe fall back that will ensure it returns a correct value by parsing the message. + * This returns a correct value by parsing the message. */ - public int getMessageSize() { - if (length != UNKNOWN_LENGTH) - return length; - maybeParse(); + public final int getMessageSize() { if (length == UNKNOWN_LENGTH) - checkState(false, "Length field has not been set in %s after full parse.", getClass().getSimpleName()); + checkState(false, "Length field has not been set in %s.", getClass().getSimpleName()); return length; } @@ -448,16 +371,4 @@ public abstract class Message { this.serializer = params.getDefaultSerializer(); } } - - public static class LazyParseException extends RuntimeException { - - public LazyParseException(String message, Throwable cause) { - super(message, cause); - } - - public LazyParseException(String message) { - super(message); - } - - } } diff --git a/core/src/main/java/org/bitcoinj/core/MessageSerializer.java b/core/src/main/java/org/bitcoinj/core/MessageSerializer.java index 35736a2f..8a9f7d4e 100644 --- a/core/src/main/java/org/bitcoinj/core/MessageSerializer.java +++ b/core/src/main/java/org/bitcoinj/core/MessageSerializer.java @@ -15,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.bitcoinj.core; import java.io.IOException; @@ -45,11 +46,6 @@ public interface MessageSerializer { */ Message deserializePayload(BitcoinSerializer.BitcoinPacketHeader header, ByteBuffer in) throws ProtocolException, BufferUnderflowException, UnsupportedOperationException; - /** - * Whether the serializer will produce lazy parse mode Messages - */ - boolean isParseLazyMode(); - /** * Whether the serializer will produce cached mode Messages */ diff --git a/core/src/main/java/org/bitcoinj/core/NetworkParameters.java b/core/src/main/java/org/bitcoinj/core/NetworkParameters.java index 42c9e9f5..4f04f516 100644 --- a/core/src/main/java/org/bitcoinj/core/NetworkParameters.java +++ b/core/src/main/java/org/bitcoinj/core/NetworkParameters.java @@ -439,7 +439,7 @@ public abstract class NetworkParameters { // As the serializers are intended to be immutable, creating // two due to a race condition should not be a problem, however // to be safe we ensure only one exists for each network. - this.defaultSerializer = getSerializer(false, false); + this.defaultSerializer = getSerializer(false); } } } @@ -449,7 +449,7 @@ public abstract class NetworkParameters { /** * Construct and return a custom serializer. */ - public abstract BitcoinSerializer getSerializer(boolean parseLazy, boolean parseRetain); + public abstract BitcoinSerializer getSerializer(boolean parseRetain); /** * The number of blocks in the last {@link getMajorityWindow()} blocks diff --git a/core/src/main/java/org/bitcoinj/core/PartialMerkleTree.java b/core/src/main/java/org/bitcoinj/core/PartialMerkleTree.java index bd2f868b..681e3067 100644 --- a/core/src/main/java/org/bitcoinj/core/PartialMerkleTree.java +++ b/core/src/main/java/org/bitcoinj/core/PartialMerkleTree.java @@ -1,6 +1,7 @@ /** * Copyright 2012 The Bitcoin Developers * Copyright 2012 Matt Corallo + * Copyright 2015 Andreas Schildbach * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -109,7 +110,7 @@ public class PartialMerkleTree extends Message { } @Override - void parse() throws ProtocolException { + protected void parse() throws ProtocolException { transactionCount = (int)readUint32(); int nHashes = (int) readVarInt(); @@ -167,11 +168,6 @@ public class PartialMerkleTree extends Message { return combineLeftRight(left.getBytes(), right.getBytes()); } - @Override - protected void parseLite() { - - } - // helper function to efficiently calculate the number of nodes at given height in the merkle tree private static int getTreeWidth(int transactionCount, int height) { return (transactionCount + (1 << height) - 1) >> height; diff --git a/core/src/main/java/org/bitcoinj/core/PeerAddress.java b/core/src/main/java/org/bitcoinj/core/PeerAddress.java index 771157e2..380305a6 100644 --- a/core/src/main/java/org/bitcoinj/core/PeerAddress.java +++ b/core/src/main/java/org/bitcoinj/core/PeerAddress.java @@ -1,5 +1,6 @@ /* * Copyright 2011 Google Inc. + * Copyright 2015 Andreas Schildbach * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -63,12 +64,8 @@ public class PeerAddress extends ChildMessage { */ public PeerAddress(NetworkParameters params, byte[] payload, int offset, int protocolVersion, Message parent, MessageSerializer serializer) throws ProtocolException { super(params, payload, offset, protocolVersion, parent, serializer, UNKNOWN_LENGTH); - // Message length is calculated in parseLite which is guaranteed to be called before it is ever read. - // Even though message length is static for a PeerAddress it is safer to leave it there - // as it will be set regardless of which constructor was used. } - /** * Construct a peer address from a memorized or hardcoded address. */ @@ -139,11 +136,6 @@ public class PeerAddress extends ChildMessage { stream.write((byte) (0xFF & port)); } - @Override - protected void parseLite() { - length = protocolVersion > 31402 ? MESSAGE_SIZE : MESSAGE_SIZE - 4; - } - @Override protected void parse() throws ProtocolException { // Format of a serialized address: @@ -163,22 +155,15 @@ public class PeerAddress extends ChildMessage { throw new RuntimeException(e); // Cannot happen. } port = ((0xFF & payload[cursor++]) << 8) | (0xFF & payload[cursor++]); - } - - @Override - public int getMessageSize() { // The 4 byte difference is the uint32 timestamp that was introduced in version 31402 length = protocolVersion > 31402 ? MESSAGE_SIZE : MESSAGE_SIZE - 4; - return length; } public String getHostname() { - maybeParse(); return hostname; } public InetAddress getAddr() { - maybeParse(); return addr; } @@ -191,43 +176,33 @@ public class PeerAddress extends ChildMessage { this.addr = addr; } - public int getPort() { - maybeParse(); return port; } - public void setPort(int port) { unCache(); this.port = port; } - public BigInteger getServices() { - maybeParse(); return services; } - public void setServices(BigInteger services) { unCache(); this.services = services; } - public long getTime() { - maybeParse(); return time; } - public void setTime(long time) { unCache(); this.time = time; } - @Override public String toString() { if (hostname != null) { diff --git a/core/src/main/java/org/bitcoinj/core/Ping.java b/core/src/main/java/org/bitcoinj/core/Ping.java index b357daac..c7ea558e 100644 --- a/core/src/main/java/org/bitcoinj/core/Ping.java +++ b/core/src/main/java/org/bitcoinj/core/Ping.java @@ -1,5 +1,6 @@ /** * Copyright 2011 Noa Resare + * Copyright 2015 Andreas Schildbach * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -51,7 +52,7 @@ public class Ping extends Message { } @Override - void parse() throws ProtocolException { + protected void parse() throws ProtocolException { try { nonce = readInt64(); hasNonce = true; @@ -61,11 +62,6 @@ public class Ping extends Message { length = hasNonce ? 8 : 0; } - @Override - protected void parseLite() { - - } - public boolean hasNonce() { return hasNonce; } diff --git a/core/src/main/java/org/bitcoinj/core/Pong.java b/core/src/main/java/org/bitcoinj/core/Pong.java index 09147555..6335388d 100644 --- a/core/src/main/java/org/bitcoinj/core/Pong.java +++ b/core/src/main/java/org/bitcoinj/core/Pong.java @@ -1,5 +1,6 @@ /** * Copyright 2012 Matt Corallo + * Copyright 2015 Andreas Schildbach * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,7 +39,7 @@ public class Pong extends Message { } @Override - void parse() throws ProtocolException { + protected void parse() throws ProtocolException { nonce = readInt64(); length = 8; } @@ -48,10 +49,6 @@ public class Pong extends Message { Utils.int64ToByteStreamLE(nonce, stream); } - @Override - protected void parseLite() { - } - /** Returns the nonce sent by the remote peer. */ public long getNonce() { return nonce; diff --git a/core/src/main/java/org/bitcoinj/core/RejectMessage.java b/core/src/main/java/org/bitcoinj/core/RejectMessage.java index 323637c6..f5a7e5df 100644 --- a/core/src/main/java/org/bitcoinj/core/RejectMessage.java +++ b/core/src/main/java/org/bitcoinj/core/RejectMessage.java @@ -1,5 +1,6 @@ /* * Copyright 2013 Matt Corallo + * Copyright 2015 Andreas Schildbach * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -82,7 +83,7 @@ public class RejectMessage extends Message { } @Override - protected void parseLite() throws ProtocolException { + protected void parse() throws ProtocolException { message = readStr(); code = RejectCode.fromCode(readBytes(1)[0]); reason = readStr(); @@ -91,12 +92,6 @@ public class RejectMessage extends Message { length = cursor - offset; } - @Override - public void parse() throws ProtocolException { - if (length == UNKNOWN_LENGTH) - parseLite(); - } - @Override public void bitcoinSerializeToStream(OutputStream stream) throws IOException { byte[] messageBytes = message.getBytes("UTF-8"); @@ -115,7 +110,6 @@ public class RejectMessage extends Message { * Note that this is ENTIRELY UNTRUSTED and should be sanity-checked before it is printed or processed. */ public String getRejectedMessage() { - ensureParsed(); return message; } @@ -123,7 +117,6 @@ public class RejectMessage extends Message { * Provides the hash of the rejected object (if getRejectedMessage() is either "tx" or "block"), otherwise null. */ public Sha256Hash getRejectedObjectHash() { - ensureParsed(); return messageHash; } diff --git a/core/src/main/java/org/bitcoinj/core/Transaction.java b/core/src/main/java/org/bitcoinj/core/Transaction.java index 15b21ed1..ae20fb0a 100644 --- a/core/src/main/java/org/bitcoinj/core/Transaction.java +++ b/core/src/main/java/org/bitcoinj/core/Transaction.java @@ -201,7 +201,6 @@ public class Transaction extends ChildMessage { * @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. @@ -253,7 +252,6 @@ public class Transaction extends ChildMessage { * include spent outputs or not. */ Coin getValueSentToMe(TransactionBag transactionBag, boolean includeSpent) { - maybeParse(); // This is tested in WalletTest. Coin v = Coin.ZERO; for (TransactionOutput o : outputs) { @@ -357,7 +355,6 @@ public class Transaction extends ChildMessage { * @return sum of the inputs that are spending coins with keys in the wallet */ public Coin getValueSentFromMe(TransactionBag wallet) throws ScriptException { - maybeParse(); // This is tested in WalletTest. Coin v = Coin.ZERO; for (TransactionInput input : inputs) { @@ -421,7 +418,6 @@ public class Transaction extends ChildMessage { * Returns true if any of the outputs is marked as spent. */ public boolean isAnyOutputSpent() { - maybeParse(); for (TransactionOutput output : outputs) { if (!output.isAvailableForSpending()) return true; @@ -434,7 +430,6 @@ public class Transaction extends ChildMessage { * otherwise. */ public boolean isEveryOwnedOutputSpent(TransactionBag transactionBag) { - maybeParse(); for (TransactionOutput output : outputs) { if (output.isAvailableForSpending() && output.isMineOrWatched(transactionBag)) return false; @@ -479,29 +474,6 @@ public class Transaction extends ChildMessage { hash = null; } - @Override - protected void parseLite() throws ProtocolException { - - //skip this if the length has been provided i.e. the tx is not part of a block - if (serializer.isParseLazyMode() && length == UNKNOWN_LENGTH) { - //If length hasn't been provided this tx is probably contained within a block. - //In parseRetain mode the block needs to know how long the transaction is - //unfortunately this requires a fairly deep (though not total) parse. - //This is due to the fact that transactions in the block's list do not include a - //size header and inputs/outputs are also variable length due the contained - //script so each must be instantiated so the scriptlength varint can be read - //to calculate total length of the transaction. - //We will still persist will this semi-light parsing because getting the lengths - //of the various components gains us the ability to cache the backing bytearrays - //so that only those subcomponents that have changed will need to be reserialized. - - //parse(); - //parsed = true; - length = calcLength(payload, offset); - cursor = offset + length; - } - } - protected static int calcLength(byte[] buf, int offset) { VarInt varint; // jump past version (uint32) @@ -539,11 +511,7 @@ public class Transaction extends ChildMessage { } @Override - void parse() throws ProtocolException { - - if (parsed) - return; - + protected void parse() throws ProtocolException { cursor = offset; version = readUint32(); @@ -579,7 +547,6 @@ public class Transaction extends ChildMessage { public int getOptimalEncodingMessageSize() { if (optimalEncodingMessageSize != 0) return optimalEncodingMessageSize; - maybeParse(); if (optimalEncodingMessageSize != 0) return optimalEncodingMessageSize; optimalEncodingMessageSize = getMessageSize(); @@ -610,7 +577,6 @@ public class Transaction extends ChildMessage { * position in a block but by the data in the inputs. */ public boolean isCoinBase() { - maybeParse(); return inputs.size() == 1 && inputs.get(0).isCoinBase(); } @@ -1067,7 +1033,6 @@ public class Transaction extends ChildMessage { * standard and won't be relayed or included in the memory pool either. */ public long getLockTime() { - maybeParse(); return lockTime; } @@ -1098,19 +1063,16 @@ public class Transaction extends ChildMessage { * @return the version */ public long getVersion() { - maybeParse(); return version; } /** Returns an unmodifiable view of all inputs. */ public List getInputs() { - maybeParse(); return Collections.unmodifiableList(inputs); } /** Returns an unmodifiable view of all outputs. */ public List getOutputs() { - maybeParse(); return Collections.unmodifiableList(outputs); } @@ -1123,7 +1085,6 @@ public class Transaction extends ChildMessage { * @return linked list of outputs relevant to the wallet in this transaction */ public List getWalletOutputs(TransactionBag transactionBag){ - maybeParse(); List walletOutputs = new LinkedList(); for (TransactionOutput o : outputs) { if (!o.isMineOrWatched(transactionBag)) continue; @@ -1135,19 +1096,16 @@ public class Transaction extends ChildMessage { /** Randomly re-orders the transaction outputs: good for privacy */ public void shuffleOutputs() { - maybeParse(); Collections.shuffle(outputs); } /** Same as getInputs().get(index). */ public TransactionInput getInput(long index) { - maybeParse(); return inputs.get((int)index); } /** Same as getOutputs().get(index) */ public TransactionOutput getOutput(long index) { - maybeParse(); return outputs.get((int)index); } @@ -1197,7 +1155,6 @@ public class Transaction extends ChildMessage { * Gets the count of regular SigOps in this transactions */ public int getSigOpCount() throws ScriptException { - maybeParse(); int sigOps = 0; for (TransactionInput input : inputs) sigOps += Script.getSigOpCount(input.getScriptBytes()); @@ -1223,7 +1180,6 @@ public class Transaction extends ChildMessage { * @throws VerificationException */ public void verify() throws VerificationException { - maybeParse(); if (inputs.size() == 0 || outputs.size() == 0) throw new VerificationException.EmptyInputsOrOutputs(); if (this.getMessageSize() > Block.MAX_BLOCK_SIZE) diff --git a/core/src/main/java/org/bitcoinj/core/TransactionInput.java b/core/src/main/java/org/bitcoinj/core/TransactionInput.java index 1f99a7b6..23a7561b 100644 --- a/core/src/main/java/org/bitcoinj/core/TransactionInput.java +++ b/core/src/main/java/org/bitcoinj/core/TransactionInput.java @@ -25,7 +25,6 @@ import com.google.common.base.Objects; import javax.annotation.Nullable; import java.io.IOException; -import java.io.ObjectOutputStream; import java.io.OutputStream; import java.lang.ref.WeakReference; import java.util.Arrays; @@ -126,18 +125,11 @@ public class TransactionInput extends ChildMessage { } @Override - protected void parseLite() throws ProtocolException { - int curs = cursor; - int scriptLen = (int) readVarInt(36); - length = cursor - offset + scriptLen + 4; - cursor = curs; - } - - @Override - void parse() throws ProtocolException { + protected void parse() throws ProtocolException { outpoint = new TransactionOutPoint(params, payload, cursor, this, serializer); cursor += outpoint.getMessageSize(); int scriptLen = (int) readVarInt(); + length = cursor - offset + scriptLen + 4; scriptBytes = readBytes(scriptLen); sequence = readUint32(); } @@ -154,7 +146,6 @@ public class TransactionInput extends ChildMessage { * Coinbase transactions have special inputs with hashes of zero. If this is such an input, returns true. */ public boolean isCoinBase() { - maybeParse(); return outpoint.getHash().equals(Sha256Hash.ZERO_HASH) && (outpoint.getIndex() & 0xFFFFFFFFL) == 0xFFFFFFFFL; // -1 but all is serialized to the wire as unsigned int. } @@ -168,7 +159,6 @@ public class TransactionInput extends ChildMessage { // parameter is overloaded to be something totally different. Script script = scriptSig == null ? null : scriptSig.get(); if (script == null) { - maybeParse(); script = new Script(scriptBytes); scriptSig = new WeakReference