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 }