Skip to content

Commit 103619e

Browse files
committed
ETCM-167: Preserve the innermost encodeable in errors.
1 parent e563d29 commit 103619e

File tree

1 file changed

+27
-19
lines changed

1 file changed

+27
-19
lines changed

src/main/scala/io/iohk/ethereum/rlp/RLPImplicitDerivations.scala

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ object RLPImplicitDerivations {
4646
rlp match {
4747
case list: RLPList =>
4848
decodeList(list.items.toList)._1
49-
case other =>
50-
throw RLPException(s"Expected to decode an RLPList", other)
49+
case _ =>
50+
throw RLPException(s"Expected to decode an RLPList", rlp)
5151
}
5252
}
5353
object RLPListDecoder {
@@ -57,6 +57,21 @@ object RLPImplicitDerivations {
5757
}
5858
}
5959

60+
private def decodeError[T](subject: String, error: String, maybeEncodeable: Option[RLPEncodeable] = None): T =
61+
throw RLPException(s"error decoding $subject: $error", maybeEncodeable)
62+
63+
private def tryDecode[T](subject: => String, encodeable: RLPEncodeable)(f: RLPEncodeable => T): T = {
64+
try {
65+
f(encodeable)
66+
} catch {
67+
case ex: RLPException =>
68+
// Preserve the original encodeable if there is one.
69+
decodeError(subject, ex.message, ex.encodeable orElse Some(encodeable))
70+
case NonFatal(ex) =>
71+
decodeError(subject, ex.getMessage, Some(encodeable))
72+
}
73+
}
74+
6075
/** Encoder for the empty list of fields. */
6176
implicit val deriveHNilRLPListEncoder: RLPListEncoder[HNil] =
6277
RLPListEncoder(_ => RLPList() -> Nil)
@@ -148,6 +163,7 @@ object RLPImplicitDerivations {
148163
policy: DerivationPolicy = DerivationPolicy.default
149164
): RLPListDecoder[FieldType[K, H] :: T] = {
150165
val fieldName: String = witness.value.name
166+
val subject = s"optional field '$fieldName'"
151167
val hInfo = FieldInfo(isOptional = true)
152168

153169
RLPListDecoder {
@@ -158,16 +174,16 @@ object RLPImplicitDerivations {
158174
(head :: tail) -> (hInfo :: tInfos)
159175

160176
case Nil =>
161-
throw RLPException(s"Could not decode optional field '$fieldName': RLPList is empty.")
177+
decodeError(subject, "RLPList is empty.")
162178

163179
case rlps =>
164180
val (tail, tInfos) = tDecoder.value.decodeList(rlps.tail)
165181
val value: H =
166-
try {
182+
tryDecode(subject, rlps.head) { rlp =>
167183
if (policy.omitTrailingOptionals && tInfos.forall(_.isOptional)) {
168184
// Expect that it's a value. We have a decoder for optional fields, so we have to wrap it into a list.
169185
try {
170-
hDecoder.value.decode(RLPList(rlps.head))
186+
hDecoder.value.decode(RLPList(rlp))
171187
} catch {
172188
case NonFatal(_) =>
173189
// The trailing fields can be followed in the RLP list by additional items
@@ -176,11 +192,8 @@ object RLPImplicitDerivations {
176192
}
177193
} else {
178194
// Expect that it's a list of 0 or 1 items.
179-
hDecoder.value.decode(rlps.head)
195+
hDecoder.value.decode(rlp)
180196
}
181-
} catch {
182-
case NonFatal(ex) =>
183-
throw RLPException(s"Could not decode optional field '$fieldName': ${ex.getMessage}", rlps.head)
184197
}
185198

186199
val head: FieldType[K, H] = field[K](value)
@@ -196,19 +209,17 @@ object RLPImplicitDerivations {
196209
ev: H <:!< Option[_]
197210
): RLPListDecoder[FieldType[K, H] :: T] = {
198211
val fieldName: String = witness.value.name
212+
val subject = s"field '$fieldName'"
199213
val hInfo = FieldInfo(isOptional = false)
200214

201215
RLPListDecoder {
202216
case Nil =>
203-
throw RLPException(s"Could not decode field '$fieldName': RLPList is empty.")
217+
decodeError(subject, "RLPList is empty.")
204218

205219
case rlps =>
206220
val value: H =
207-
try {
208-
hDecoder.value.decode(rlps.head)
209-
} catch {
210-
case NonFatal(ex) =>
211-
throw RLPException(s"Could not decode field '$fieldName': ${ex.getMessage}", rlps.head)
221+
tryDecode(subject, rlps.head) {
222+
hDecoder.value.decode(_)
212223
}
213224
val head: FieldType[K, H] = field[K](value)
214225
val (tail, tInfos) = tDecoder.value.decodeList(rlps.tail)
@@ -224,11 +235,8 @@ object RLPImplicitDerivations {
224235
recDecoder: Lazy[RLPDecoder[Rec]],
225236
ct: ClassTag[T]
226237
): RLPDecoder[T] = RLPDecoder { rlp =>
227-
try {
238+
tryDecode(s"type ${ct.runtimeClass.getSimpleName}", rlp) { rlp =>
228239
generic.from(recDecoder.value.decode(rlp))
229-
} catch {
230-
case NonFatal(ex) =>
231-
throw RLPException(s"Could not decode type ${ct.runtimeClass.getSimpleName}: ${ex.getMessage}", rlp)
232240
}
233241
}
234242

0 commit comments

Comments
 (0)