Beispiel #1
0
        private static MsgTx DecodeTransaction(byte[] rawTransaction)
        {
            var msgTx = new MsgTx();

            msgTx.Decode(rawTransaction);
            return(msgTx);
        }
Beispiel #2
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="transaction">The transaction that the script applies to.</param>
        /// <param name="script"></param>
        /// <param name="options"></param>
        public ScriptEngine(MsgTx transaction, int txIndex, Script script, ScriptOptions options)
        {
            if (transaction == null)
            {
                throw new ArgumentNullException(nameof(transaction));
            }
            if (txIndex < 0 || txIndex >= transaction.TxIn.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(txIndex));
            }
            if (script == null)
            {
                throw new ArgumentNullException(nameof(script));
            }
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            _transaction  = transaction;
            _txIndex      = txIndex;
            _script       = script;
            _opCodeLookup = new Dictionary <OpCode, Action <ParsedOpCode> >();

            Options     = options;
            MainStack   = new ScriptStack(Options.AssertScriptIntegerMinimalEncoding);
            AltStack    = new ScriptStack(Options.AssertScriptIntegerMinimalEncoding);
            BranchStack = new BranchStack();

            InitializeOpCodeDictionary();
        }
Beispiel #3
0
        public void OpCheckSig(ParsedOpCode op, MsgTx transaction)
        {
            try
            {
                var rawPublicKey = MainStack.Pop();
                var rawSignature = MainStack.Pop();

                if (rawSignature.Length < 1)
                {
                    MainStack.Push(false);
                    return;
                }

                var signature     = rawSignature.Take(rawSignature.Length - 1).ToArray();
                var signatureType = (SignatureHashType)rawSignature.Last();

                AssertSignatureHashType(signatureType);
                AssertSignatureEncoding(signature);
                AssertPublicKeyEncoding(rawPublicKey);

                var subScript = _script.GetOpCodesWithoutData(rawSignature);
                var hash      = CalculateSignatureHash(subScript, signatureType, (MsgTx)transaction.Clone(), _txIndex);

                var ecSignature      = new ECSignature(signature);
                var securityService  = new ECPublicSecurityService(rawPublicKey);
                var isValidSignature = securityService.VerifySignature(hash, ecSignature);

                MainStack.Push(isValidSignature);
            }
            catch (ScriptException)
            {
                MainStack.Push(false);
            }
        }
Beispiel #4
0
        /// <summary>
        /// Broadcasts a signed transaction to the Decred network
        /// </summary>
        /// <param name="operationId"></param>
        /// <param name="hexTransaction"></param>
        /// <returns></returns>
        /// <exception cref="TransactionBroadcastException"></exception>
        public async Task Broadcast(Guid operationId, string hexTransaction)
        {
            if (operationId == Guid.Empty)
            {
                throw new BusinessException(ErrorReason.BadRequest, "Operation id is invalid");
            }
            if (string.IsNullOrWhiteSpace(hexTransaction))
            {
                throw new BusinessException(ErrorReason.BadRequest, "SignedTransaction is invalid");
            }

            var txBytes = HexUtil.ToByteArray(hexTransaction);
            var msgTx   = new MsgTx();

            msgTx.Decode(txBytes);

            // If the operation exists in the cache, throw exception
            var cachedResult = await _broadcastTxRepo.GetAsync(operationId.ToString());

            if (cachedResult != null)
            {
                throw new BusinessException(ErrorReason.DuplicateRecord, "Operation already broadcast");
            }

            var txHash     = HexUtil.FromByteArray(msgTx.GetHash().Reverse().ToArray());
            var txWasMined = await _txRepo.GetTxInfoByHash(txHash, long.MaxValue) != null;

            if (txWasMined)
            {
                await SaveBroadcastedTransaction(new BroadcastedTransaction
                {
                    OperationId        = operationId,
                    Hash               = txHash,
                    EncodedTransaction = hexTransaction
                });

                throw new BusinessException(ErrorReason.DuplicateRecord, "Operation already broadcast");
            }

            // Submit the transaction to the network via dcrd
            var result = await _dcrdClient.SendRawTransactionAsync(hexTransaction);

            if (result.Error != null)
            {
                throw new TransactionBroadcastException($"[{result.Error.Code}] {result.Error.Message}");
            }

            await SaveBroadcastedTransaction(new BroadcastedTransaction
            {
                OperationId        = operationId,
                Hash               = txHash,
                EncodedTransaction = hexTransaction
            });
        }
Beispiel #5
0
        /// <summary>
        /// Calculates the hash of a transaction to be signed.
        /// </summary>
        /// <param name="transaction"></param>
        /// <returns></returns>
        private byte[] CalculateTxHash(MsgTx transaction)
        {
            var wbuf = new List <byte>(32 * 2 + 4);

            wbuf.AddRange(BitConverter.GetBytes((uint)1));

            var prefixHash  = transaction.GetHash(TxSerializeType.NoWitness);
            var witnessHash = transaction.GetHash(TxSerializeType.WitnessSigning);

            wbuf.AddRange(prefixHash);
            wbuf.AddRange(witnessHash);

            return(HashUtil.Blake256(wbuf.ToArray()));
        }
Beispiel #6
0
        public void GetHash_GivenTestObjectWithKnownHash_ReturnsExpectedHash()
        {
            var msgTx = new MsgTx
            {
                Version           = 1,
                SerializationType = TxSerializeType.Full,
                TxIn  = new[] { txIn },
                TxOut = new[] { txOut }
            };

            var actualHash       = msgTx.GetHash().Reverse().ToArray();
            var actualHashString = Hex.ToHexString(actualHash);

            Assert.Equal(expectedHash, actualHashString);
        }
Beispiel #7
0
        public void New_GivenSerializedValueWithMultipleTx_DeserializesInputAndReserializes()
        {
            var tests = new MsgTxTestSubject[]
            {
                new MultiTxTestSubject(),
                new NoTxTests()
            };

            foreach (var test in tests)
            {
                var subject = new MsgTx();
                subject.Decode(test.EncodedMessage);

                var deserialized = subject.Encode();
                Assert.True(test.EncodedMessage.SequenceEqual(deserialized));
            }
        }
Beispiel #8
0
        /// <summary>
        /// Determines the state of a broadcasted transaction
        /// </summary>
        /// <param name="operationId"></param>
        /// <returns></returns>
        /// <exception cref="BusinessException"></exception>
        public async Task <BroadcastedSingleTransactionResponse> GetBroadcastedTxSingle(Guid operationId)
        {
            if (operationId == Guid.Empty)
            {
                throw new BusinessException(ErrorReason.BadRequest, "Operation id is invalid");
            }

            // Retrieve the broadcasted transaction and deserialize it.
            var broadcastedTransaction = await GetBroadcastedTransaction(operationId);

            var transaction = new MsgTx();

            transaction.Decode(HexUtil.ToByteArray(broadcastedTransaction.EncodedTransaction));

            // Calculate the fee and total amount spent from the transaction.
            var fee    = transaction.TxIn.Sum(t => t.ValueIn) - transaction.TxOut.Sum(t => t.Value);
            var amount = transaction.TxOut.Sum(t => t.Value);

            // Check to see if the transaction has been included in a block.
            var safeBlockHeight = await _dcrdClient.GetMaxConfirmedBlockHeight();

            var knownTx = await _txRepo.GetTxInfoByHash(broadcastedTransaction.Hash, safeBlockHeight);

            var txState = knownTx == null
                ? BroadcastedTransactionState.InProgress
                : BroadcastedTransactionState.Completed;

            // If the tx has been included in a block,
            // use the block height + timestamp from the block
            var txBlockHeight = knownTx?.BlockHeight ?? safeBlockHeight;
            var timestamp     = knownTx?.BlockTime.UtcDateTime ?? DateTime.UtcNow;

            return(new BroadcastedSingleTransactionResponse
            {
                Block = txBlockHeight,
                State = txState,
                Hash = broadcastedTransaction.Hash,
                Amount = amount.ToString(),
                Fee = fee.ToString(),
                Error = "",
                ErrorCode = null,
                OperationId = operationId,
                Timestamp = timestamp
            });
        }
Beispiel #9
0
            public MsgTx SpendingTx()
            {
                var coinbaseTx = new MsgTx
                {
                    TxIn = new[]
                    {
                        new TxIn
                        {
                            PreviousOutPoint = new OutPoint(new byte[32], 0, TxTree.TxTreeRegular),
                            SignatureScript  = new[] { (byte)OpCode.OP_0, (byte)OpCode.OP_0 }
                        }
                    },
                    TxOut = new[]
                    {
                        new TxOut
                        {
                            Value    = 0,
                            PkScript = PublicKeyScript.Bytes
                        }
                    }
                };

                var coinbaseTxHash = coinbaseTx.GetHash();
                var spendingTx     = new MsgTx
                {
                    TxIn = new[]
                    {
                        new TxIn
                        {
                            PreviousOutPoint = new OutPoint(coinbaseTxHash, 0, TxTree.TxTreeRegular),
                            SignatureScript  = SignatureScript.Bytes
                        }
                    },
                    TxOut = new[]
                    {
                        new TxOut()
                    }
                };

                return(spendingTx);
            }
Beispiel #10
0
        public void GetRoot_GivenTestnetGenesisTranasction_ReturnsExpectedMerkleRoot()
        {
            var testnetGenesisTx = new MsgTx
            {
                SerializationType = TxSerializeType.Full,
                Version           = 1,
                TxIn = new[]
                {
                    new TxIn
                    {
                        PreviousOutPoint = new OutPoint
                        {
                            Hash  = new byte[32],
                            Index = 0xffffffff,
                        },
                        SignatureScript = new byte[]
                        {
                            0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x45,
                            0x54, 0x68, 0x65, 0x20, 0x54, 0x69, 0x6d, 0x65,
                            0x73, 0x20, 0x30, 0x33, 0x2f, 0x4a, 0x61, 0x6e,
                            0x2f, 0x32, 0x30, 0x30, 0x39, 0x20, 0x43, 0x68,
                            0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x6f, 0x72,
                            0x20, 0x6f, 0x6e, 0x20, 0x62, 0x72, 0x69, 0x6e,
                            0x6b, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x65, 0x63,
                            0x6f, 0x6e, 0x64, 0x20, 0x62, 0x61, 0x69, 0x6c,
                            0x6f, 0x75, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20,
                            0x62, 0x61, 0x6e, 0x6b, 0x73,
                        },
                        Sequence = 0xffffffff
                    },
                },
                TxOut = new TxOut[]
                {
                    new TxOut()
                    {
                        Value    = 0x00000000,
                        PkScript = new byte[]
                        {
                            0x41, 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55,
                            0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30,
                            0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39,
                            0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61,
                            0xde, 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef,
                            0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1,
                            0x12, 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b,
                            0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1,
                            0x1d, 0x5f, 0xac
                        },
                    },
                },
                LockTime = 0,
                Expiry   = 0,
            };

            // For some reason, the testnet genesis tx is hashed differently than mainnet to
            // get the merkle root.
            var hash       = testnetGenesisTx.GetHash();
            var merkleTree = new MerkleTree();
            var merkleRoot = merkleTree.GetRoot(new[] { hash });

            //            Assert.True();
        }
Beispiel #11
0
        public static byte[] CalculateSignatureHash(ParsedOpCode[] subScript, SignatureHashType hashType, MsgTx transaction, int index)
        {
            const SignatureHashType mask = (SignatureHashType)0x1f;

            if ((hashType & mask) == SignatureHashType.Single && index >= transaction.TxOut.Length)
            {
                throw new InvalidSignatureException("SignatureHashType.Single index out of range");
            }

            // Clear out signature scripts for input transactions not at index
            // transactionIndex
            for (var i = 0; i < transaction.TxIn.Length; i++)
            {
                transaction.TxIn[i].SignatureScript =
                    i == index?
                    subScript.SelectMany(s => s.Serialize()).ToArray()
                        : new byte[0];
            }

            switch (hashType & mask)
            {
            case SignatureHashType.None:
                transaction.TxOut = new TxOut[0];
                for (var i = 0; i < transaction.TxIn.Length; i++)
                {
                    if (i != index)
                    {
                        transaction.TxIn[i].Sequence = 0;
                    }
                }
                break;

            case SignatureHashType.Single:
                transaction.TxOut = new TxOut[index];

                for (var i = 0; i < index; i++)
                {
                    transaction.TxOut[i].Value    = -1;
                    transaction.TxOut[i].PkScript = null;
                }

                for (var i = 0; i < transaction.TxIn.Length; i++)
                {
                    if (i != index)
                    {
                        transaction.TxIn[i].Sequence = 0;
                    }
                }
                break;

            case SignatureHashType.Old:
                break;

            case SignatureHashType.All:
                break;

            case SignatureHashType.AllValue:
                break;

            case SignatureHashType.AnyOneCanPay:
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            if ((hashType & SignatureHashType.AnyOneCanPay) != 0)
            {
                transaction.TxIn = transaction.TxIn
                                   .Skip(index)
                                   .Take(1)
                                   .ToArray();
            }

            var wbuf = new List <byte>(32 * 2 + 4);

            wbuf.AddRange(BitConverter.GetBytes((uint)hashType));

            var prefixHash  = transaction.GetHash(TxSerializeType.NoWitness);
            var witnessHash = transaction.GetHash(
                (hashType & mask) != SignatureHashType.All ?
                TxSerializeType.WitnessSigning :
                TxSerializeType.WitnessValueSigning
                );

            wbuf.AddRange(prefixHash);
            wbuf.AddRange(witnessHash);

            return(HashUtil.Blake256(wbuf.ToArray()));
        }
Beispiel #12
0
 private void OpCheckSigVerify(ParsedOpCode op, MsgTx transaction)
 {
     OpCheckSig(op, transaction);
     OpVerify();
 }