Example #1
0
        //Types.Output GetUTXO(Types.Outpoint outpoint, bool IsInBlock)
        //{
        //	using (TransactionContext dbTx = _DBContext.GetTransactionContext())
        //	{
        //		return GetUTXO(outpoint, dbTx, IsInBlock);
        //	}
        //}

        public UtxoLookup UtxoLookupFactory(TransactionContext dbTx, bool isInBlock, TransactionValidation.PointedTransaction ptx = null)
        {
            return(UtxoLookup.FromConverter(t =>
            {
                bool valid;
                var output = GetUTXO(t, dbTx, isInBlock, out valid, ptx);
                return output == null ? FSharpOption <Types.Output> .None : new FSharpOption <Types.Output>(output);
            }));
        }
Example #2
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);
        }
Example #3
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);
        }
Example #4
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));
        }
Example #5
0
        bool IsTransactionValid(TransactionValidation.PointedTransaction ptx)
        {
            if (!HasUtxos(ptx))
            {
                MinerTrace.Information("could not validate tx - utxo missing");
                return(false);
            }

            var utxoLookup = UtxoLookup.FromConverter(outpoint =>
            {
                var outputs = _UtxoSet.Where(t => t.Item1.Equals(outpoint)).Select(t => t.Item2);
                return(!outputs.Any() ? FSharpOption <Types.Output> .None : new FSharpOption <Types.Output>(outputs.First()));
            });

            var contractLookup = FSharpFunc <byte[], FSharpOption <ContractFunction> > .FromConverter(contractHash =>
            {
                if (!_ActiveContracts.Contains(contractHash))
                {
                    return(FSharpOption <ContractFunction> .None);
                }

                try
                {
                    var code = new GetContractCodeAction(contractHash).Publish().Result;

                    //TODO: module name
                    var extration = ContractExamples.FStarExecution.extract(System.Text.Encoding.ASCII.GetString(code));

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

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

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

                    return(ContractExamples.FStarExecution.deserialize(compilation.Value).Value.Item1);
                }
                catch (Exception e)
                {
                    MinerTrace.Error("Could not compile contract " + Convert.ToBase64String(contractHash), e);
                    return(null);
                }
            });

            if (!TransactionValidation.validateNonCoinbaseTx(
                    ptx,
                    utxoLookup,
                    contractLookup
                    ))
            {
                MinerTrace.Information("could not validate tx");
                return(false);
            }

            MinerTrace.Information("validated tx");

            //TODO: memory management issues. trying to explicitly collect DynamicMethods
            GC.Collect();
            GC.WaitForPendingFinalizers();

            return(true);
        }