private void CachePrevOut(PrevTxOutput prevTxOutput)
        {
            var cacheEntryOptions = new MemoryCacheEntryOptions()
                                    .SetSize(1)
                                    .SetSlidingExpiration(TimeSpan.FromMinutes(30));

            prevTxOutputCache.Cache.Set <PrevTxOutput>($"{HelperTools.ByteToHexString(prevTxOutput.TxExternalId)}_{prevTxOutput.N}", prevTxOutput, cacheEntryOptions);
        }
示例#2
0
 public static byte[] EncodePrevTxOutput(PrevTxOutput txOutput)
 {
     using (var stream = new MemoryStream())
         using (var writer = new BinaryWriter(stream))
         {
             EncodePrevTxOutput(writer, txOutput);
             return(stream.ToArray());
         }
 }
示例#3
0
 public static void EncodePrevTxOutput(BinaryWriter writer, PrevTxOutput txOutput)
 {
     writer.WriteUInt64(txOutput.Value);
     writer.WriteVarBytes(txOutput.ScriptPublicKey.ToArray());
     writer.WriteInt32(txOutput.BlockHeight);
     writer.WriteInt32(txOutput.TxIndex);
     writer.WriteUInt32(txOutput.TxVersion);
     writer.WriteBool(txOutput.IsCoinbase);
 }
示例#4
0
        public bool TryAddTransaction(DecodedTx decodedTx)
        {
            if (ContainsTransaction(decodedTx.Hash))
            {
                // unconfirmed tx already exists
                return(false);
            }

            var           tx = decodedTx.Transaction;
            UnconfirmedTx unconfirmedTx;

            // allow concurrent transaction adds if underlying storage supports it
            // in either case, lock waits for block add/rollback to finish
            if (storageManager.IsUnconfirmedTxesConcurrent)
            {
                updateLock.EnterReadLock();
            }
            else
            {
                updateLock.EnterWriteLock();
            }
            try
            {
                using (var chainState = coreDaemon.GetChainState())
                {
                    // verify each input is available to spend
                    var prevTxOutputKeys = new HashSet <TxOutputKey>();
                    var prevTxOutputs    = ImmutableArray.CreateBuilder <PrevTxOutput>(tx.Inputs.Length);
                    var inputValue       = 0UL;
                    for (var inputIndex = 0; inputIndex < tx.Inputs.Length; inputIndex++)
                    {
                        var input = tx.Inputs[inputIndex];

                        if (!prevTxOutputKeys.Add(input.PrevTxOutputKey))
                        {
                            // tx double spends one of its own inputs
                            return(false);
                        }

                        UnspentTx unspentTx;
                        if (!chainState.TryGetUnspentTx(input.PrevTxHash, out unspentTx))
                        {
                            // input's prev output does not exist
                            return(false);
                        }

                        if (input.PrevTxOutputIndex >= unspentTx.OutputStates.Length)
                        {
                            // input's prev output does not exist
                            return(false);
                        }

                        if (unspentTx.OutputStates[(int)input.PrevTxOutputIndex] != OutputState.Unspent)
                        {
                            // input's prev output has already been spent
                            return(false);
                        }

                        TxOutput txOutput;
                        if (!chainState.TryGetUnspentTxOutput(input.PrevTxOutputKey, out txOutput))
                        {
                            // input's prev output does not exist
                            return(false);
                        }

                        var prevTxOutput = new PrevTxOutput(txOutput, unspentTx);
                        prevTxOutputs.Add(prevTxOutput);
                        checked { inputValue += prevTxOutput.Value; }
                    }

                    var outputValue = 0UL;
                    for (var outputIndex = 0; outputIndex < tx.Outputs.Length; outputIndex++)
                    {
                        var output = tx.Outputs[outputIndex];
                        checked { outputValue += output.Value; }
                    }

                    if (outputValue > inputValue)
                    {
                        // transaction spends more than its inputs
                        return(false);
                    }

                    // validation passed

                    // create the unconfirmed tx
                    var blockTx       = new DecodedBlockTx(-1, decodedTx);
                    var validatableTx = new ValidatableTx(blockTx, null, prevTxOutputs.ToImmutable());
                    unconfirmedTx = new UnconfirmedTx(validatableTx, DateTimeOffset.Now);

                    // add the unconfirmed tx
                    using (var handle = storageManager.OpenUnconfirmedTxesCursor())
                    {
                        var unconfirmedTxesCursor = handle.Item;

                        unconfirmedTxesCursor.BeginTransaction();
                        if (unconfirmedTxesCursor.TryAddTransaction(unconfirmedTx))
                        {
                            unconfirmedTxesCursor.CommitTransaction();
                        }
                        else
                        {
                            // unconfirmed tx already exists
                            return(false);
                        }
                    }
                }
            }
            finally
            {
                if (storageManager.IsUnconfirmedTxesConcurrent)
                {
                    updateLock.ExitReadLock();
                }
                else
                {
                    updateLock.ExitWriteLock();
                }
            }

            UnconfirmedTxAdded?.Invoke(this, new UnconfirmedTxAddedEventArgs(unconfirmedTx));
            return(true);
        }
示例#5
0
        public void ValidationTransactionScript(Chain newChain, BlockTx tx, TxInput txInput, int txInputIndex, PrevTxOutput prevTxOutput)
        {
            var chainedHeader = newChain.LastBlock;

            // BIP16 didn't become active until Apr 1 2012
            var nBIP16SwitchTime      = DateTimeOffset.FromUnixTimeSeconds(1333238400U);
            var strictPayToScriptHash = chainedHeader.Time >= nBIP16SwitchTime;

            var flags = strictPayToScriptHash ? verify_flags_type.verify_flags_p2sh : verify_flags_type.verify_flags_none;

            // Start enforcing the DERSIG (BIP66) rules, for block.nVersion=3 blocks,
            // when 75% of the network has upgraded:
            if (chainedHeader.Version >= 3 &&
                IsSuperMajority(3, newChain, ChainParams.MajorityEnforceBlockUpgrade))
            {
                flags |= verify_flags_type.verify_flags_dersig;
            }

            // Start enforcing CHECKLOCKTIMEVERIFY, (BIP65) for block.nVersion=4
            // blocks, when 75% of the network has upgraded:
            if (chainedHeader.Version >= 4 &&
                IsSuperMajority(4, newChain, ChainParams.MajorityEnforceBlockUpgrade))
            {
                flags |= verify_flags_type.verify_flags_checklocktimeverify;
            }

            var result = LibbitcoinConsensus.VerifyScript(
                tx.TxBytes,
                prevTxOutput.ScriptPublicKey,
                txInputIndex,
                flags);

            if (!result)
            {
                logger.Debug($"Script did not pass in block: {chainedHeader.Hash}, tx: {tx.Index}, {tx.Hash}, input: {txInputIndex}");
                throw new ValidationException(chainedHeader.Hash);
            }
        }
示例#6
0
 public void ValidationTransactionScript(Chain newChain, BlockTx tx, TxInput txInput, int txInputIndex, PrevTxOutput prevTxOutput)
 {
     if (ValidationTransactionScriptAction == null)
     {
         coreRules.ValidationTransactionScript(newChain, tx, txInput, txInputIndex, prevTxOutput);
     }
     else
     {
         ValidationTransactionScriptAction(newChain, tx, txInput, txInputIndex, prevTxOutput);
     }
 }