Быстрый вопрос о подписании сделки. Я написал метод подписи транзакций с использованием байт. В основном просто понять Scrypt часть и входы и выходы лучше.
Все хорошо работает с одним входом и 2 выходами (изменение), например, эта сделка работала http://blockexplorer.com/tx/852cb5b462de0fc0d67d14618945e854822e649098242577a363bd1d2caa9c7a#o0
Что им бороться с собой несколько входов. Ниже artcile перечисляет вход, как это. Который имеет смысл. Если вход является сбор, ниже просто повторяется? Затем подписывается вся структура?
предыдущий выходной хэш
(В обратном порядке) 48 40 4d d4 5b 9e а0 d 6 52 25 FC а8 8а b7 ча а4 25 41 ЕВ 52 97 58 57 f9 6f b5 0c d7 32 с8 b4 81
предыдущий индекс 00 Выходной 00 00 00
длина сценария
scriptSig сценарий, содержащий подпись
Последовательность FF FF FF FF
Я следовал этой ТПИ, и пример питона от него.
http://www.righto.com/2014/02/bitcoins-hard-way-using-raw-bitcoin.html
C # код: классы NB, DTO не в образце
общественный класс Transaction
{
общественного Byte [] Версия
{
получить
{
вернуть новые байты [4] {0x01, 0x00, 0x00, 0x00};
}
}
общественного Byte [] Locktime
{
получить
{
вернуть новые байты [4] {0x00, 0x00, 0x00, 0x00};
}
}
общественного Byte [] HashType
{
получить
{
вернуть новые байты [4] {0x01, 0x00, 0x00, 0x00};
}
}
общественного Byte [] Изменить
{
получить;
частный набор;
}
общественного Byte [] Значение
{
получить;
частный набор;
}
общественного Byte NumTxIn
{
получить
{
если (_outputsToSpend! = NULL)
{
вернуть Convert.ToByte (_outputsToSpend.Count); // новый байт [1] {0x01};
}
еще
{
вернуть Convert.ToByte (0);
}
}
}
общественного Byte NumTxOut
{
получить
{
вернуть Convert.ToByte (2);
}
}
общественного Byte [] ВЫХОДЫ
{
получить
{
возвращать нуль;
}
}
общественного Byte [] Последовательность
{
получить
{
вернуть новые байты [4] {0xFF, 0xFF, 0xFF, 0xFF}; // FF FF FF FF
}
}
частный IList
публичная сделка (IList
{
// сумма = сумма * DC.Common.Math.SATOSHI;
// плата = плата * DC.Common.Math.SATOSHI;
// Сумма отправки + плата шахтеров
Десятичное изменение = (сумма + плата) - outputsToSpend.Sum (о => o.Value) / DC.Common.Math.SATOSHI;
//ИЗМЕНЕНИЕ
this.Change = DC.Common.Math.GetValueAsBytes (изменить);
this.value = DC.Common.Math.GetValueAsBytes (сумма);
_outputsToSpend = outputsToSpend;
}
общественные байты [] CreateAndSignTransaction (DC.Common.Models.Address sourceAddress, Строка DestinationAddress, Строка destinationHash160, Десятичная сумма, Десятичный плата = 0.0001M)
{
если (! DC.Common.BitcoinHelper.IsValidAddress (DestinationAddress))
певд ArgumentException ("Пункт назначения адрес не является действительным");
// Int32 OUTPUT_INDEX = 1;
Int32 SIGHASH_ALL = 1;
// 1
Байт [] версия = this.Version;
Debug.Assert (версия [0] == 1);
Debug.Assert (version.Length == 4);
// 2
// Байт num_txin = Convert.ToByte (outputsToSpend.Count); // новый байт [1] {0x01};
Байт [] tx_fields = version.Concat (this.NumTxIn);
Debug.Assert (tx_fields.Length == 5);
Еогеасп (DC.Common.Models.UnspentOutput outputToSpend в _outputsToSpend)
{
// ЭТО кеш СДЕЛКИ, который содержит неизрасходованный OUTPUT
// NB, УЖЕ ПЕРЕВЕРНУТЫМ!
Байт [] incomingTxHash = DC.Common.StringHelper.HexStringToByte (outputToSpend.TxHash);
//Array.Reverse(incomingTxHash);
// 3
Байт [] prevout_hash = DC.Common.StringHelper.HexStringToByte (outputToSpend.TxHash);
//Array.Reverse(prevout_hash);
tx_fields = tx_fields.Concat (prevout_hash);
// 4 (индекс 0)
// TODO: это подтверждают. ARRAY имеет длину 4 байта, Wiht ПРЕДЫДУЩИЙ INDEX EG 00 00 00 01
Байт [] output_index = BitConverter.GetBytes (outputToSpend.TxOutputN);
Array.Reverse (output_index);
// Байт [] output_index = новый байт [4] {0x00, 0x00, 0x00, 0x00};
//Array.Copy(outputIndexTemp, 1, output_index, 4 - outputIndexTemp.Length, outputIndexTemp.Length);
tx_fields = tx_fields.Concat (output_index);
//ЗАМЕНА. NB У НАС ЕСТЬ Scrypt, JUST CONVERT байт
// ## Далее идет часть ввода транзакции. здесь мы размещаем сценарий на * выходной *, что мы хотим, чтобы искупить
// Строка sourceOutputPublicKey = DC.Common.Script.ParseScript (outputsToSpend [0] .Script);
Байт [] tempScript = DC.Common.StringHelper.HexStringToByte (outputToSpend.Script);
Байт scriptSighHashLength = Convert.ToByte (tempScript.Length);
tx_fields = tx_fields.Concat (scriptSighHashLength);
Байт [] scriptSigHash = DC.Common.StringHelper.HexStringToByte (outputToSpend.Script);
tx_fields = tx_fields.Concat (scriptSigHash);
// 7
tx_fields = tx_fields.Concat (this.Sequence);
}
// 8
// Байт [] num_txout = новый байт [1] {0x02}; // 1
tx_fields = tx_fields.Concat (this.NumTxOut);
// 9
// Байт [] значение = DC.Common.Math.GetValueAsBytes (сумма);
tx_fields = tx_fields.Concat (this.value);
// 10
//http://bitcoin.stackexchange.com/questions/3374/how-to-redeem-a-basic-tx
Байт [] scriptPubKey = DC.Common.Script.CreateScriptPubKey (destinationHash160);
Байт scriptLen = Convert.ToByte (scriptPubKey.Length);
tx_fields = tx_fields.Concat (scriptLen);
tx_fields = tx_fields.Concat (scriptPubKey);
// Сумма отправки + плата шахтеров
// десятичного изменение = (сумма + плата) - outputsToSpend.Sum (о => o.Value) / DC.Common.Math.SATOSHI;
//ИЗМЕНЕНИЕ
tx_fields = tx_fields.Concat (this.Change);
//http://bitcoin.stackexchange.com/questions/3374/how-to-redeem-a-basic-tx
Байт [] changeScriptPubKey = DC.Common.Script.CreateScriptPubKey (sourceAddress.PublicKeyHash160); // SELF
Байт changeScriptLen = Convert.ToByte (changeScriptPubKey.Length);
tx_fields = tx_fields.Concat (changeScriptLen);
tx_fields = tx_fields.Concat (changeScriptPubKey);
// END CHANGE
// 12
tx_fields = tx_fields.Concat (this.LockTime);
// 13
tx_fields = tx_fields.Concat (this.HashType);
// DOUBLE HASH
Байт [] hash_scriptless = Crypto.DoubleSHA256 (tx_fields);
// SIGN DATA
Байт [] sig_data = Crypto.Sign (hash_scriptless, sourceAddress.d, DC.Common.Crypto.GetDomainParams ());
sig_data = sig_data.Concat (Convert.ToByte (SIGHASH_ALL));
//final_tx.write_int32(tx_fields['version '])
//final_tx.write_compact_size(tx_fields['num_txin'])
//final_tx.write(tx_fields['prevout_hash '])
//final_tx.write_uint32(tx_fields['output_index '])
Байт [] final_tx = this.Version; // новый байт [4] {0x01, 0x00, 0x00, 0x00}; //версия
Debug.Assert (final_tx [0] == 1);
final_tx = final_tx.Concat (NumTxIn); // Количество
Еогеасп (DC.Common.Models.UnspentOutput outputToSpend в _outputsToSpend)
{
// final_tx = final_tx.Concat (prevout_hash);
Байт [] previousTxHash = StringHelper.HexStringToByte (outputToSpend.TxHash);
final_tx = final_tx.Concat (previousTxHash);
Байт [] previousOutputIndex = новый байт [4];
previousOutputIndex = BitConverter.GetBytes (outputToSpend.TxOutputN); //ДЕЛАТЬ
Array.Reverse (previousOutputIndex);
final_tx = final_tx.Concat (previousOutputIndex);
}
Байт [] pub_key = StringHelper.HexStringToByte (sourceAddress.PublicKeyAsHex);
// scriptSig = CHR (LEN (sig_data)) + sig_data + CHR (LEN (pubkey_data)) + pubkey_data
Байт [] scriptSig = новый байт [1]; // Длина
scriptSig [0] = Convert.ToByte (sig_data.Length); // Длина
scriptSig = scriptSig.Concat (sig_data); //данные
scriptSig = scriptSig.Concat (Convert.ToByte (pub_key.Length)); // ключ паб Длина
scriptSig = scriptSig.Concat (pub_key); // ключ паб
final_tx = final_tx.Concat (Convert.ToByte (scriptSig.Length)); // Длина сценария сиг
final_tx = final_tx.Concat (scriptSig);
final_tx = final_tx.Concat (this.Sequence);
final_tx = final_tx.Concat (this.NumTxOut);
final_tx = final_tx.Concat (this.value);
final_tx = final_tx.Concat (Convert.ToByte (scriptPubKey.Length));
final_tx = final_tx.Concat (scriptPubKey);
final_tx = final_tx.Concat (this.Change);
final_tx = final_tx.Concat (Convert.ToByte (changeScriptPubKey.Length));
final_tx = final_tx.Concat (changeScriptPubKey);
final_tx = final_tx.Concat (this.LockTime);
вернуться final_tx;
}
}