/
BitcoindException.scala
323 lines (274 loc) · 9.37 KB
/
BitcoindException.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
package org.bitcoins.rpc
import play.api.libs.json.Reads
import play.api.libs.json.{JsResult, JsValue}
import play.api.libs.json.JsError
import play.api.libs.json.JsSuccess
/** Represents failures that can happen when using the `bitcoind` RPC interface.
*
* @see
* [[https://github.com/bitcoin/bitcoin/blob/eb7daf4d600eeb631427c018a984a77a34aca66e/src/rpc/protocol.h#L32 protcol.h]]
* for an enumeration of all error codes used
*/
sealed abstract class BitcoindException(private val message: String)
extends Exception {
override def getMessage(): String = s"Error $code: $message"
val code: Int
}
/** Wallet errors from `bitcoind` RPC calls
*
* @see
* [[https://github.com/bitcoin/bitcoin/blob/eb7daf4d600eeb631427c018a984a77a34aca66e/src/rpc/protocol.h#L32 protcol.h]]
* for an enumeration of all error codes used
*/
object BitcoindException {
import org.bitcoins.rpc.BitcoindP2PException._
import org.bitcoins.rpc.BitcoindWalletException._
implicit val reads: Reads[BitcoindException] = new Reads[BitcoindException] {
def reads(json: JsValue): JsResult[BitcoindException] =
for {
code <- (json \ "code").validate[Int]
message <- (json \ "message").validate[String]
exception <- BitcoindException.fromCodeAndMessage(code, message) match {
case None =>
JsError(
s"Could not construct bitcoind exception with code $code and message '$message'"
)
case Some(value) => JsSuccess(value)
}
} yield exception
}
private val all: List[String => BitcoindException] = List(
InvalidParams(_),
InternalError(_),
ParseError(_),
MiscError(_),
TypeError(_),
InvalidAddressOrKey(_),
OutOfMemory(_),
InvalidParameter(_),
DatabaseError(_),
DeserializationError(_),
VerifyError(_),
VerifyRejected(_),
VerifyAlreadyInChain(_),
InWarmUp(_),
MethodDeprecated(_),
ForbiddenBySafeMode(_),
InInitialDownload(_),
NodeAlreadyAdded(_),
NodeNotAdded(_),
NodeNotConnected(_),
InvalidIpOrSubnet(_),
P2PDisabled(_),
WalletError(_),
InsufficientFunds(_),
InvalidLabelName(_),
KeypoolRanOut(_),
UnlockNeeded(_),
PassphraseIncorrect(_),
WrongEncState(_),
EncryptionFailed(_),
AlreadyUnlocked(_),
NotFound(_),
NotSpecified(_)
)
/** Attempts to construct a BitcoindException from the given code and message
*/
def fromCodeAndMessage(
code: Int,
message: String
): Option[BitcoindException] = {
val constructorOpt = all.find(func => func(message).code == code)
constructorOpt.map(func => func(message))
}
final case class InvalidParams(private val message: String)
extends BitcoindException(message) {
val code: Int = -32602
}
/** InternalError is only used for genuine errors in bitcoind (for example
* datadir corruption)
*/
final case class InternalError(private val message: String)
extends BitcoindException(message) {
val code: Int = -32603
}
final case class ParseError(private val message: String)
extends BitcoindException(message) {
val code: Int = -32700
}
/** `std::exception` thrown in command handling */
final case class MiscError(private val message: String)
extends BitcoindException(message) {
val code: Int = -1
}
/** Unexpected type was passed as parameter */
final case class TypeError(private val message: String)
extends BitcoindException(message) {
val code: Int = -3
}
/** Invalid address or key */
final case class InvalidAddressOrKey(private val message: String)
extends BitcoindException(message) {
val code: Int = -5
}
/** Ran out of memory during operation */
final case class OutOfMemory(private val message: String)
extends BitcoindException(message) {
val code: Int = -7
}
/** Invalid, missing or duplicate parameter */
final case class InvalidParameter(private val message: String)
extends BitcoindException(message) {
val code: Int = -8
}
/** Database error */
final case class DatabaseError(private val message: String)
extends BitcoindException(message) {
val code: Int = -20
}
/** Error parsing or validating structure in raw format */
final case class DeserializationError(private val message: String)
extends BitcoindException(message) {
val code: Int = -22
}
/** General error during transaction or block submission */
final case class VerifyError(private val message: String)
extends BitcoindException(message) {
val code: Int = -25
}
/** Transaction or block was rejected by network rules */
final case class VerifyRejected(private val message: String)
extends BitcoindException(
if (message == "non-final")
"Transaction is not final. Try again in a bit."
else message
) {
val code: Int = -26
}
/** Transaction already in chain */
final case class VerifyAlreadyInChain(private val message: String)
extends BitcoindException(message) {
val code: Int = -27
}
/** Client still warming up */
final case class InWarmUp(private val message: String)
extends BitcoindException(message) {
val code: Int = -28
}
/** RPC method is deprecated */
final case class MethodDeprecated(private val message: String)
extends BitcoindException(message) {
val code: Int = -32
}
/** Server is in safe mode, and command is not allowed in safe mode */
final case class ForbiddenBySafeMode(private val message: String)
extends BitcoindException(message) {
val code: Int = -2
}
}
/** P2P client errors
*
* @see
* [[https://github.com/bitcoin/bitcoin/blob/eb7daf4d600eeb631427c018a984a77a34aca66e/src/rpc/protocol.h#L32 protcol.h]]
* for an enumeration of all error codes used
*/
sealed abstract class BitcoindP2PException(private val message: String)
extends BitcoindException(message)
object BitcoindP2PException {
/** Bitcoin is not connected */
final case class NotConnected(private val message: String)
extends BitcoindP2PException(message) {
val code: Int = -9
}
/** Still downloading initial blocks */
final case class InInitialDownload(private val message: String)
extends BitcoindP2PException(message) {
val code: Int = -10
}
/** Node is already added */
final case class NodeAlreadyAdded(private val message: String)
extends BitcoindP2PException(message) {
val code: Int = -23
}
/** Node has not been added before */
final case class NodeNotAdded(private val message: String)
extends BitcoindP2PException(message) {
val code: Int = -24
}
/** Node to disconnect not found in connected nodes */
final case class NodeNotConnected(private val message: String)
extends BitcoindP2PException(message) {
val code: Int = -29
}
/** Invalid IP/Subnet */
final case class InvalidIpOrSubnet(private val message: String)
extends BitcoindP2PException(message) {
val code: Int = -30
}
/** No valid connection manager instance found */
final case class P2PDisabled(private val message: String)
extends BitcoindP2PException(message) {
val code: Int = -31
}
}
sealed abstract class BitcoindWalletException(private val message: String)
extends BitcoindException(message)
object BitcoindWalletException {
/** Unspecified problem with wallet (key not found etc.) */
final case class WalletError(private val message: String)
extends BitcoindWalletException(message) {
val code: Int = -4
}
/** Not enough funds in wallet or account */
final case class InsufficientFunds(private val message: String)
extends BitcoindWalletException(message) {
val code: Int = -6
}
/** Invalid label name */
final case class InvalidLabelName(private val message: String)
extends BitcoindWalletException(message) {
val code: Int = -11
}
/** Keypool ran out, call keypoolrefill first */
final case class KeypoolRanOut(private val message: String)
extends BitcoindWalletException(message) {
val code: Int = -12
}
/** Enter the wallet passphrase with walletpassphrase first */
final case class UnlockNeeded(private val message: String)
extends BitcoindWalletException(message) {
val code: Int = -13
}
/** The wallet passphrase entered was incorrect */
final case class PassphraseIncorrect(private val message: String)
extends BitcoindWalletException(message) {
val code: Int = -14
}
/** Command given in wrong wallet encryption state (encrypting an encrypted
* wallet etc.)
*/
final case class WrongEncState(private val message: String)
extends BitcoindWalletException(message) {
val code: Int = -15
}
/** Failed to encrypt the wallet */
final case class EncryptionFailed(private val message: String)
extends BitcoindWalletException(message) {
val code: Int = -16
}
/** Wallet is already unlocked */
final case class AlreadyUnlocked(private val message: String)
extends BitcoindWalletException(message) {
val code: Int = -17
}
/** Invalid wallet specified */
final case class NotFound(private val message: String)
extends BitcoindWalletException(message) {
val code: Int = -18
}
/** No wallet specified (error when there are multiple wallets loaded) */
final case class NotSpecified(private val message: String)
extends BitcoindWalletException(message) {
val code: Int = -19
}
}