Message: extract interface, add BaseMessage abstract class

This commit is contained in:
Sean Gilligan 2023-04-09 07:56:54 -07:00 committed by Andreas Schildbach
parent 78a76f76a5
commit 1fef4e2cdb
17 changed files with 148 additions and 106 deletions

View file

@ -26,7 +26,7 @@ import java.util.List;
* Abstract superclass for address messages on the P2P network, which contain network addresses of other peers. This is
* one of the ways peers can find each other without using the {@link PeerDiscovery} mechanism.
*/
public abstract class AddressMessage extends Message {
public abstract class AddressMessage extends BaseMessage {
protected static final long MAX_ADDRESSES = 1000;
protected List<PeerAddress> addresses;

View file

@ -0,0 +1,117 @@
/*
* Copyright by the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.bitcoinj.base.Sha256Hash;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
/**
* A Message is a data structure that can be serialized/deserialized using the Bitcoin serialization format.
* Specific types of messages that are used both in the blockchain, and on the wire, are derived from this
* class.
* <p>
* Instances of this class are not safe for use by multiple threads.
*/
public abstract class BaseMessage implements Message {
private static final Logger log = LoggerFactory.getLogger(BaseMessage.class);
protected final MessageSerializer serializer;
protected BaseMessage() {
this.serializer = DummySerializer.DEFAULT;
}
protected BaseMessage(MessageSerializer serializer) {
this.serializer = serializer;
}
/**
* @param payload Bitcoin protocol formatted byte array containing message content.
* @param serializer the serializer to use for this message.
* @throws ProtocolException
*/
protected BaseMessage(ByteBuffer payload, MessageSerializer serializer) throws ProtocolException {
this.serializer = serializer;
try {
parse(payload);
} catch(BufferUnderflowException e) {
throw new ProtocolException(e);
}
}
protected BaseMessage(ByteBuffer payload) throws ProtocolException {
this(payload, DummySerializer.DEFAULT);
}
// These methods handle the serialization/deserialization using the custom Bitcoin protocol.
protected abstract void parse(ByteBuffer payload) throws BufferUnderflowException, ProtocolException;
/**
* <p>Serialize this message to a byte array that conforms to the bitcoin wire protocol.</p>
*
* @return serialized data in Bitcoin protocol format
*/
@Override
public final byte[] bitcoinSerialize() {
// No cached array available so serialize parts by stream.
ByteArrayOutputStream stream = new ByteArrayOutputStream(100); // initial size just a guess
try {
bitcoinSerializeToStream(stream);
} catch (IOException e) {
// Cannot happen, we are serializing to a memory stream.
}
return stream.toByteArray();
}
/** @deprecated use {@link #bitcoinSerialize()} */
@Deprecated
public byte[] unsafeBitcoinSerialize() {
return bitcoinSerialize();
}
/**
* Serializes this message to the provided stream. If you just want the raw bytes use bitcoinSerialize().
*/
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
log.error("Error: {} class has not implemented bitcoinSerializeToStream method. Generating message with no payload", getClass());
}
/** @deprecated use {@link Transaction#getTxId()}, {@link Block#getHash()}, {@link FilteredBlock#getHash()} or {@link TransactionOutPoint#hash()} */
@Deprecated
public Sha256Hash getHash() {
throw new UnsupportedOperationException();
}
/**
* Return the size of the serialized message. Note that if the message was deserialized from a payload, this
* size can differ from the size of the original payload.
* @return size of this object when serialized (in bytes)
*/
@Override
public int getMessageSize() {
return bitcoinSerialize().length;
}
}

View file

@ -70,7 +70,7 @@ import static org.bitcoinj.base.internal.Preconditions.checkState;
*
* <p>Instances of this class are not safe for use by multiple threads.</p>
*/
public class Block extends Message {
public class Block extends BaseMessage {
/**
* Flags used to control which elements of block validation are done on
* received blocks.

View file

@ -55,7 +55,7 @@ import static org.bitcoinj.base.internal.Preconditions.checkArgument;
*
* <p>Instances of this class are not safe for use by multiple threads.</p>
*/
public class BloomFilter extends Message {
public class BloomFilter extends BaseMessage {
/** The BLOOM_UPDATE_* constants control when the bloom filter is auto-updated by the peer using
it as a filter, either never, for all outputs or only for P2PK outputs (default) */
public enum BloomUpdate {

View file

@ -28,7 +28,7 @@ import java.nio.ByteBuffer;
*
* <p>Instances of this class are not safe for use by multiple threads.</p>
*/
public abstract class EmptyMessage extends Message {
public abstract class EmptyMessage extends BaseMessage {
public EmptyMessage() {
super();

View file

@ -34,7 +34,7 @@ import static org.bitcoinj.base.internal.Preconditions.check;
*
* <p>Instances of this class are not safe for use by multiple threads.</p>
*/
public class FeeFilterMessage extends Message {
public class FeeFilterMessage extends BaseMessage {
private Coin feeRate;
public FeeFilterMessage(ByteBuffer payload) {

View file

@ -37,7 +37,7 @@ import java.util.Objects;
*
* <p>Instances of this class are not safe for use by multiple threads.</p>
*/
public class FilteredBlock extends Message {
public class FilteredBlock extends BaseMessage {
private Block header;
private PartialMerkleTree merkleTree;

View file

@ -34,7 +34,7 @@ import static org.bitcoinj.base.internal.Preconditions.check;
*
* <p>Instances of this class are not safe for use by multiple threads.</p>
*/
public class GetBlocksMessage extends Message {
public class GetBlocksMessage extends BaseMessage {
protected long version;
protected BlockLocator locator;

View file

@ -38,7 +38,7 @@ import static org.bitcoinj.base.internal.Preconditions.check;
*
* <p>Instances of this class are not safe for use by multiple threads.</p>
*/
public class HeadersMessage extends Message {
public class HeadersMessage extends BaseMessage {
private static final Logger log = LoggerFactory.getLogger(HeadersMessage.class);
// The main client will never send us more than this number of headers.

View file

@ -37,7 +37,7 @@ import static org.bitcoinj.base.internal.Preconditions.check;
*
* <p>Instances of this class are not safe for use by multiple threads.</p>
*/
public abstract class ListMessage extends Message {
public abstract class ListMessage extends BaseMessage {
// For some reason the compiler complains if this is inside InventoryItem
protected List<InventoryItem> items;

View file

@ -1,6 +1,5 @@
/*
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
* Copyright by the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,102 +16,28 @@
package org.bitcoinj.core;
import org.bitcoinj.base.Sha256Hash;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
/**
* <p>A Message is a data structure that can be serialized/deserialized using the Bitcoin serialization format.
* Specific types of messages that are used both in the block chain, and on the wire, are derived from this
* class.</p>
*
* <p>Instances of this class are not safe for use by multiple threads.</p>
* A Message is a data structure that can be serialized/deserialized using the Bitcoin serialization format.
* Classes that can be serialized to the blockchain or P2P protocol should implement this interface.
*/
public abstract class Message {
private static final Logger log = LoggerFactory.getLogger(Message.class);
public static final int MAX_SIZE = 0x02000000; // 32MB
protected final MessageSerializer serializer;
protected Message() {
this.serializer = DummySerializer.DEFAULT;
}
protected Message(MessageSerializer serializer) {
this.serializer = serializer;
}
public interface Message {
/**
* @param payload Bitcoin protocol formatted byte array containing message content.
* @param serializer the serializer to use for this message.
* @throws ProtocolException
* Maximum size of a Bitcoin P2P Message (32 MB)
*/
protected Message(ByteBuffer payload, MessageSerializer serializer) throws ProtocolException {
this.serializer = serializer;
try {
parse(payload);
} catch(BufferUnderflowException e) {
throw new ProtocolException(e);
}
}
protected Message(ByteBuffer payload) throws ProtocolException {
this(payload, DummySerializer.DEFAULT);
}
// These methods handle the serialization/deserialization using the custom Bitcoin protocol.
protected abstract void parse(ByteBuffer payload) throws BufferUnderflowException, ProtocolException;
/**
* <p>Serialize this message to a byte array that conforms to the bitcoin wire protocol.</p>
*
* @return a byte array
*/
public final byte[] bitcoinSerialize() {
// No cached array available so serialize parts by stream.
ByteArrayOutputStream stream = new ByteArrayOutputStream(100); // initial size just a guess
try {
bitcoinSerializeToStream(stream);
} catch (IOException e) {
// Cannot happen, we are serializing to a memory stream.
}
return stream.toByteArray();
}
/** @deprecated use {@link #bitcoinSerialize()} */
@Deprecated
public byte[] unsafeBitcoinSerialize() {
return bitcoinSerialize();
}
/**
* Serializes this message to the provided stream. If you just want the raw bytes use bitcoinSerialize().
*/
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
log.error("Error: {} class has not implemented bitcoinSerializeToStream method. Generating message with no payload", getClass());
}
/** @deprecated use {@link Transaction#getTxId()}, {@link Block#getHash()}, {@link FilteredBlock#getHash()} or {@link TransactionOutPoint#hash()} */
@Deprecated
public Sha256Hash getHash() {
throw new UnsupportedOperationException();
}
int MAX_SIZE = 0x02000000;
/**
* Return the size of the serialized message. Note that if the message was deserialized from a payload, this
* size can differ from the size of the original payload.
* @return size of the serialized message in bytes
*
* @return size of this object when serialized (in bytes)
*/
public int getMessageSize() {
return bitcoinSerialize().length;
}
int getMessageSize();
/**
* Serialize this message to a byte array that conforms to the Bitcoin wire protocol.
*
* @return serialized data in Bitcoin protocol format
*/
byte[] bitcoinSerialize();
}

View file

@ -30,7 +30,7 @@ import java.util.Random;
*
* <p>Instances of this class are not safe for use by multiple threads.</p>
*/
public class Ping extends Message {
public class Ping extends BaseMessage {
private long nonce;
public Ping(ByteBuffer payload) throws ProtocolException {

View file

@ -29,7 +29,7 @@ import java.nio.ByteBuffer;
*
* <p>Instances of this class are not safe for use by multiple threads.</p>
*/
public class Pong extends Message {
public class Pong extends BaseMessage {
private long nonce;
public Pong(ByteBuffer payload) throws ProtocolException {

View file

@ -35,7 +35,7 @@ import java.util.stream.Stream;
*
* <p>Instances of this class are not safe for use by multiple threads.</p>
*/
public class RejectMessage extends Message {
public class RejectMessage extends BaseMessage {
private String message, reason;
public enum RejectCode {

View file

@ -92,7 +92,7 @@ import static org.bitcoinj.base.internal.ByteUtils.writeInt64LE;
*
* <p>Instances of this class are not safe for use by multiple threads.</p>
*/
public class Transaction extends Message {
public class Transaction extends BaseMessage {
private static final Comparator<Transaction> SORT_TX_BY_ID = Comparator.comparing(Transaction::getTxId);
/**

View file

@ -48,7 +48,7 @@ import static org.bitcoinj.base.internal.Preconditions.check;
*
* <p>Instances of this class are not safe for use by multiple threads.</p>
*/
public class VersionMessage extends Message {
public class VersionMessage extends BaseMessage {
/** The version of this library release, as a string. */
public static final String BITCOINJ_VERSION = "0.17-SNAPSHOT";

View file

@ -233,7 +233,7 @@ public class BitcoinSerializerTest {
public void testSerializeUnknownMessage() throws Exception {
MessageSerializer serializer = MAINNET.getDefaultSerializer();
Message unknownMessage = new Message() {
Message unknownMessage = new BaseMessage() {
@Override
protected void parse(ByteBuffer payload) throws BufferUnderflowException, ProtocolException {
}