/** * Copyright 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.bitcoin.core; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; /** * Abstract superclass of classes with list based payload, i.e. InventoryMessage and GetDataMessage. */ public abstract class ListMessage extends Message { // For some reason the compiler complains if this is inside InventoryItem private List<InventoryItem> items; private static final long MAX_INVENTORY_ITEMS = 50000; public ListMessage(NetworkParameters params, byte[] bytes) throws ProtocolException { super(params, bytes, 0); } public ListMessage(NetworkParameters params) { super(params); items = new ArrayList<InventoryItem>(); } public List<InventoryItem> getItems() { return items; } public void addItem(InventoryItem item) { items.add(item); } @Override public void parse() throws ProtocolException { // An inv is vector<CInv> where CInv is int+hash. The int is either 1 or 2 for tx or block. long arrayLen = readVarInt(); if (arrayLen > MAX_INVENTORY_ITEMS) throw new ProtocolException("Too many items in INV message: " + arrayLen); items = new ArrayList<InventoryItem>((int)arrayLen); for (int i = 0; i < arrayLen; i++) { if (cursor + 4 + 32 > bytes.length) { throw new ProtocolException("Ran off the end of the INV"); } int typeCode = (int) readUint32(); InventoryItem.Type type; // See ppszTypeName in net.h switch (typeCode) { case 0: type = InventoryItem.Type.Error; break; case 1: type = InventoryItem.Type.Transaction; break; case 2: type = InventoryItem.Type.Block; break; default: throw new ProtocolException("Unknown CInv type: " + typeCode); } InventoryItem item = new InventoryItem(type, readHash()); items.add(item); } bytes = null; } @Override public void bitcoinSerializeToStream( OutputStream stream) throws IOException { stream.write(new VarInt(items.size()).encode()); for (InventoryItem i : items) { // Write out the type code. Utils.uint32ToByteStreamLE(i.type.ordinal(), stream); // And now the hash. stream.write(Utils.reverseBytes(i.hash)); } } }