Beispiel #1
0
 List <ACSItem> GetActiveContracts()
 {
     using (var dbTx = _DBContext.GetTransactionContext())
     {
         return(ActiveContractSet.All(dbTx).Select(t => t.Item2).ToList());
     }
 }
Beispiel #2
0
        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;
            });
        }
Beispiel #3
0
        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;
        }
Beispiel #4
0
        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();
                });
            }
        }
Beispiel #5
0
        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);
            }
        }
Beispiel #6
0
        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);
        }
Beispiel #7
0
        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);
                    }
                }
            }
        }
Beispiel #8
0
        /// <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);
            }
        }