/// <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())); }
/// <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 }); }
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); }
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); }
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(); }
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())); }