package org.ripple.power.txns.btc; import java.io.EOFException; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; import org.ripple.power.Helper; /** * <p>A 'reject' message is sent when the receiver rejects a message. The message * contains a reason code and text description for the rejection. There is no * response to the message - it is merely a diagnostic aid. However, the sender * may disconnect if too many rejections occur.</p> * * <p>Reject Message</p> * <pre> * Size Field Description * ==== ===== =========== * VarString Command The failing command * 1 byte Reason The reason code * VarString Description Descriptive text * 32 bytes Hash Block hash ('block') or transaction hash ('tx'), omitted otherwise * </pre> */ public class RejectMessage { /** Malformed message */ public static final int REJECT_MALFORMED = 0x01; /** Invalid message */ public static final int REJECT_INVALID = 0x10; /** Obsolete message */ public static final int REJECT_OBSOLETE = 0x11; /** Duplicate transaction */ public static final int REJECT_DUPLICATE = 0x12; /** Non-standard transaction */ public static final int REJECT_NONSTANDARD = 0x40; /** Dust transaction */ public static final int REJECT_DUST = 0x41; /** Insufficient fee provided */ public static final int REJECT_INSUFFICIENT_FEE = 0x42; /** Block checkpoint mismatch */ public static final int REJECT_CHECKPOINT = 0x43; /** Reject message reason code mappings */ public static final Map<Integer, String> reasonCodes = new HashMap<>(); static { reasonCodes.put(REJECT_MALFORMED, "Malformed"); reasonCodes.put(REJECT_INVALID, "Invalid"); reasonCodes.put(REJECT_OBSOLETE, "Obsolete"); reasonCodes.put(REJECT_DUPLICATE, "Duplicate"); reasonCodes.put(REJECT_NONSTANDARD, "Nonstandard"); reasonCodes.put(REJECT_DUST, "Dust"); reasonCodes.put(REJECT_INSUFFICIENT_FEE, "Insufficient fee"); reasonCodes.put(REJECT_CHECKPOINT, "Checkpoint"); } /** * Builds a 'reject' message to be sent to the destination peer * * @param peer Destination peer * @param cmd Failing command * @param reason Reason code * @param description Descriptive text * @return 'reject' message */ public static Message buildRejectMessage(Peer peer, String cmd, int reason, String description) { return buildRejectMessage(peer, cmd, reason, description, Sha256Hash.ZERO_HASH); } /** * Builds a 'reject' message to be sent to the destination peer * * @param peer Destination peer * @param cmd Failing command * @param reason Reason code * @param desc Descriptive text * @param hash Block or transaction hash * @return 'reject' message */ public static Message buildRejectMessage(Peer peer, String cmd, int reason, String desc, Sha256Hash hash) { // // Build the message data // SerializedBuffer msgBuffer = new SerializedBuffer(); msgBuffer.putString(cmd) .putUnsignedByte(reason) .putString(desc); if (!hash.equals(Sha256Hash.ZERO_HASH)) msgBuffer.putBytes(Helper.reverseBytes(hash.getBytes())); // // Build the message // ByteBuffer buffer = MessageHeader.buildMessage("reject", msgBuffer); return new Message(buffer, peer, MessageHeader.MessageCommand.REJECT); } /** * Processes a 'reject' message * * @param msg Message * @param inBuffer Input buffer * @param msgListener Message listener * @throws EOFException Serialized byte stream is too short */ public static void processRejectMessage(Message msg, SerializedBuffer inBuffer, MessageListener msgListener) throws EOFException { // // Get the command name // String cmd = inBuffer.getString(); // // Get the reason code // int reasonCode = inBuffer.getUnsignedByte(); // // Get the description // String desc = inBuffer.getString(); // // Get the hash // Sha256Hash hash = Sha256Hash.ZERO_HASH; if (inBuffer.available() >= 32) hash = new Sha256Hash(Helper.reverseBytes(inBuffer.getBytes(32))); // // Notify the message listener // msgListener.processReject(msg, cmd, reasonCode, desc, hash); } }