Ejemplo n.º 1
0
        public void TestWireDecodeTransaction()
        {
            var actual      = DataDecoder.DecodeTransaction(null, TRANSACTION_1_BYTES.ToArray());
            var actualBytes = DataEncoder.EncodeTransaction(actual).TxBytes;

            CollectionAssert.AreEqual(TRANSACTION_1_BYTES.ToList(), actualBytes.ToList());
        }
Ejemplo n.º 2
0
        public async Task SendTransaction(Transaction transaction)
        {
            await Task.Yield();

            var sendTxMessage = Messaging.ConstructMessage("tx", DataEncoder.EncodeTransaction(transaction));

            await SendMessageAsync(sendTxMessage);
        }
Ejemplo n.º 3
0
        public byte[] TxSignature(ImmutableArray <byte> scriptPubKey, Transaction tx, int inputIndex, byte hashType)
        {
            ///TODO
            Debug.Assert(inputIndex < tx.Inputs.Length);

            // Blank out other inputs' signatures
            var empty     = ImmutableArray.Create <byte>();
            var newInputs = ImmutableArray.CreateBuilder <TxInput>(tx.Inputs.Length);

            for (var i = 0; i < tx.Inputs.Length; i++)
            {
                var oldInput = tx.Inputs[i];
                var newInput = oldInput.With(scriptSignature: i == inputIndex ? scriptPubKey : empty);
                newInputs.Add(newInput);
            }

            //// Blank out some of the outputs
            //if ((hashType & 0x1F) == (int)ScriptHashType.SIGHASH_NONE)
            //{
            //    //TODO
            //    Debug.Assert(false);

            //    // Wildcard payee

            //    // Let the others update at will
            //}
            //else if ((hashType & 0x1F) == (int)ScriptHashType.SIGHASH_SINGLE)
            //{
            //    //TODO
            //    Debug.Assert(false);

            //    // Only lock-in the txout payee at same index as txin

            //    // Let the others update at will
            //}

            //// Blank out other inputs completely, not recommended for open transactions
            //if ((hashType & 0x80) == (int)ScriptHashType.SIGHASH_ANYONECANPAY)
            //{
            //    //TODO
            //    Debug.Assert(false);
            //}

            // create simplified transaction
            var newTx = tx.With(Inputs: newInputs.ToImmutable());

            // return wire-encoded simplified transaction with the 4-byte hashType tacked onto the end
            using (var stream = new MemoryStream())
                using (var writer = new BinaryWriter(stream))
                {
                    writer.WriteBytes(DataEncoder.EncodeTransaction(newTx));
                    writer.WriteUInt32(hashType);

                    return(stream.ToArray());
                }
        }
Ejemplo n.º 4
0
        public static DecodedBlockTx Create(int txIndex, Transaction tx)
        {
            if (tx == null)
            {
                throw new ArgumentNullException(nameof(tx));
            }

            var decodedTx = DataEncoder.EncodeTransaction(tx);

            return(new DecodedBlockTx(txIndex, decodedTx));
        }
Ejemplo n.º 5
0
        public bool TryAddBlockTransactions(UInt256 blockHash, IEnumerable <Transaction> blockTxes)
        {
            if (this.ContainsBlock(blockHash))
            {
                return(false);
            }

            try
            {
                using (var handle = this.cursorCache.TakeItem())
                {
                    var cursor = handle.Item;

                    using (var jetTx = cursor.jetSession.BeginTransaction())
                    {
                        int blockId;
                        using (var jetUpdate = cursor.jetSession.BeginUpdate(cursor.blockIdsTableId, JET_prep.Insert))
                        {
                            blockId = Api.RetrieveColumnAsInt32(cursor.jetSession, cursor.blockIdsTableId, cursor.blockIdsIdColumnId, RetrieveColumnGrbit.RetrieveCopy).Value;
                            Api.SetColumn(cursor.jetSession, cursor.blockIdsTableId, cursor.blockIdsHashColumnId, DbEncoder.EncodeUInt256(blockHash));

                            jetUpdate.Save();
                        }

                        var txIndex = 0;
                        foreach (var tx in blockTxes)
                        {
                            AddTransaction(blockId, txIndex, tx.Hash, DataEncoder.EncodeTransaction(tx), cursor);
                            txIndex++;
                        }

                        // increase block count
                        Api.EscrowUpdate(cursor.jetSession, cursor.globalsTableId, cursor.blockCountColumnId, +1);

                        jetTx.CommitLazy();
                        return(true);
                    }
                }
            }
            catch (EsentKeyDuplicateException)
            {
                return(false);
            }
        }
Ejemplo n.º 6
0
 public TransactionStorage(string baseDirectory)
     : base(baseDirectory, "Transactions",
            tx => DataEncoder.EncodeTransaction(tx),
            (txHash, bytes) => DataEncoder.DecodeTransaction(bytes, txHash))
 {
 }
Ejemplo n.º 7
0
        public void TestWireDecodeTransaction()
        {
            var actual = DataEncoder.EncodeTransaction(DataEncoder.DecodeTransaction(TRANSACTION_1_BYTES.ToArray()));

            CollectionAssert.AreEqual(TRANSACTION_1_BYTES.ToList(), actual.ToList());
        }
Ejemplo n.º 8
0
 public static DecodedTx Create(UInt32 version, ImmutableArray <TxInput> inputs, ImmutableArray <TxOutput> outputs, UInt32 lockTime)
 {
     return(DataEncoder.EncodeTransaction(version, inputs, outputs, lockTime));
 }
Ejemplo n.º 9
0
        public void TallyTransaction(Chain newChain, ValidatableTx validatableTx, ref object runningTally)
        {
            var chainedHeader = newChain.LastBlock;

            if (runningTally == null)
            {
                var medianPrevHeaderTime = GetMedianPrevHeaderTime(newChain, chainedHeader.Height);

                var lockTimeFlags  = 0; // TODO why is this used here?
                var lockTimeCutoff = ((lockTimeFlags & LOCKTIME_MEDIAN_TIME_PAST) != 0)
                                      ? GetMedianPrevHeaderTime(newChain, chainedHeader.Height).ToUnixTimeSeconds()
                                      : chainedHeader.Time.ToUnixTimeSeconds();

                runningTally = new BlockTally {
                    BlockSize = 80, LockTimeCutoff = lockTimeCutoff
                };
            }

            var blockTally = (BlockTally)runningTally;

            var tx      = validatableTx.Transaction;
            var txIndex = validatableTx.Index;

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

            // first transaction must be coinbase
            if (validatableTx.Index == 0 && !tx.IsCoinbase)
            {
                throw new ValidationException(chainedHeader.Hash);
            }
            // all other transactions must not be coinbase
            else if (validatableTx.Index > 0 && tx.IsCoinbase)
            {
                throw new ValidationException(chainedHeader.Hash);
            }
            // must have inputs
            else if (tx.Inputs.Length == 0)
            {
                throw new ValidationException(chainedHeader.Hash);
            }
            // must have outputs
            else if (tx.Outputs.Length == 0)
            {
                throw new ValidationException(chainedHeader.Hash);
            }
            // coinbase scriptSignature length must be >= 2 && <= 100
            else if (tx.IsCoinbase && (tx.Inputs[0].ScriptSignature.Length < 2 || tx.Inputs[0].ScriptSignature.Length > 100))
            {
                throw new ValidationException(chainedHeader.Hash);
            }
            // all transactions must be finalized
            else if (!IsFinal(tx, chainedHeader.Height, blockTally.LockTimeCutoff))
            {
                throw new ValidationException(chainedHeader.Hash);
            }

            // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
            // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet):
            if (tx.IsCoinbase &&
                chainedHeader.Version >= 2 &&
                IsSuperMajority(2, newChain, ChainParams.MajorityEnforceBlockUpgrade))
            {
                var requiredScript = GetPushInt64Script(chainedHeader.Height);
                var actualScript   = tx.Inputs[0].ScriptSignature;

                if (actualScript.Length < requiredScript.Length ||
                    !actualScript.Take(requiredScript.Length).SequenceEqual(requiredScript))
                {
                    throw new ValidationException(chainedHeader.Hash);
                }
            }

            // running input/output value tallies
            var txTotalInputValue  = 0UL;
            var txTotalOutputValue = 0UL;
            var txSigOpCount       = 0;

            // validate & tally inputs
            for (var inputIndex = 0; inputIndex < tx.Inputs.Length; inputIndex++)
            {
                var input = tx.Inputs[inputIndex];

                if (!tx.IsCoinbase)
                {
                    var prevOutput = validatableTx.PrevTxOutputs[inputIndex];

                    // if spending a coinbase, it must be mature
                    if (prevOutput.IsCoinbase &&
                        chainedHeader.Height - prevOutput.BlockHeight < COINBASE_MATURITY)
                    {
                        throw new ValidationException(chainedHeader.Hash);
                    }

                    // non-coinbase txes must not have coinbase prev tx output key (txHash: 0, outputIndex: -1)
                    if (input.PrevTxOutputKey.TxOutputIndex == uint.MaxValue && input.PrevTxOutputKey.TxHash == UInt256.Zero)
                    {
                        throw new ValidationException(chainedHeader.Hash);
                    }

                    // tally
                    txTotalInputValue += prevOutput.Value;
                }

                // tally
                txSigOpCount += CountLegacySigOps(input.ScriptSignature, accurate: false);
                if (!tx.IsCoinbase && strictPayToScriptHash)
                {
                    txSigOpCount += CountP2SHSigOps(validatableTx, inputIndex);
                }
            }

            // validate & tally outputs
            for (var outputIndex = 0; outputIndex < tx.Outputs.Length; outputIndex++)
            {
                var output = tx.Outputs[outputIndex];

                // must not have any negative money value outputs
                if (unchecked ((long)output.Value) < 0)
                {
                    throw new ValidationException(chainedHeader.Hash);
                }
                // must not have any outputs with a value greater than max money
                else if (output.Value > MAX_MONEY)
                {
                    throw new ValidationException(chainedHeader.Hash);
                }

                // tally
                if (!tx.IsCoinbase)
                {
                    txTotalOutputValue += output.Value;
                }
                txSigOpCount += CountLegacySigOps(output.ScriptPublicKey, accurate: false);
            }

            // must not have a total output value greater than max money
            if (txTotalOutputValue > MAX_MONEY)
            {
                throw new ValidationException(chainedHeader.Hash);
            }

            // validate non-coinbase fees
            long txFeeValue;

            if (!validatableTx.IsCoinbase)
            {
                // ensure that output amount isn't greater than input amount
                if (txTotalOutputValue > txTotalInputValue)
                {
                    throw new ValidationException(chainedHeader.Hash, $"Failing tx {tx.Hash}: Transaction output value is greater than input value");
                }

                // calculate fee value (unspent amount)
                txFeeValue = (long)txTotalInputValue - (long)txTotalOutputValue;
                Debug.Assert(txFeeValue >= 0);
            }
            else
            {
                txFeeValue = 0;
            }


            // block tallies
            if (validatableTx.IsCoinbase)
            {
                blockTally.CoinbaseTx = validatableTx;
            }
            blockTally.TxCount++;
            blockTally.TotalFees       += txFeeValue;
            blockTally.TotalSigOpCount += txSigOpCount;
            // re-encode transaction for block size calculation so it is optimal length
            blockTally.BlockSize +=
                DataEncoder.EncodeTransaction(validatableTx.Transaction).TxBytes.Length;

            //TODO
            if (blockTally.TotalSigOpCount > MAX_BLOCK_SIGOPS)
            {
                throw new ValidationException(chainedHeader.Hash);
            }
            //TODO
            else if (blockTally.BlockSize + DataEncoder.VarIntSize((uint)blockTally.TxCount) > MAX_BLOCK_SIZE)
            {
                throw new ValidationException(chainedHeader.Hash);
            }

            // all validation has passed
        }
Ejemplo n.º 10
0
        public void TestWireEncodeTransaction()
        {
            var actual = DataEncoder.EncodeTransaction(TRANSACTION_1).TxBytes;

            CollectionAssert.AreEqual(TRANSACTION_1_BYTES.ToList(), actual.ToList());
        }