github.com/btcsuite/btcd@v0.24.0/wire/msgreject.go (about)

     1  // Copyright (c) 2014-2016 The btcsuite developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package wire
     6  
     7  import (
     8  	"fmt"
     9  	"io"
    10  
    11  	"github.com/btcsuite/btcd/chaincfg/chainhash"
    12  )
    13  
    14  // RejectCode represents a numeric value by which a remote peer indicates
    15  // why a message was rejected.
    16  type RejectCode uint8
    17  
    18  // These constants define the various supported reject codes.
    19  const (
    20  	RejectMalformed       RejectCode = 0x01
    21  	RejectInvalid         RejectCode = 0x10
    22  	RejectObsolete        RejectCode = 0x11
    23  	RejectDuplicate       RejectCode = 0x12
    24  	RejectNonstandard     RejectCode = 0x40
    25  	RejectDust            RejectCode = 0x41
    26  	RejectInsufficientFee RejectCode = 0x42
    27  	RejectCheckpoint      RejectCode = 0x43
    28  )
    29  
    30  // Map of reject codes back strings for pretty printing.
    31  var rejectCodeStrings = map[RejectCode]string{
    32  	RejectMalformed:       "REJECT_MALFORMED",
    33  	RejectInvalid:         "REJECT_INVALID",
    34  	RejectObsolete:        "REJECT_OBSOLETE",
    35  	RejectDuplicate:       "REJECT_DUPLICATE",
    36  	RejectNonstandard:     "REJECT_NONSTANDARD",
    37  	RejectDust:            "REJECT_DUST",
    38  	RejectInsufficientFee: "REJECT_INSUFFICIENTFEE",
    39  	RejectCheckpoint:      "REJECT_CHECKPOINT",
    40  }
    41  
    42  // String returns the RejectCode in human-readable form.
    43  func (code RejectCode) String() string {
    44  	if s, ok := rejectCodeStrings[code]; ok {
    45  		return s
    46  	}
    47  
    48  	return fmt.Sprintf("Unknown RejectCode (%d)", uint8(code))
    49  }
    50  
    51  // MsgReject implements the Message interface and represents a bitcoin reject
    52  // message.
    53  //
    54  // This message was not added until protocol version RejectVersion.
    55  type MsgReject struct {
    56  	// Cmd is the command for the message which was rejected such as
    57  	// as CmdBlock or CmdTx.  This can be obtained from the Command function
    58  	// of a Message.
    59  	Cmd string
    60  
    61  	// RejectCode is a code indicating why the command was rejected.  It
    62  	// is encoded as a uint8 on the wire.
    63  	Code RejectCode
    64  
    65  	// Reason is a human-readable string with specific details (over and
    66  	// above the reject code) about why the command was rejected.
    67  	Reason string
    68  
    69  	// Hash identifies a specific block or transaction that was rejected
    70  	// and therefore only applies the MsgBlock and MsgTx messages.
    71  	Hash chainhash.Hash
    72  }
    73  
    74  // BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
    75  // This is part of the Message interface implementation.
    76  func (msg *MsgReject) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
    77  	if pver < RejectVersion {
    78  		str := fmt.Sprintf("reject message invalid for protocol "+
    79  			"version %d", pver)
    80  		return messageError("MsgReject.BtcDecode", str)
    81  	}
    82  
    83  	// Command that was rejected.
    84  	buf := binarySerializer.Borrow()
    85  	defer binarySerializer.Return(buf)
    86  
    87  	cmd, err := readVarStringBuf(r, pver, buf)
    88  	if err != nil {
    89  		return err
    90  	}
    91  	msg.Cmd = cmd
    92  
    93  	// Code indicating why the command was rejected.
    94  	if _, err := io.ReadFull(r, buf[:1]); err != nil {
    95  		return err
    96  	}
    97  	msg.Code = RejectCode(buf[0])
    98  
    99  	// Human readable string with specific details (over and above the
   100  	// reject code above) about why the command was rejected.
   101  	reason, err := readVarStringBuf(r, pver, buf)
   102  	if err != nil {
   103  		return err
   104  	}
   105  	msg.Reason = reason
   106  
   107  	// CmdBlock and CmdTx messages have an additional hash field that
   108  	// identifies the specific block or transaction.
   109  	if msg.Cmd == CmdBlock || msg.Cmd == CmdTx {
   110  		_, err := io.ReadFull(r, msg.Hash[:])
   111  		if err != nil {
   112  			return err
   113  		}
   114  	}
   115  
   116  	return nil
   117  }
   118  
   119  // BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
   120  // This is part of the Message interface implementation.
   121  func (msg *MsgReject) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
   122  	if pver < RejectVersion {
   123  		str := fmt.Sprintf("reject message invalid for protocol "+
   124  			"version %d", pver)
   125  		return messageError("MsgReject.BtcEncode", str)
   126  	}
   127  
   128  	// Command that was rejected.
   129  	buf := binarySerializer.Borrow()
   130  	defer binarySerializer.Return(buf)
   131  
   132  	err := writeVarStringBuf(w, pver, msg.Cmd, buf)
   133  	if err != nil {
   134  		return err
   135  	}
   136  
   137  	// Code indicating why the command was rejected.
   138  	buf[0] = byte(msg.Code)
   139  	if _, err := w.Write(buf[:1]); err != nil {
   140  		return err
   141  	}
   142  
   143  	// Human readable string with specific details (over and above the
   144  	// reject code above) about why the command was rejected.
   145  	err = writeVarStringBuf(w, pver, msg.Reason, buf)
   146  	if err != nil {
   147  		return err
   148  	}
   149  
   150  	// CmdBlock and CmdTx messages have an additional hash field that
   151  	// identifies the specific block or transaction.
   152  	if msg.Cmd == CmdBlock || msg.Cmd == CmdTx {
   153  		_, err := w.Write(msg.Hash[:])
   154  		if err != nil {
   155  			return err
   156  		}
   157  	}
   158  
   159  	return nil
   160  }
   161  
   162  // Command returns the protocol command string for the message.  This is part
   163  // of the Message interface implementation.
   164  func (msg *MsgReject) Command() string {
   165  	return CmdReject
   166  }
   167  
   168  // MaxPayloadLength returns the maximum length the payload can be for the
   169  // receiver.  This is part of the Message interface implementation.
   170  func (msg *MsgReject) MaxPayloadLength(pver uint32) uint32 {
   171  	plen := uint32(0)
   172  	// The reject message did not exist before protocol version
   173  	// RejectVersion.
   174  	if pver >= RejectVersion {
   175  		// Unfortunately the bitcoin protocol does not enforce a sane
   176  		// limit on the length of the reason, so the max payload is the
   177  		// overall maximum message payload.
   178  		plen = MaxMessagePayload
   179  	}
   180  
   181  	return plen
   182  }
   183  
   184  // NewMsgReject returns a new bitcoin reject message that conforms to the
   185  // Message interface.  See MsgReject for details.
   186  func NewMsgReject(command string, code RejectCode, reason string) *MsgReject {
   187  	return &MsgReject{
   188  		Cmd:    command,
   189  		Code:   code,
   190  		Reason: reason,
   191  	}
   192  }