msgreject.go raw

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