public TransactionPolicyError[] Check(Transaction transaction, ICoin[] spentCoins)
		{
			spentCoins = spentCoins ?? new ICoin[0];
			List<TransactionPolicyError> errors = new List<TransactionPolicyError>();

			if(transaction.Version > Transaction.CURRENT_VERSION || transaction.Version < 1)
			{
				errors.Add(new TransactionPolicyError("Invalid transaction version, expected " + Transaction.CURRENT_VERSION));
			}

			var dups = transaction.Inputs.AsIndexedInputs().GroupBy(i => i.PrevOut);
			foreach(var dup in dups)
			{
				var duplicates = dup.ToArray();
				if(duplicates.Length != 1)
					errors.Add(new DuplicateInputPolicyError(duplicates));
			}

			foreach(var input in transaction.Inputs.AsIndexedInputs())
			{
				var coin = spentCoins.FirstOrDefault(s => s.Outpoint == input.PrevOut);
				if(coin == null)
				{
					errors.Add(new CoinNotFoundPolicyError(input));
				}
			}

			var fees = transaction.GetFee(spentCoins);
			if(fees != null)
			{
				if(fees < Money.Zero)
					errors.Add(new NotEnoughFundsPolicyError("Not enough funds in this transaction", -fees));
			}

			return errors.ToArray();
		}
		public TransactionPolicyError[] Check(Transaction transaction, ICoin[] spentCoins)
		{
			if(transaction == null)
				throw new ArgumentNullException("transaction");

			spentCoins = spentCoins ?? new ICoin[0];

			List<TransactionPolicyError> errors = new List<TransactionPolicyError>();



			foreach(var input in transaction.Inputs.AsIndexedInputs())
			{
				var coin = spentCoins.FirstOrDefault(s => s.Outpoint == input.PrevOut);
				if(coin != null)
				{
					if(ScriptVerify != null)
					{
						ScriptError error;
						if(!VerifyScript(input, coin.TxOut.ScriptPubKey, ScriptVerify.Value, out error))
						{
							errors.Add(new ScriptPolicyError(input, error, ScriptVerify.Value, coin.TxOut.ScriptPubKey));
						}
					}
				}

				var txin = input.TxIn;
				if(txin.ScriptSig.Length > MaxScriptSigLength)
				{
					errors.Add(new InputPolicyError("Max scriptSig length exceeded actual is " + txin.ScriptSig.Length + ", max is " + MaxScriptSigLength, input));
				}
				if(!txin.ScriptSig.IsPushOnly)
				{
					errors.Add(new InputPolicyError("All operation should be push", input));
				}
				if(!txin.ScriptSig.HasCanonicalPushes)
				{
					errors.Add(new InputPolicyError("All operation should be canonical push", input));
				}
			}

			foreach(var txout in transaction.Outputs.AsCoins())
			{
				var template = StandardScripts.GetTemplateFromScriptPubKey(txout.ScriptPubKey);
				if(template == null)
					errors.Add(new OutputPolicyError("Non-Standard scriptPubKey", (int)txout.Outpoint.N));
			}
			int txSize = transaction.GetSerializedSize();
			if(MaxTransactionSize != null)
			{
				if(txSize >= MaxTransactionSize.Value)
					errors.Add(new TransactionSizePolicyError(txSize, MaxTransactionSize.Value));
			}

			var fees = transaction.GetFee(spentCoins);
			if(fees != null)
			{
				if(CheckFee)
				{
					if(MaxTxFee != null)
					{
						var max = MaxTxFee.GetFee(txSize);
						if(fees > max)
							errors.Add(new FeeTooHighPolicyError(fees, max));
					}

					if(MinRelayTxFee != null)
					{
						if(MinRelayTxFee != null)
						{
							var min = MinRelayTxFee.GetFee(txSize);
							if(fees < min)
								errors.Add(new FeeTooLowPolicyError(fees, min));
						}
					}
				}
			}
			if(MinRelayTxFee != null)
			{
				foreach(var output in transaction.Outputs)
				{
					var bytes = output.ScriptPubKey.ToBytes(true);
					if(output.IsDust(MinRelayTxFee) && !IsOpReturn(bytes))
						errors.Add(new DustPolicyError(output.Value, output.GetDustThreshold(MinRelayTxFee)));
				}
			}
			var opReturnCount = transaction.Outputs.Select(o => o.ScriptPubKey.ToBytes(true)).Count(b => IsOpReturn(b));
			if(opReturnCount > 1)
				errors.Add(new TransactionPolicyError("More than one op return detected"));
			return errors.ToArray();
		}