List <ACSItem> GetActiveContracts() { using (var dbTx = _DBContext.GetTransactionContext()) { return(ActiveContractSet.All(dbTx).Select(t => t.Item2).ToList()); } }
void UndoBlock(Types.Block block, byte[] key) { BlockChainTrace.Information($"undoing block {block.header.blockNumber}", block); _BlockChain.BlockStore.SetLocation(_DbTx, key, LocationEnum.Branch); var blockUndoData = _BlockChain.BlockStore.GetUndoData(_DbTx, key); if (blockUndoData != null) { blockUndoData.AddedUTXO.ForEach(u => { BlockChainTrace.Information($"undo block {block.header.blockNumber}: utxo removed, amount {u.Item2.spend.amount}", block); _BlockChain.UTXOStore.Remove(_DbTx, u.Item1.txHash, u.Item1.index); }); blockUndoData.RemovedUTXO.ForEach(u => { BlockChainTrace.Information($"undo block {block.header.blockNumber}: new utxo, amount {u.Item2.spend.amount}", block); _BlockChain.UTXOStore.Put(_DbTx, u.Item1.txHash, u.Item1.index, u.Item2); }); foreach (var item in blockUndoData.ACSDeltas) { if (item.Value.LastBlock.HasValue) // restore last block - undo extend { var current = new ActiveContractSet().Get(_DbTx, item.Key); if (current != null) { current.Value.LastBlock = item.Value.LastBlock.Value; _BlockChain.ActiveContractSet.Add(_DbTx, current.Value); } else { BlockChainTrace.Error("missing ACS item!", new Exception()); } } else if (item.Value.ACSItem != null) // restore entire item - undo expire { _BlockChain.ActiveContractSet.Add(_DbTx, item.Value.ACSItem); } else // remove item - undo activate { _BlockChain.ActiveContractSet.Remove(_DbTx, item.Key); } } } block.transactions.ToList().ForEach(tx => { var txHash = Merkle.transactionHasher.Invoke(tx); UnconfirmedTxs[txHash] = tx; }); }
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; }
void UpdateMempool(TransactionContext dbTx, HashDictionary <TransactionValidation.PointedTransaction> confirmedTxs, HashDictionary <Types.Transaction> unconfirmedTxs) { lock (memPool) { dbTx.Commit(); var activeContracts = new HashSet(); foreach (var item in ActiveContractSet.All(dbTx)) { activeContracts.Add(item.Item1); } foreach (var item in memPool.ContractPool) { activeContracts.Add(item.Key); } RemoveConfirmedTxsFromMempool(confirmedTxs); MakeOrphan(dbTx); memPool.TxPool.MoveToICTxPool(activeContracts); RemoveInvalidAutoTxs(dbTx); foreach (var t in unconfirmedTxs) { new HandleTransactionAction { Tx = t.Value, CheckInDb = false }.Publish(); } memPool.ICTxPool.Where(t => { byte[] contractHash; IsContractGeneratedTx(t.Value, out contractHash); return(activeContracts.Contains(contractHash)); }) .ToList().ForEach(t => { memPool.ICTxPool.Remove(t.Key); new HandleTransactionAction { Tx = TransactionValidation.unpoint(t.Value), CheckInDb = false }.Publish(); }); } }
bool AssembleAutoTx(byte[] contractHash, byte[] message, out Types.Transaction transaction, bool isWitness) { using (TransactionContext dbTx = _DBContext.GetTransactionContext()) { var utxoLookup = UtxoLookupFactory(dbTx, false); var contractFunction = ActiveContractSet.GetContractFunction(dbTx, contractHash); if (contractFunction != null) { return(ExecuteContract(contractHash, contractFunction, message, out transaction, utxoLookup, isWitness)); } transaction = null; return(false); } }
public BlockChain(string dbName, byte[] genesisBlockHash) { memPool = new MemPool(); UTXOStore = new UTXOStore(); ActiveContractSet = new ActiveContractSet(); BlockStore = new BlockStore(); BlockNumberDifficulties = new BlockNumberDifficulties(); ChainTip = new ChainTip(); Timestamps = new BlockTimestamps(); GenesisBlockHash = genesisBlockHash; _DBContext = new DBContext(dbName); OwnResource(_DBContext); //var listener = new EventLoopMessageListener<QueueAction>(HandleQueueAction, "BlockChain listener"); //OwnResource(MessageProducer<QueueAction>.Instance.AddMessageListener(listener)); var buffer = new BufferBlock <QueueAction>(); QueueAction.Target = buffer; using (var dbTx = _DBContext.GetTransactionContext()) { var chainTip = ChainTip.Context(dbTx).Value; //TODO: check if makred as main? Tip = chainTip == null ? null : BlockStore.GetBlock(dbTx, chainTip); if (Tip != null) { BlockChainTrace.Information("Tip's block number is " + Tip.Value.header.blockNumber); //Try to validate orphans of tip, if any. this would be the case when a sync action was interrupted BlockStore.Orphans(dbTx, Tip.Key).ToList().ForEach(t => new HandleBlockAction(t.Key, t.Value, true).Publish()); } else { BlockChainTrace.Information("No tip."); } InitBlockTimestamps(dbTx); } var consumer = ConsumeAsync(buffer); }
void RemoveInvalidAutoTxs(TransactionContext dbTx) { foreach (var item in memPool.TxPool.ToList()) { var ptx = item.Value; byte[] contractHash; if (IsContractGeneratedTx(ptx, out contractHash) == IsContractGeneratedTxResult.ContractGenerated) { var utxoLookup = UtxoLookupFactory(dbTx, false, ptx); var contractFunction = ActiveContractSet.GetContractFunction(dbTx, contractHash); if (!IsValidAutoTx(ptx, utxoLookup, contractHash, contractFunction)) { BlockChainTrace.Information("invalid auto-tx removed from mempool", item.Value); memPool.TxPool.RemoveWithDependencies(item.Key); } } } }
/// <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); } }