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
// Copyright 2018 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Error types for chain
use crate::core::core::{block, committed, transaction};
use crate::core::ser;
use crate::keychain;
use crate::util::secp;
use crate::util::secp::pedersen::Commitment;
use failure::{Backtrace, Context, Fail};
use grin_store as store;
use std::fmt::{self, Display};
use std::io;

/// Error definition
#[derive(Debug, Fail)]
pub struct Error {
	inner: Context<ErrorKind>,
}

/// Chain error definitions
#[derive(Clone, Eq, PartialEq, Debug, Fail)]
pub enum ErrorKind {
	/// The block doesn't fit anywhere in our chain
	#[fail(display = "Block is unfit: {}", _0)]
	Unfit(String),
	/// Special case of orphan blocks
	#[fail(display = "Orphan")]
	Orphan,
	/// Difficulty is too low either compared to ours or the block PoW hash
	#[fail(display = "Difficulty is too low compared to ours or the block PoW hash")]
	DifficultyTooLow,
	/// Addition of difficulties on all previous block is wrong
	#[fail(display = "Addition of difficulties on all previous blocks is wrong")]
	WrongTotalDifficulty,
	/// Block header edge_bits is lower than our min
	#[fail(display = "Cuckoo Size too small")]
	LowEdgebits,
	/// Scaling factor between primary and secondary PoW is invalid
	#[fail(display = "Wrong scaling factor")]
	InvalidScaling,
	/// The proof of work is invalid
	#[fail(display = "Invalid PoW")]
	InvalidPow,
	/// Peer abusively sending us an old block we already have
	#[fail(display = "Old Block")]
	OldBlock,
	/// The block doesn't sum correctly or a tx signature is invalid
	#[fail(display = "Invalid Block Proof")]
	InvalidBlockProof(block::Error),
	/// Block time is too old
	#[fail(display = "Invalid Block Time")]
	InvalidBlockTime,
	/// Block height is invalid (not previous + 1)
	#[fail(display = "Invalid Block Height")]
	InvalidBlockHeight,
	/// One of the root hashes in the block is invalid
	#[fail(display = "Invalid Root")]
	InvalidRoot,
	/// One of the MMR sizes in the block header is invalid
	#[fail(display = "Invalid MMR Size")]
	InvalidMMRSize,
	/// Error from underlying keychain impl
	#[fail(display = "Keychain Error")]
	Keychain(keychain::Error),
	/// Error from underlying secp lib
	#[fail(display = "Secp Lib Error")]
	Secp(secp::Error),
	/// One of the inputs in the block has already been spent
	#[fail(display = "Already Spent: {:?}", _0)]
	AlreadySpent(Commitment),
	/// An output with that commitment already exists (should be unique)
	#[fail(display = "Duplicate Commitment: {:?}", _0)]
	DuplicateCommitment(Commitment),
	/// Attempt to spend a coinbase output before it sufficiently matures.
	#[fail(display = "Attempt to spend immature coinbase")]
	ImmatureCoinbase,
	/// Error validating a Merkle proof (coinbase output)
	#[fail(display = "Error validating merkle proof")]
	MerkleProof,
	/// Output not found
	#[fail(display = "Output not found")]
	OutputNotFound,
	/// Rangeproof not found
	#[fail(display = "Rangeproof not found")]
	RangeproofNotFound,
	/// Tx kernel not found
	#[fail(display = "Tx kernel not found")]
	TxKernelNotFound,
	/// output spent
	#[fail(display = "Output is spent")]
	OutputSpent,
	/// Invalid block version, either a mistake or outdated software
	#[fail(display = "Invalid Block Version: {:?}", _0)]
	InvalidBlockVersion(block::HeaderVersion),
	/// We've been provided a bad txhashset
	#[fail(display = "Invalid TxHashSet: {}", _0)]
	InvalidTxHashSet(String),
	/// Internal issue when trying to save or load data from store
	#[fail(display = "Store Error: {}, reason: {}", _1, _0)]
	StoreErr(store::Error, String),
	/// Internal issue when trying to save or load data from append only files
	#[fail(display = "File Read Error: {}", _0)]
	FileReadErr(String),
	/// Error serializing or deserializing a type
	#[fail(display = "Serialization Error")]
	SerErr(ser::Error),
	/// Error with the txhashset
	#[fail(display = "TxHashSetErr: {}", _0)]
	TxHashSetErr(String),
	/// Tx not valid based on lock_height.
	#[fail(display = "Transaction Lock Height")]
	TxLockHeight,
	/// No chain exists and genesis block is required
	#[fail(display = "Genesis Block Required")]
	GenesisBlockRequired,
	/// Error from underlying tx handling
	#[fail(display = "Transaction Validation Error: {:?}", _0)]
	Transaction(transaction::Error),
	/// Anything else
	#[fail(display = "Other Error: {}", _0)]
	Other(String),
	/// Error from summing and verifying kernel sums via committed trait.
	#[fail(display = "Committed Trait: Error summing and verifying kernel sums")]
	Committed(committed::Error),
	/// We cannot process data once the Grin server has been stopped.
	#[fail(display = "Stopped (Grin Shutting Down)")]
	Stopped,
	/// Internal Roaring Bitmap error
	#[fail(display = "Roaring Bitmap error")]
	Bitmap,
}

impl Display for Error {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
		let cause = match self.cause() {
			Some(c) => format!("{}", c),
			None => String::from("Unknown"),
		};
		let backtrace = match self.backtrace() {
			Some(b) => format!("{}", b),
			None => String::from("Unknown"),
		};
		let output = format!(
			"{} \n Cause: {} \n Backtrace: {}",
			self.inner, cause, backtrace
		);
		Display::fmt(&output, f)
	}
}

impl Error {
	/// get kind
	pub fn kind(&self) -> ErrorKind {
		self.inner.get_context().clone()
	}
	/// get cause
	pub fn cause(&self) -> Option<&dyn Fail> {
		self.inner.cause()
	}
	/// get backtrace
	pub fn backtrace(&self) -> Option<&Backtrace> {
		self.inner.backtrace()
	}

	/// Whether the error is due to a block that was intrinsically wrong
	pub fn is_bad_data(&self) -> bool {
		// shorter to match on all the "not the block's fault" errors
		match self.kind() {
			ErrorKind::Unfit(_)
			| ErrorKind::Orphan
			| ErrorKind::StoreErr(_, _)
			| ErrorKind::SerErr(_)
			| ErrorKind::TxHashSetErr(_)
			| ErrorKind::GenesisBlockRequired
			| ErrorKind::Other(_) => false,
			_ => true,
		}
	}
}

impl From<ErrorKind> for Error {
	fn from(kind: ErrorKind) -> Error {
		Error {
			inner: Context::new(kind),
		}
	}
}

impl From<Context<ErrorKind>> for Error {
	fn from(inner: Context<ErrorKind>) -> Error {
		Error { inner: inner }
	}
}

impl From<block::Error> for Error {
	fn from(error: block::Error) -> Error {
		let ec = error.clone();
		Error {
			inner: error.context(ErrorKind::InvalidBlockProof(ec)),
		}
	}
}

impl From<store::Error> for Error {
	fn from(error: store::Error) -> Error {
		let ec = error.clone();
		Error {
			//inner: error.context();Context::new(ErrorKind::StoreErr(error.clone(),
			// format!("{:?}", error))),
			inner: error.context(ErrorKind::StoreErr(ec.clone(), format!("{:?}", ec))),
		}
	}
}

impl From<keychain::Error> for Error {
	fn from(error: keychain::Error) -> Error {
		Error {
			inner: Context::new(ErrorKind::Keychain(error)),
		}
	}
}

impl From<transaction::Error> for Error {
	fn from(error: transaction::Error) -> Error {
		Error {
			inner: Context::new(ErrorKind::Transaction(error)),
		}
	}
}

impl From<committed::Error> for Error {
	fn from(error: committed::Error) -> Error {
		Error {
			inner: Context::new(ErrorKind::Committed(error)),
		}
	}
}

impl From<io::Error> for Error {
	fn from(e: io::Error) -> Error {
		Error {
			inner: Context::new(ErrorKind::TxHashSetErr(e.to_string())),
		}
	}
}

impl From<secp::Error> for Error {
	fn from(e: secp::Error) -> Error {
		Error {
			inner: Context::new(ErrorKind::Secp(e)),
		}
	}
}