Beispiel #1
0
        }; //TODO


        public static bool Execute(out Types.Transaction transaction, ContractArgs contractArgs, bool isWitness)
        {
            try
            {
                var fileName     = HttpServerUtility.UrlTokenEncode(contractArgs.ContractHash);
                var contractCode = File.ReadAllText(Path.Combine(_OutputPath, Path.ChangeExtension(fileName, ".fs")));
                var func         = ContractExamples.Execution.compileQuotedContract(contractCode);

                var result = func.Invoke(new Tuple <byte[], byte[], FSharpFunc <Types.Outpoint, FSharpOption <Types.Output> > >(
                                             contractArgs.Message,
                                             contractArgs.ContractHash,
                                             FSharpFunc <Types.Outpoint, FSharpOption <Types.Output> > .FromConverter(t => contractArgs.tryFindUTXOFunc(t))));

                var txSkeleton = result as Tuple <FSharpList <Types.Outpoint>, FSharpList <Types.Output>, byte[]>;

                transaction = txSkeleton == null || txSkeleton.Item2.Count() == 0 ? null :
                              new Types.Transaction(
                    Tests.tx.version,
                    txSkeleton.Item1,
                    ListModule.OfSeq <byte[]>(isWitness ? new byte[][] { contractArgs.Message } : new byte[][] { }),
                    txSkeleton.Item2,
                    FSharpOption <Types.ExtendedContract> .None                           //TODO: get from txSkeleton.Item3
                    );

                return(true);
            }
            catch (Exception e)
            {
                BlockChainTrace.Error("Error executing contract", e);
            }

            transaction = null;

            return(false);
        }
Beispiel #2
0
        public static IsContractGeneratedTxResult IsContractGeneratedTx(TransactionValidation.PointedTransaction ptx, out byte[] contractHash)
        {
            contractHash = null;

            foreach (var input in ptx.pInputs)
            {
                if ([email protected])
                {
                    if (contractHash == null)
                    {
                        contractHash = ((Types.OutputLock.ContractLock)input.Item2.@lock).contractHash;
                    }
                    else if (!contractHash.SequenceEqual(((Types.OutputLock.ContractLock)input.Item2.@lock).contractHash))
                    {
                        return(IsContractGeneratedTxResult.Invalid);
                    }

                    else if (!contractHash.SequenceEqual(((Types.OutputLock.ContractLock)input.Item2.@lock).contractHash))
                    {
                        BlockChainTrace.Information("Unexpected contactHash", contractHash);
                        return(IsContractGeneratedTxResult.Invalid);
                    }
                }
            }

            return(contractHash == null ? IsContractGeneratedTxResult.NotContractGenerated : IsContractGeneratedTxResult.ContractGenerated);
        }
Beispiel #3
0
        public void ShouldEvictWithDependencies()
        {
            var key = Key.Create();
            var tx  = Utils
                      .GetTx().AddOutput(Key.Create().Address, Consensus.Tests.zhash, 100)
                      .Sign(key.Private).Tag("tx");
            var tx1 = Utils.GetTx().AddInput(tx, 0).AddOutput(Key.Create().Address, Consensus.Tests.zhash, 1).Sign(key.Private).Tag("tx1");
            var tx2 = Utils.GetTx().AddInput(tx, 0).AddOutput(Key.Create().Address, Consensus.Tests.zhash, 2).Sign(key.Private).Tag("tx2");

            var contractHash = new byte[] { };

            BlockChainTrace.SetTag(contractHash, "mock contract");
            _BlockChain.memPool.ContractPool.AddRef(tx1.Key(), new ACSItem()
            {
                Hash = contractHash
            });
            HandleBlock(_GenesisBlock.AddTx(tx).Tag("genesis"));
            Assert.That(TxState(tx), Is.EqualTo(TxStateEnum.Confirmed));
            HandleBlock(_GenesisBlock.Child().AddTx(tx1).Tag("main"));
            Assert.That(TxState(tx1), Is.EqualTo(TxStateEnum.Confirmed));
            var branch = _GenesisBlock.Child().Tag("branch");

            HandleBlock(branch.Child().Tag("branch orphan"));
            HandleBlock(branch.AddTx(tx2).Tag("branch child"));


            System.Threading.Thread.Sleep(1000);


            Assert.That(TxState(tx2), Is.EqualTo(TxStateEnum.Confirmed));
            Assert.That(TxState(tx1), Is.EqualTo(TxStateEnum.Invalid));
            Assert.That(_BlockChain.memPool.TxPool.ContainsKey(tx1.Key()), Is.False);
        }
Beispiel #4
0
        // remove
        bool IsTransactionValid(Types.Transaction tx, byte[] txHash, out TransactionValidation.PointedTransaction ptx)
        {
            if (_BlockChain.BlockStore.TxStore.ContainsKey(_DbTx, txHash) && _BlockChain.BlockStore.TxStore.Get(_DbTx, txHash).Value.InMainChain)
            {
                BlockChainTrace.Information("Tx already in store", txHash);
                ptx = null;
                return(false);
            }

            switch (_BlockChain.IsOrphanTx(_DbTx, tx, true, out ptx))
            {
            case BlockChain.IsTxOrphanResult.Orphan:
                BlockChainTrace.Information("tx invalid - orphan", tx);
                return(false);

            case BlockChain.IsTxOrphanResult.Invalid:
                BlockChainTrace.Information("tx invalid - reference(s)", tx);
                return(false);
            }

            if (_BlockChain.IsDoubleSpend(_DbTx, tx, true))
            {
                return(false);
            }

            //TODO: coinbase validation + check that witness has blocknumber

            if (!BlockChain.IsValidUserGeneratedTx(_DbTx, ptx))
            {
                BlockChainTrace.Information("tx invalid - structural", ptx);
                return(false);
            }

            byte[] contractHash;
            switch (BlockChain.IsContractGeneratedTx(ptx, out contractHash))
            {
            case BlockChain.IsContractGeneratedTxResult.ContractGenerated:
                if (!_BlockChain.ActiveContractSet.IsActive(_DbTx, contractHash))
                {
                    BlockChainTrace.Information("tx invalid - contract not active", tx);
                    return(false);
                }
                var contractFunction = _BlockChain.ActiveContractSet.GetContractFunction(_DbTx, contractHash);

                if (!BlockChain.IsValidAutoTx(ptx, UtxoLookup, contractHash, contractFunction))
                {
                    BlockChainTrace.Information("auto-tx invalid", ptx);
                    return(false);
                }
                break;

            case BlockChain.IsContractGeneratedTxResult.Invalid:
                BlockChainTrace.Information("tx invalid - input locks", tx);
                return(false);
            }

            return(true);
        }
Beispiel #5
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 #6
0
        public ContractFunction GetContractFunction(TransactionContext dbTx, byte[] contractHash)
        {
            var acsItem = Get(dbTx, contractHash);

            if (acsItem == null)
            {
                return(null);
            }

            var deserialization = FSharpOption <Tuple <ContractFunction, ContractCostFunction> > .None;

            try
            {
                deserialization = ContractExamples.FStarExecution.deserialize(acsItem.Value.Serialized);
            }
            catch
            {
                BlockChainTrace.Information("Error deserializing contract");
            }

            if (FSharpOption <Tuple <ContractFunction, ContractCostFunction> > .get_IsNone(deserialization) || deserialization == null)
            {
                BlockChainTrace.Information("Reserializing contract");

                try
                {
                    var compilation = ContractExamples.FStarExecution.compile(acsItem.Value.Extracted);

                    if (FSharpOption <byte[]> .get_IsNone(compilation))
                    {
                        return(null);
                    }

                    acsItem.Value.Serialized = compilation.Value;

                    Add(dbTx, acsItem.Value);

                    deserialization = ContractExamples.FStarExecution.deserialize(compilation.Value);

                    if (FSharpOption <Tuple <ContractFunction, ContractCostFunction> > .get_IsNone(deserialization))
                    {
                        BlockChainTrace.Error("Error deserializing contract");
                        return(null);
                    }
                }
                catch (Exception e)
                {
                    BlockChainTrace.Error("Error recompiling contract", e);
                    return(null);
                }
            }

            return(deserialization.Value.Item1);
        }
Beispiel #7
0
        // Note: when contract uses blokchain state as context, need to pass it in.
        public static bool ExecuteContract(
            byte[] contractHash,
            ContractFunction contractFunction,
            byte[] message,
            out Types.Transaction transaction,
            UtxoLookup UtxoLookup,
            bool isWitness)
        {
            var contractFunctionInput = new ContractFunctionInput(
                message,
                contractHash,
                UtxoLookup
                );
            TransactionSkeleton transactionSkeleton = null;

            transaction = null;

            try
            {
                var serializer = new ContractExamples.FStarCompatibility.DataSerializer(Consensus.Serialization.context);
                Consensus.Serialization.context.Serializers.RegisterOverride(serializer);

                var result = contractFunction.Invoke(contractFunctionInput);

                if (result.IsError)
                {
                    BlockChainTrace.Information("Contract resulted in error: " + result.ErrorValue);
                    return(false);
                }

                transactionSkeleton = result.ResultValue;
            }
            catch (Exception e)
            {
                BlockChainTrace.Error("Error executing contract", e);
                return(false);
            }

            if (transactionSkeleton == null)
            {
                return(false);
            }

            transaction = new Types.Transaction(
                Tests.tx.version,
                transactionSkeleton.Item1,
                ListModule.OfSeq(isWitness ? new byte[][] { message } : new byte[][] { }),
                transactionSkeleton.Item2,
                FSharpOption <Types.ExtendedContract> .None //TODO: get from txSkeleton.Item3
                );

            return(true);
        }
Beispiel #8
0
        bool IsValidTimeStamp()
        {
            //TODO: assert block's timestamp isn't too far in the future
            var result = _Bk.header.timestamp >= _BlockChain.Timestamps.Median();

            if (!result)
            {
                BlockChainTrace.Information($"block {_Bk.header.blockNumber} has invalid timestamp", _BkHash);
            }

            return(result);
        }
Beispiel #9
0
        bool IsValidBlockNumber()
        {
            var parentBlock = GetBlock(_Bk.header.parent).Value;

#if TRACE
            if (parentBlock.header.blockNumber >= _Bk.header.blockNumber)
            {
                BlockChainTrace.Information($"block {_Bk.header.blockNumber}: expecting block-number greater than {parentBlock.header.blockNumber}, found {_Bk.header.blockNumber}", _BkHash);
            }
#endif
            return(parentBlock.header.blockNumber < _Bk.header.blockNumber);
        }
Beispiel #10
0
        public static bool Compile_old(String fsharpCode, out byte[] contractHash)
        {
            var tempSourceFile = Path.ChangeExtension(Path.GetTempFileName(), ".fs");
            var process        = new Process();

            contractHash = GetHash(fsharpCode);

            File.WriteAllText(tempSourceFile, fsharpCode);

            if (!Directory.Exists(_OutputPath))
            {
                Directory.CreateDirectory(_OutputPath);
            }

            if (IsRunningOnMono())
            {
                process.StartInfo.FileName  = "fsharpc";
                process.StartInfo.Arguments = $"-o { GetFileName(contractHash) } -a {tempSourceFile}{DEPENCENCY_OPTION + string.Join(DEPENCENCY_OPTION, _Dependencies)}";
            }
            else
            {
                //TODO
            }

            process.OutputDataReceived += (sender, args1) =>
            {
                Console.WriteLine("## " + args1.Data);
            };

            process.StartInfo.UseShellExecute        = false;
            process.StartInfo.RedirectStandardOutput = true;

            process.OutputDataReceived += (sender, args1) =>
            {
                BlockChainTrace.Information(args1.Data);
            };

            try
            {
                process.Start();
                process.BeginOutputReadLine();
                process.WaitForExit();
            }
            catch (Exception e)
            {
                BlockChainTrace.Error("process", e);
            }

            File.Delete(tempSourceFile);

            return(process.ExitCode == 0);
        }
Beispiel #11
0
        public static bool IsValidAutoTx(TransactionValidation.PointedTransaction ptx, UtxoLookup UtxoLookup, byte[] contractHash, ContractFunction contractFunction)
        {
            var isWitness  = false;
            var witnessIdx = -1;

            byte[] message = null;

            for (var i = 0; i < ptx.witnesses.Length; i++)
            {
                if (ptx.witnesses[i].Length > 0)
                {
                    witnessIdx = i;
                }
            }

            if (witnessIdx == 0)
            {
                message = ptx.witnesses[0];
            }
            else if (witnessIdx == -1)
            {
                var contractLock = ptx.pInputs[0].Item2.@lock as Types.OutputLock.ContractLock;

                if (contractLock == null)
                {
                    BlockChainTrace.Information("expected ContractLock, tx invalid");
                    return(false);
                }

                message = contractLock.data;
            }

            isWitness = witnessIdx == 0;

            Types.Transaction tx;

            var isExecutionSuccessful = ExecuteContract(
                contractHash,
                contractFunction,
                message,
                out tx,
                UtxoLookup,
                isWitness
                );

            return(isExecutionSuccessful && tx != null && TransactionValidation.unpoint(ptx).Equals(tx));
        }
Beispiel #12
0
        public bool TryActivate(TransactionContext dbTx, string contractCode, ulong kalapas, byte[] contractHash, uint blockNumber)
        {
            if (IsActive(dbTx, contractHash))
            {
                return(false);
            }

            //TODO: module name
            var extration = ContractExamples.FStarExecution.extract(contractCode);

            if (FSharpOption <string> .get_IsNone(extration))
            {
                BlockChainTrace.Information("Could not extract contract");
                return(false);
            }

            var compilation = ContractExamples.FStarExecution.compile(extration.Value);

            if (FSharpOption <byte[]> .get_IsNone(compilation))
            {
                BlockChainTrace.Information("Could not complie contract");
                return(false);
            }

            var kalapasPerBlock = KalapasPerBlock(contractCode);

            if (kalapas < kalapasPerBlock)
            {
                return(false);
            }

            var blocks = Convert.ToUInt32(kalapas / kalapasPerBlock);

            Add(dbTx, new ACSItem()
            {
                Hash            = contractHash,
                KalapasPerBlock = kalapasPerBlock,
                LastBlock       = blockNumber + blocks,
                Extracted       = extration.Value,
                Serialized      = compilation.Value
            });

            BlockChainTrace.Information($"Contract activated for {blocks} blocks", contractHash);

            return(true);
        }
Beispiel #13
0
        void Reorg()
        {
            var originalTip = _BlockChain.Tip;

            Keyed <Types.Block> fork = null;
            var newMainChain         = GetNewMainChainStartFromForkToLeaf(new Keyed <Types.Block>(_BkHash, _Bk), out fork);

            _BlockChain.ChainTip.Context(_DbTx).Value = fork.Key;
            _BlockChain.Tip = fork;
            _BlockChain.InitBlockTimestamps(_DbTx);

            var oldMainChain = GetOldMainChainStartFromLeafToFork(fork, originalTip.Key);

            foreach (var block in oldMainChain)
            {
                UndoBlock(block.Value, block.Key);
            }

            //append new chain
            foreach (var _bk in newMainChain)
            {
                var action = new BlockVerificationHelper(
                    _BlockChain,
                    _DbTx,
                    _bk.Key,
                    _bk.Value,
                    false,
                    true,
                    ConfirmedTxs,
                    UnconfirmedTxs,
                    QueueActions);

                BlockChainTrace.Information($"new main chain bk {_bk.Value.header.blockNumber} {action.Result.BkResultEnum}", _bk.Value);

                if (action.Result.BkResultEnum == BkResultEnum.Rejected)
                {
                    _BlockChain.ChainTip.Context(_DbTx).Value = originalTip.Key;
                    _BlockChain.Tip = originalTip;
                    _BlockChain.InitBlockTimestamps(_DbTx);

                    BlockChainTrace.Information("reorganization undo", _bk.Value);
                    Result = new BkResult(BkResultEnum.Rejected);
                    return;
                }
            }
        }
Beispiel #14
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 #15
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 #16
0
        //TODO: should asset that the block came from main?
        Types.Block GetBlock(byte[] key)
        {
            using (TransactionContext context = _DBContext.GetTransactionContext())
            {
                var location = BlockStore.GetLocation(context, key);

                if (location == LocationEnum.Main)
                {
                    try
                    {
                        var bk = BlockStore.GetBlock(context, key);
                        return(bk == null ? null : bk.Value);
                    } catch (Exception e)
                    {
                        BlockChainTrace.Error("GetBlock", e);
                        return(null);
                    }
                }

                return(null);
            }
        }
Beispiel #17
0
        public static bool Compile(String csharpCode, out byte[] contractHash)
        {
            var provider   = new CSharpCodeProvider();
            var parameters = new CompilerParameters();

            foreach (var dependency in _Dependencies)
            {
                parameters.ReferencedAssemblies.Add(dependency);
            }

            if (!Directory.Exists(_OutputPath))
            {
                Directory.CreateDirectory(_OutputPath);
            }
            contractHash = GetHash(csharpCode);

            parameters.GenerateInMemory   = false;
            parameters.GenerateExecutable = false;
            parameters.OutputAssembly     = GetFileName(contractHash);
            var results = provider.CompileAssemblyFromSource(parameters, csharpCode);

            if (results.Errors.HasErrors)
            {
                StringBuilder sb = new StringBuilder();

                foreach (CompilerError error in results.Errors)
                {
                    sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
                }

                BlockChainTrace.Error(sb.ToString(), new Exception());
                //throw new InvalidOperationException(sb.ToString());

                return(false);
            }

            return(true);
        }
Beispiel #18
0
        public void ShouldRemoveConfirmedFromMempoolWithDependencies()
        {
            var key = Key.Create();
            var tx  = Utils
                      .GetTx().AddOutput(Key.Create().Address, Consensus.Tests.zhash, 100)
                      .Sign(key.Private).Tag("tx");
            var mempoolTx = Utils.GetTx().AddInput(tx, 0).AddOutput(Key.Create().Address, Consensus.Tests.zhash, 1).Sign(key.Private)
                            .Tag("mempoolTx");

            var contractHash = new byte[] { };

            BlockChainTrace.SetTag(contractHash, "mock contract");
            HandleBlock(_GenesisBlock.AddTx(tx).Tag("genesis"));
            HandleTransaction(mempoolTx);
            _BlockChain.memPool.ContractPool.AddRef(mempoolTx.Key(), new ACSItem()
            {
                Hash = contractHash
            });
            Assert.That(_BlockChain.memPool.TxPool.Count, Is.EqualTo(1));
            Assert.That(_BlockChain.memPool.ContractPool.Count, Is.EqualTo(1));
            HandleBlock(_GenesisBlock.Child().AddTx(mempoolTx).Tag("genesis"));
            Assert.That(_BlockChain.memPool.TxPool.Count, Is.EqualTo(0));
            Assert.That(_BlockChain.memPool.ContractPool.Count, Is.EqualTo(0));
        }
Beispiel #19
0
        public static bool Execute_old(out Types.Transaction transaction, ContractArgs contractArgs, bool isWitness)
        {
            try
            {
                var assembly = Assembly.LoadFrom(GetFileName(contractArgs.ContractHash));
                var module   = assembly.GetModules()[0];
                var type     = module.GetTypes()[0];

                //**************************************************
                // used for CSharp based contract debugging
                var matchedTypes = Assembly.GetEntryAssembly()
                                   .GetModules()[0]
                                   .GetTypes()
                                   .Where(t => t.FullName == type.FullName);

                if (matchedTypes.Any())
                {
                    type = matchedTypes.First();
                }

                //**************************************************
                // used for FSharp based contract debugging
                //var matchedTypes = Assembly.LoadFile("TestFSharpContracts.dll")
                //    .GetModules()[0]
                //    .GetTypes()
                //    .Where(t => t.FullName == type.FullName);

                //if (matchedTypes.Any())
                //{
                //    type = matchedTypes.First();
                //}

                var method = type.GetMethod("main");
                var args   = new object[] {
#if CSHARP_CONTRACTS
                    new List <byte>(contractArgs.Message),
                    contractArgs.ContractHash,
                    contractArgs.tryFindUTXOFunc,
#else
                    contractArgs.Message,
                    contractArgs.ContractHash,
                    FSharpFunc <Types.Outpoint, FSharpOption <Types.Output> > .FromConverter(t => contractArgs.tryFindUTXOFunc(t))
#endif
                };

                var result = method.Invoke(null, args);

#if CSHARP_CONTRACTS
                var txSkeleton = result as Tuple <IEnumerable <Types.Outpoint>, IEnumerable <Types.Output>, byte[]>;
#else
                var txSkeleton = result as Tuple <FSharpList <Types.Outpoint>, FSharpList <Types.Output>, byte[]>;
#endif

                transaction = txSkeleton == null || txSkeleton.Item2.Count() == 0 ? null :
                              new Types.Transaction(
                    Tests.tx.version,
#if CSHARP_CONTRACTS
                    ListModule.OfSeq(txSkeleton.Item1),
#else
                    txSkeleton.Item1,
#endif
                    ListModule.OfSeq <byte[]>(isWitness ? new byte[][] { contractArgs.Message } : new byte[][] { }),
#if CSHARP_CONTRACTS
                    ListModule.OfSeq(txSkeleton.Item2),
#else
                    txSkeleton.Item2,
#endif
                    FSharpOption <Types.ExtendedContract> .None                           //TODO: get from txSkeleton.Item3
                    );

                return(true);
            }
            catch (Exception e)
            {
                BlockChainTrace.Error("Error executing contract", e);
            }

            transaction = null;

            return(false);
        }
Beispiel #20
0
        public BlockVerificationHelper(
            BlockChain blockChain,
            TransactionContext dbTx,
            byte[] bkHash,
            Types.Block bk,
            bool handleOrphan = false,
            bool handleBranch = false,
            HashDictionary <TransactionValidation.PointedTransaction> confirmedTxs = null,
            HashDictionary <Types.Transaction> invalidatedTxs = null,
            List <QueueAction> queuedActions = null
            )
        {
            ConfirmedTxs   = confirmedTxs ?? new HashDictionary <TransactionValidation.PointedTransaction>();
            UnconfirmedTxs = invalidatedTxs ?? new HashDictionary <Types.Transaction>();            //todo: refactor to set as new obj by default
            QueueActions   = queuedActions ?? new List <QueueAction>();

            _BlockChain = blockChain;
            _DbTx       = dbTx;
            _BkHash     = bkHash;
            _Bk         = bk;

            if (!IsValid())
            {
                BlockChainTrace.Information($"block {_Bk.header.blockNumber} is invalid", _Bk);
                Result = new BkResult(BkResultEnum.Rejected);
                return;
            }

            if (IsInStore())
            {
                var    reject        = false;
                byte[] missingParent = null;
                var    location      = blockChain.BlockStore.GetLocation(dbTx, bkHash);

                switch (location)
                {
                case LocationEnum.Branch:
                    reject = !handleBranch;
                    break;

                case LocationEnum.Orphans:
                    missingParent = GetMissingParent();

                    reject = !handleOrphan && !handleBranch;
                    break;

                default:
                    reject = true;
                    break;
                }

                if (reject)
                {
                    BlockChainTrace.Information($"Block {_Bk.header.blockNumber} already in store ({location})", bk);
                    Result = new BkResult(BkResultEnum.Rejected, missingParent);
                    return;
                }
            }

            if (bk.transactions.Count() == 0)
            {
                BlockChainTrace.Information("empty tx list", bk);
                Result = new BkResult(BkResultEnum.Rejected);
                return;
            }

            if (!IsValidTime())
            {
                BlockChainTrace.Information("invalid time", bk);
                Result = new BkResult(BkResultEnum.Rejected);
                return;
            }

            //TODO:

            /*
             * 3. Transaction list must be non - empty
             * 4. Block hash must satisfy claimed nBits proof of work
             * 5. Block timestamp must not be more than two hours in the future
             * 6. First transaction must be coinbase, the rest must not be
             * 7. For each transaction, apply "tx" checks 2 - 4
             * 8. (omitted)
             * 9. (omitted)
             * 10. Verify Merkle hash
             */

            if (IsGenesis())
            {
                if (!IsGenesisValid())
                {
                    BlockChainTrace.Information("invalid genesis block", bk);
                    Result = new BkResult(BkResultEnum.Rejected);
                    return;
                }
                else
                {
                    blockChain.Timestamps.Init(bk.header.timestamp);
                    ExtendMain(QueueActions, 0, true);
                    Result = new BkResult(BkResultEnum.Accepted);
                    BlockChainTrace.Information("accepted genesis block", bk);
                    return;
                }
            }

            if (IsOrphan())
            {
                var missingParent = GetMissingParent();
                blockChain.BlockStore.Put(dbTx, bkHash, bk, LocationEnum.Orphans, 0);
                BlockChainTrace.Information($"block {_Bk.header.blockNumber} added as orphan", bk);
                Result = new BkResult(BkResultEnum.AcceptedOrphan, missingParent);
                return;
            }

            //12. Check that nBits value matches the difficulty rules

            if (!IsValidDifficulty() || !IsValidBlockNumber() || !IsValidTimeStamp())
            {
                BlockChainTrace.Information($"block {_Bk.header.blockNumber} rejected", bk);
                Result = new BkResult(BkResultEnum.Rejected);
                return;
            }

            //14. For certain old blocks(i.e.on initial block download) check that hash matches known values

            var totalWork = TotalWork();

            UtxoLookup = _BlockChain.UtxoLookupFactory(_DbTx, true);


            if (handleBranch)             // make a branch block main
            {
                if (!ExtendMain(QueueActions, totalWork))
                {
                    Result = new BkResult(BkResultEnum.Rejected);
                    return;
                }
            }
            else if (!IsNewGreatestWork(totalWork))
            {
                blockChain.BlockStore.Put(dbTx, bkHash, bk, LocationEnum.Branch, totalWork);
            }
            else if (blockChain.BlockStore.IsLocation(dbTx, bk.header.parent, LocationEnum.Main))
            {
                if (!ExtendMain(QueueActions, totalWork))
                {
                    BlockChainTrace.Information($"block {_Bk.header.blockNumber} rejected", bk);
                    Result = new BkResult(BkResultEnum.Rejected);
                    return;
                }
            }
            else
            {
                BlockChainTrace.Information($"block {bk.header.blockNumber} extends a branch with new difficulty", bk);

                Reorg();
            }

            BlockChainTrace.Information($"block {bk.header.blockNumber} accepted", bk);
            Result = new BkResult(BkResultEnum.Accepted);
        }
Beispiel #21
0
 public static Types.Block Tag(this Types.Block block, string value)
 {
     BlockChainTrace.SetTag(block, value);
     return(block);
 }
 public static Types.Transaction Tag(this Types.Transaction tx, string value)
 {
     BlockChainTrace.SetTag(tx, value);
     return(tx);
 }
Beispiel #23
0
        bool ExtendMain(List <QueueAction> queuedActions, double totalWork, bool isGenesis = false)
        {
            if (_BlockChain.BlockStore.ContainsKey(_DbTx, _BkHash))
            {
                _BlockChain.BlockStore.SetLocation(_DbTx, _BkHash, LocationEnum.Main);
            }
            else
            {
                _BlockChain.BlockStore.Put(_DbTx, _BkHash, _Bk, LocationEnum.Main, totalWork);
            }

            _BlockChain.Timestamps.Push(_Bk.header.timestamp);

            if (_Bk.header.blockNumber % 2000 == 0)
            {
                _BlockChain.BlockNumberDifficulties.Add(_DbTx.Transaction, _Bk.header.blockNumber, _BkHash);
            }

            var blockUndoData = new BlockUndoData();

            var confirmedTxs = new HashDictionary <TransactionValidation.PointedTransaction>();

            //TODO: lock with mempool
            for (var txIdx = 0; txIdx < _Bk.transactions.Count(); txIdx++)
            {
                var tx     = _Bk.transactions[txIdx];
                var txHash = Merkle.transactionHasher.Invoke(tx);
                TransactionValidation.PointedTransaction ptx;

                if (!isGenesis)
                {
                    if ((txIdx == 0 && !IsCoinbaseTxValid(tx)) || (txIdx > 0 && IsCoinbaseTxValid(tx)))
                    {
                        if (txIdx == 0)
                        {
                            BlockChainTrace.Information("Invalid coinbase tx");
                        }
                        else
                        {
                            BlockChainTrace.Information($"Invalid tx ({txIdx})");
                        }

                        return(false);
                    }

                    if (!IsTransactionValid(tx, txHash, out ptx))
                    {
                        return(false);
                    }

                    confirmedTxs[txHash] = ptx;

                    foreach (var pInput in ptx.pInputs)
                    {
                        _BlockChain.UTXOStore.Remove(_DbTx, pInput.Item1);
                        BlockChainTrace.Information($"utxo spent, amount {pInput.Item2.spend.amount}", ptx);
                        //BlockChainTrace.Information($" of", pInput.Item1.txHash);
                        blockUndoData.RemovedUTXO.Add(new Tuple <Types.Outpoint, Types.Output>(pInput.Item1, pInput.Item2));
                    }
                }
                else
                {
                    ptx = TransactionValidation.toPointedTransaction(
                        tx,
                        ListModule.Empty <Types.Output>()
                        );
                }

                _BlockChain.BlockStore.TxStore.Put(_DbTx, txHash, tx, true);

                var contractExtendSacrifices = new HashDictionary <ulong>();
                var activationSacrifice      = 0UL;

                for (var outputIdx = 0; outputIdx < tx.outputs.Count(); outputIdx++)
                {
                    var output = tx.outputs[outputIdx];

                    if ([email protected])
                    {
                        if (!output.spend.asset.SequenceEqual(Tests.zhash))
                        {
                            continue;                             // not Zen
                        }
                        var contractSacrificeLock = (Types.OutputLock.ContractSacrificeLock)output.@lock;

                        if (contractSacrificeLock.IsHighVLock)
                        {
                            continue;                             // not current version
                        }
                        if (contractSacrificeLock.Item.lockData.Length > 0 && contractSacrificeLock.Item.lockData[0] != null && contractSacrificeLock.Item.lockData[0].Length > 0)
                        {
                            var contractKey = contractSacrificeLock.Item.lockData[0];                             // output-lock-level indicated contract

                            contractExtendSacrifices[contractKey] =
                                (contractExtendSacrifices.ContainsKey(contractKey) ? contractExtendSacrifices[contractKey] : 0) +
                                output.spend.amount;
                        }
                        else if (contractSacrificeLock.Item.lockData.Length == 0)
                        {
                            activationSacrifice += output.spend.amount;
                        }
                    }

                    //todo: fix  to exclude CSLocks&FLocks, instead of including by locktype
                    if ([email protected] || [email protected])
                    {
                        BlockChainTrace.Information($"new utxo, amount {output.spend.amount}", tx);
                        var outpoint = new Types.Outpoint(txHash, (uint)outputIdx);
                        _BlockChain.UTXOStore.Put(_DbTx, outpoint, output);
                        blockUndoData.AddedUTXO.Add(new Tuple <Types.Outpoint, Types.Output>(outpoint, output));
                    }
                }

                if (FSharpOption <Types.ExtendedContract> .get_IsSome(tx.contract) && !tx.contract.Value.IsHighVContract)
                {
                    var codeBytes    = ((Types.ExtendedContract.Contract)tx.contract.Value).Item.code;
                    var contractHash = Merkle.innerHash(codeBytes);
                    var contractCode = System.Text.Encoding.ASCII.GetString(codeBytes);

                    if (_BlockChain.ActiveContractSet.TryActivate(_DbTx, contractCode, activationSacrifice, contractHash, _Bk.header.blockNumber))
                    {
                        blockUndoData.ACSDeltas.Add(contractHash, new ACSUndoData());
                        ContractsTxsStore.Add(_DbTx.Transaction, contractHash, txHash);
                    }
                }

                foreach (var item in contractExtendSacrifices)
                {
                    var currentACSItem = _BlockChain.ActiveContractSet.Get(_DbTx, item.Key);

                    if (currentACSItem.Value != null)
                    {
                        if (_BlockChain.ActiveContractSet.TryExtend(_DbTx, item.Key, item.Value))
                        {
                            if (!blockUndoData.ACSDeltas.ContainsKey(item.Key))
                            {
                                blockUndoData.ACSDeltas.Add(item.Key, new ACSUndoData()
                                {
                                    LastBlock = currentACSItem.Value.LastBlock
                                });
                            }
                        }
                    }
                }
            }

            var expiringContracts = _BlockChain.ActiveContractSet.GetExpiringList(_DbTx, _Bk.header.blockNumber);

            foreach (var acsItem in expiringContracts)
            {
                if (!blockUndoData.ACSDeltas.ContainsKey(acsItem.Key))
                {
                    blockUndoData.ACSDeltas.Add(acsItem.Key, new ACSUndoData()
                    {
                        ACSItem = acsItem.Value
                    });
                }
            }

            if (!isGenesis)
            {
                _BlockChain.BlockStore.SetUndoData(_DbTx, _BkHash, blockUndoData);
            }

            _BlockChain.ActiveContractSet.DeactivateContracts(_DbTx, expiringContracts.Select(t => t.Key));

            ValidateACS();

            _BlockChain.ChainTip.Context(_DbTx).Value = _BkHash;
            //TODO: only update after commit
            _BlockChain.Tip = new Keyed <Types.Block>(_BkHash, _Bk);

            queuedActions.Add(new MessageAction(new BlockMessage(confirmedTxs, _Bk.header.blockNumber)));

            foreach (var item in confirmedTxs)
            {
                ConfirmedTxs[item.Key] = item.Value;
                UnconfirmedTxs.Remove(item.Key);
            }

            return(true);
        }
Beispiel #24
0
        //void HandleQueueAction(QueueAction action)
        async Task ConsumeAsync(ISourceBlock <QueueAction> source)
        {
            while (await source.OutputAvailableAsync())
            {
                var action = source.Receive();

                try
                {
                    //((dynamic)this).Handle((dynamic)action);

                    if (action is HandleBlockAction)
                    {
                        ((HandleBlockAction)action).SetResult(HandleBlock(action as HandleBlockAction));
                    }
                    else if (action is GetActiveContractsAction)
                    {
                        ((GetActiveContractsAction)action).SetResult(GetActiveContracts());
                    }
                    else if (action is GetContractPointedOutputsAction)
                    {
                        ((GetContractPointedOutputsAction)action).SetResult(GetContractPointedOutputs(
                                                                                ((GetContractPointedOutputsAction)action).ContractHash));
                    }
                    else if (action is HandleOrphansOfTxAction)
                    {
                        HandleOrphansOfTransaction(action as HandleOrphansOfTxAction);
                    }
                    else if (action is GetIsContractActiveAction)
                    {
                        ((GetIsContractActiveAction)action).SetResult(IsContractActive(
                                                                          ((GetIsContractActiveAction)action).ContractHash));
                    }
                    //else if (action is GetUTXOAction)
                    //((GetUTXOAction)action).SetResult(GetUTXO(((GetUTXOAction)action).Outpoint, ((GetUTXOAction)action).IsInBlock));
                    else if (action is GetIsConfirmedUTXOExistAction)
                    {
                        var outpoint = ((GetIsConfirmedUTXOExistAction)action).Outpoint;
                        ((GetIsConfirmedUTXOExistAction)action).SetResult(IsConfirmedUTXOExist(outpoint));
                    }
                    else if (action is GetContractCodeAction)
                    {
                        ((GetContractCodeAction)action).SetResult(GetContractCode(
                                                                      ((GetContractCodeAction)action).ContractHash));
                    }
                    else if (action is HandleTransactionAction)
                    {
                        ((HandleTransactionAction)action).SetResult(HandleTransaction(((HandleTransactionAction)action).Tx, ((HandleTransactionAction)action).CheckInDb));
                    }
                    else if (action is GetBlockAction)
                    {
                        ((GetBlockAction)action).SetResult(GetBlock(((GetBlockAction)action).BkHash));
                    }
                    else if (action is GetTxAction)
                    {
                        ((GetTxAction)action).SetResult(GetTransaction(((GetTxAction)action).TxHash));
                    }
                    else if (action is ExecuteContractAction)
                    {
                        var executeContractAction = ((ExecuteContractAction)action);
                        Types.Transaction tx;
                        var result = AssembleAutoTx(executeContractAction.ContractHash, executeContractAction.Message, out tx, executeContractAction.Message != null);
                        ((ExecuteContractAction)action).SetResult(new Tuple <bool, Types.Transaction>(result, tx));
                    }

                    //TODO: remove
                    else if (action is GetUTXOSetAction)
                    {
                        var getUTXOSetAction = (GetUTXOSetAction)action;
                        HashDictionary <List <Types.Output> > txOutputs;
                        HashDictionary <Types.Transaction>    txs;
                        GetUTXOSet(getUTXOSetAction.Predicate, out txOutputs, out txs);
                        getUTXOSetAction.SetResult(new Tuple <HashDictionary <List <Types.Output> >, HashDictionary <Types.Transaction> >(txOutputs, txs));
                    }
                    //TODO: rename
                    else if (action is GetUTXOSetAction2)
                    {
                        using (var dbTx = _DBContext.GetTransactionContext())
                        {
                            ((GetUTXOSetAction2)action).SetResult(UTXOStore.All(dbTx).ToList());
                        }
                    }
#if TEST
                    else if (action is GetBlockLocationAction)
                    {
                        using (var dbTx = _DBContext.GetTransactionContext())
                        {
                            ((GetBlockLocationAction)action).SetResult(BlockStore.GetLocation(dbTx, ((GetBlockLocationAction)action).Block));
                        }
                    }
#endif
                }
                catch (Exception e)
                {
#if DEBUG
                    BlockChainTrace.Error("Blockchain request handle got an exception.\n\nOriginal caller's stack:\n\n" + action.StackTrace + "\n\nException:\n\n", e);
#else
                    BlockChainTrace.Error("Blockchain request exception", e);
#endif
                }
            }
        }
Beispiel #25
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);
            }
        }
Beispiel #26
0
        public HashDictionary <ACSItem> GetExpiringList(TransactionContext dbTx, uint blockNumber)
        {
#if TRACE
            All(dbTx).Where(t => t.Item2.LastBlock == blockNumber).ToList().ForEach(t => BlockChainTrace.Information($"contract due to expire at {blockNumber}", t.Item1));
#endif

            var values = new HashDictionary <ACSItem>();

            foreach (var contract in All(dbTx).Where(t => t.Item2.LastBlock <= blockNumber))
            {
                values[contract.Item1] = contract.Item2;
            }

            return(values);
        }