OSDN Git Service

Merge pull request #41 from Bytom/dev
[bytom/vapor.git] / vendor / github.com / btcsuite / btcd / peer / log.go
1 // Copyright (c) 2015-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 peer
6
7 import (
8         "fmt"
9         "strings"
10         "time"
11
12         "github.com/btcsuite/btcd/chaincfg/chainhash"
13         "github.com/btcsuite/btcd/txscript"
14         "github.com/btcsuite/btcd/wire"
15         "github.com/btcsuite/btclog"
16 )
17
18 const (
19         // maxRejectReasonLen is the maximum length of a sanitized reject reason
20         // that will be logged.
21         maxRejectReasonLen = 250
22 )
23
24 // log is a logger that is initialized with no output filters.  This
25 // means the package will not perform any logging by default until the caller
26 // requests it.
27 var log btclog.Logger
28
29 // The default amount of logging is none.
30 func init() {
31         DisableLog()
32 }
33
34 // DisableLog disables all library log output.  Logging output is disabled
35 // by default until UseLogger is called.
36 func DisableLog() {
37         log = btclog.Disabled
38 }
39
40 // UseLogger uses a specified Logger to output package logging info.
41 func UseLogger(logger btclog.Logger) {
42         log = logger
43 }
44
45 // LogClosure is a closure that can be printed with %v to be used to
46 // generate expensive-to-create data for a detailed log level and avoid doing
47 // the work if the data isn't printed.
48 type logClosure func() string
49
50 func (c logClosure) String() string {
51         return c()
52 }
53
54 func newLogClosure(c func() string) logClosure {
55         return logClosure(c)
56 }
57
58 // directionString is a helper function that returns a string that represents
59 // the direction of a connection (inbound or outbound).
60 func directionString(inbound bool) string {
61         if inbound {
62                 return "inbound"
63         }
64         return "outbound"
65 }
66
67 // formatLockTime returns a transaction lock time as a human-readable string.
68 func formatLockTime(lockTime uint32) string {
69         // The lock time field of a transaction is either a block height at
70         // which the transaction is finalized or a timestamp depending on if the
71         // value is before the lockTimeThreshold.  When it is under the
72         // threshold it is a block height.
73         if lockTime < txscript.LockTimeThreshold {
74                 return fmt.Sprintf("height %d", lockTime)
75         }
76
77         return time.Unix(int64(lockTime), 0).String()
78 }
79
80 // invSummary returns an inventory message as a human-readable string.
81 func invSummary(invList []*wire.InvVect) string {
82         // No inventory.
83         invLen := len(invList)
84         if invLen == 0 {
85                 return "empty"
86         }
87
88         // One inventory item.
89         if invLen == 1 {
90                 iv := invList[0]
91                 switch iv.Type {
92                 case wire.InvTypeError:
93                         return fmt.Sprintf("error %s", iv.Hash)
94                 case wire.InvTypeWitnessBlock:
95                         return fmt.Sprintf("witness block %s", iv.Hash)
96                 case wire.InvTypeBlock:
97                         return fmt.Sprintf("block %s", iv.Hash)
98                 case wire.InvTypeWitnessTx:
99                         return fmt.Sprintf("witness tx %s", iv.Hash)
100                 case wire.InvTypeTx:
101                         return fmt.Sprintf("tx %s", iv.Hash)
102                 }
103
104                 return fmt.Sprintf("unknown (%d) %s", uint32(iv.Type), iv.Hash)
105         }
106
107         // More than one inv item.
108         return fmt.Sprintf("size %d", invLen)
109 }
110
111 // locatorSummary returns a block locator as a human-readable string.
112 func locatorSummary(locator []*chainhash.Hash, stopHash *chainhash.Hash) string {
113         if len(locator) > 0 {
114                 return fmt.Sprintf("locator %s, stop %s", locator[0], stopHash)
115         }
116
117         return fmt.Sprintf("no locator, stop %s", stopHash)
118
119 }
120
121 // sanitizeString strips any characters which are even remotely dangerous, such
122 // as html control characters, from the passed string.  It also limits it to
123 // the passed maximum size, which can be 0 for unlimited.  When the string is
124 // limited, it will also add "..." to the string to indicate it was truncated.
125 func sanitizeString(str string, maxLength uint) string {
126         const safeChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY" +
127                 "Z01234567890 .,;_/:?@"
128
129         // Strip any characters not in the safeChars string removed.
130         str = strings.Map(func(r rune) rune {
131                 if strings.ContainsRune(safeChars, r) {
132                         return r
133                 }
134                 return -1
135         }, str)
136
137         // Limit the string to the max allowed length.
138         if maxLength > 0 && uint(len(str)) > maxLength {
139                 str = str[:maxLength]
140                 str = str + "..."
141         }
142         return str
143 }
144
145 // messageSummary returns a human-readable string which summarizes a message.
146 // Not all messages have or need a summary.  This is used for debug logging.
147 func messageSummary(msg wire.Message) string {
148         switch msg := msg.(type) {
149         case *wire.MsgVersion:
150                 return fmt.Sprintf("agent %s, pver %d, block %d",
151                         msg.UserAgent, msg.ProtocolVersion, msg.LastBlock)
152
153         case *wire.MsgVerAck:
154                 // No summary.
155
156         case *wire.MsgGetAddr:
157                 // No summary.
158
159         case *wire.MsgAddr:
160                 return fmt.Sprintf("%d addr", len(msg.AddrList))
161
162         case *wire.MsgPing:
163                 // No summary - perhaps add nonce.
164
165         case *wire.MsgPong:
166                 // No summary - perhaps add nonce.
167
168         case *wire.MsgAlert:
169                 // No summary.
170
171         case *wire.MsgMemPool:
172                 // No summary.
173
174         case *wire.MsgTx:
175                 return fmt.Sprintf("hash %s, %d inputs, %d outputs, lock %s",
176                         msg.TxHash(), len(msg.TxIn), len(msg.TxOut),
177                         formatLockTime(msg.LockTime))
178
179         case *wire.MsgBlock:
180                 header := &msg.Header
181                 return fmt.Sprintf("hash %s, ver %d, %d tx, %s", msg.BlockHash(),
182                         header.Version, len(msg.Transactions), header.Timestamp)
183
184         case *wire.MsgInv:
185                 return invSummary(msg.InvList)
186
187         case *wire.MsgNotFound:
188                 return invSummary(msg.InvList)
189
190         case *wire.MsgGetData:
191                 return invSummary(msg.InvList)
192
193         case *wire.MsgGetBlocks:
194                 return locatorSummary(msg.BlockLocatorHashes, &msg.HashStop)
195
196         case *wire.MsgGetHeaders:
197                 return locatorSummary(msg.BlockLocatorHashes, &msg.HashStop)
198
199         case *wire.MsgHeaders:
200                 return fmt.Sprintf("num %d", len(msg.Headers))
201
202         case *wire.MsgReject:
203                 // Ensure the variable length strings don't contain any
204                 // characters which are even remotely dangerous such as HTML
205                 // control characters, etc.  Also limit them to sane length for
206                 // logging.
207                 rejCommand := sanitizeString(msg.Cmd, wire.CommandSize)
208                 rejReason := sanitizeString(msg.Reason, maxRejectReasonLen)
209                 summary := fmt.Sprintf("cmd %v, code %v, reason %v", rejCommand,
210                         msg.Code, rejReason)
211                 if rejCommand == wire.CmdBlock || rejCommand == wire.CmdTx {
212                         summary += fmt.Sprintf(", hash %v", msg.Hash)
213                 }
214                 return summary
215         }
216
217         // No summary for other messages.
218         return ""
219 }