bool IsContractActive(byte[] contractHash) { using (var dbTx = _DBContext.GetTransactionContext()) { return(ActiveContractSet.IsActive(dbTx, contractHash)); } //TODO: get number of blocks //var lastBlock = ActiveContractSet.LastBlock(dbTx, contractHash); //var currentHeight = Tip == null ? 0 : Tip.Value.header.blockNumber; //return nextBlocks > currentHeight - lastBlock; }
/// <summary> /// Handles a new transaction from network or wallet. /// </summary> TxResultEnum HandleTransaction(Types.Transaction tx, bool checkInDb = true) { using (var dbTx = _DBContext.GetTransactionContext()) { TransactionValidation.PointedTransaction ptx; var txHash = Merkle.transactionHasher.Invoke(tx); lock (memPool) { if (memPool.TxPool.Contains(txHash) || memPool.ICTxPool.Contains(txHash) || memPool.OrphanTxPool.Contains(txHash)) { BlockChainTrace.Information("Tx already in mempool", txHash); return(TxResultEnum.Known); } if (checkInDb && BlockStore.TxStore.ContainsKey(dbTx, txHash) && BlockStore.TxStore.Get(dbTx, txHash).Value.InMainChain) { BlockChainTrace.Information("Tx already in store", txHash); return(TxResultEnum.Known); } Action removeDeps = () => { memPool.ICTxPool.GetDependencies(txHash).ToList().ForEach(t => t.Item1.RemoveWithDependencies(t.Item2)); memPool.OrphanTxPool.GetDependencies(txHash).ToList().ForEach(t => t.Item1.RemoveWithDependencies(t.Item2)); }; if (IsDoubleSpend(dbTx, tx, false)) { new TxMessage(txHash, null, TxStateEnum.Invalid).Publish(); removeDeps(); return(TxResultEnum.DoubleSpend); } switch (IsOrphanTx(dbTx, tx, false, out ptx)) { case IsTxOrphanResult.Orphan: BlockChainTrace.Information("tx added as orphan", tx); memPool.OrphanTxPool.Add(txHash, tx); return(TxResultEnum.Orphan); case IsTxOrphanResult.Invalid: BlockChainTrace.Information("tx refers to an output that cannot exist", tx); removeDeps(); return(TxResultEnum.Invalid); } if (IsCoinbaseTx(ptx)) { BlockChainTrace.Information("tx is coinbase", tx); return(TxResultEnum.Invalid); } if (!IsReferencedCoinbaseTxsValid(dbTx, ptx)) { BlockChainTrace.Information("referenced coinbase immature", tx); return(TxResultEnum.Invalid); } //if (!IsStructurallyValidTx(dbTx, ptx)) //{ // BlockChainTrace.Information("tx invalid - structural", ptx); // return TxResultEnum.Invalid; //} byte[] contractHash; switch (IsContractGeneratedTx(ptx, out contractHash)) { case IsContractGeneratedTxResult.ContractGenerated: if (!ActiveContractSet.IsActive(dbTx, contractHash)) { BlockChainTrace.Information("tx added to ICTx mempool", tx); BlockChainTrace.Information(" of contract", contractHash); memPool.TxPool.ICTxPool.Add(txHash, ptx); return(TxResultEnum.InactiveContract); } var utxoLookup = UtxoLookupFactory(dbTx, false, ptx); var contractFunction = ActiveContractSet.GetContractFunction(dbTx, contractHash); if (!IsValidAutoTx(ptx, utxoLookup, contractHash, contractFunction)) { BlockChainTrace.Information("auto-tx invalid", ptx); removeDeps(); return(TxResultEnum.Invalid); } break; case IsContractGeneratedTxResult.Invalid: BlockChainTrace.Information("tx invalid - input locks", tx); return(TxResultEnum.Invalid); case IsContractGeneratedTxResult.NotContractGenerated: // assume user generated if (!IsValidUserGeneratedTx(dbTx, ptx)) { BlockChainTrace.Information("tx invalid - input locks", tx); removeDeps(); return(TxResultEnum.Invalid); } break; } BlockChainTrace.Information("tx added to mempool", ptx); memPool.TxPool.Add(txHash, ptx); new TxMessage(txHash, ptx, TxStateEnum.Unconfirmed).Publish(); new HandleOrphansOfTxAction(txHash).Publish(); } return(TxResultEnum.Accepted); } }