Ошибки при построении/отправке мультиподписных транзакций

На примере здесь: https://bitcoinj.github.io/working-with-contracts

Я считаю, что все сделал правильно. Тем не менее, моя программа не может распространяться правильно или из-за ошибки tx, и я не могу определить, почему

Несколько вещей, которые я считаю причиной

1) Моя одноранговая группа. соответствующим образом (например, использую ли я класс UTXO или TransactionSignature) 3) Попытка потратить средства с отслеживаемого адреса. У меня есть необходимые ключи для разблокировки UTXO, но я хотел бы посмотреть, смогу ли я потратить средства без использования класса кошелька 4) В целом поддержка Multisig для биткойнов отсутствует или неполная. я надеюсь, что это не так, как я действительно хотел бы, чтобы это работало. Но - я не думаю, что это самая большая проблема, потому что я провел модульные тесты, и все они все еще проверяются.

Шаг через код, чтобы быть тщательным:

Создайте 3 ECKeys для мультиподписного контракта 2 из 3, поместите их в список, создайте сценарий выкупа, который сортирует ключи в лексикографическом порядке и записывает сценарий мультиподписи m-of-n, затем создайте экземпляр объекта транзакции и назначьте его в качестве ВЫХОДА. который я буду использовать в качестве ВХОДА (сумма + сценарий погашения), также известного как UTXO, который я буду тратить (РЕДАКТИРОВАТЬ: краткое упоминание. На самом деле ECKeys, которые я использую, являются жестко закодированными значениями, которые я сделал некоторое время назад, это для иллюстрации. Я также должен упомянуть, что это мультиподпись P2SH, а не необработанная нестандартная мультиподпись.

ECKey keyA = new ECKey();
ECKey keyB = new ECKey();
ECKey keyC = new ECKey();

List<ECKey> keys = ImmutableList.of(key1, key2, key3);

Script script = ScriptBuilder.createRedeemScript(2, keys);
Script scriptPubKey = ScriptBuilder.createP2SHOutputScript(script);

Transaction contract = new Transaction(params);
TransactionOutput multiSigOutput = contract.addOutput(Coin.valueOf(50000), scriptPubKey);

Создайте второй объект транзакции, который я буду использовать для сборки выходного сценария, также известного как адрес (значение + пункт назначения), на который я буду подписывать свой UTXO. Также где sigHash подписан двумя моими ключами и добавлен в scriptSig транзакции

                        Transaction spendTx = new Transaction(params);
                        Address address = Address.fromBase58(params, "19EfMrs5WkcvtBBnuEqP6v1yppeWww61Kc");
                        Script outputScript = ScriptBuilder.createOutputScript(address);
                        spendTx.addOutput(multiSigOutput.getValue(), outputScript);
//                        System.out.println(spendTx.getOutputs());
                        TransactionInput input = spendTx.addInput(multiSigOutput);

теперь вручную подписывайте входы... (подписи в том же порядке, что и в скрипте)

//sign transaction manually
Sha256Hash sigHash = spendTx.hashForSignature(0, script, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature signature = list.get(0).sign(sigHash);
ECKey.ECDSASignature signature1 = list.get(1).sign(sigHash);
TransactionSignature txSig = new TransactionSignature(signature, Transaction.SigHash.ALL, false);
TransactionSignature txSig1 = new TransactionSignature(signature1, Transaction.SigHash.ALL, false);

... теперь создайте multisignputscript, проверьте и транслируйте tx

                        Script inputScript = ScriptBuilder.createP2SHMultiSigInputScript((ImmutableList.of(txSig, txSig1)));
//                        System.out.println(inputScript);
                        input.setScriptSig(inputScript);
                        input.verify(multiSigOutput);

                        peerGroup.broadcastTransaction(spendTx);

                        System.out.println(kit.peerGroup().getConnectedPeers());
                        System.out.println("transaction broadcasted");

хорошо... это не распространяется, но проверка подтверждается. и я даже не знаю, является ли это проблемой сети, поскольку это проблема кода, потому что, когда я изменяю значение в выходном сценарии на> баланс UTXO, он не генерирует исключение InsufficientMoneyException, как я думаю, это должно быть. Я бы показал некоторые журналы ошибок, но их нет. Единственная ошибка заключается в том, что когда я меняю createmultisiginputscript на createP2SHmultisiginputscript, консоль выдает ненулевую ошибку nulldummy, которую у меня также возникают проблемы с исправлением, поэтому я никогда не мог узнать, является ли переход на этот метод правильным решением. Я думаю, что я правильно настроил соединение с группой пиров.

File chainFile = new File(this.getFilesDir(), "test.spvchain");
System.out.println("does chainfile exist?"  + chainFile.exists());
if(chainFile.exists()) {
    try {
        SPVBlockStore chainStore = new SPVBlockStore(params, chainFile);
        BlockChain chain = new BlockChain(params, chainStore);
        peerGroup = new PeerGroup(params, chain);
        peerGroup.addPeerDiscovery(new DnsDiscovery(params));
        peerGroup.startAsync();
    } catch (BlockStoreException e) {
        e.printStackTrace();
    }

Так что я действительно не понимаю... Я пришел к выводу, что мое понимание как-то не так. Извините за запутанный длинный пост. Прошли дни. Кто-нибудь может помочь?

РЕДАКТИРОВАТЬ: вот необработанная транзакция

В шестнадцатеричном формате:

В журналах:

fbb119d8990cd3912a9ec0118fe3ad8ad61a8388e4a13dd342d9eb67aacfdc65

01-12 17:49:20.670 2507-2507/com.cryptoapp.app I/System.out: in 0[] PUSHDATA(71)[3044022022b97b9372d35acaea70f3735dee290f5697cab7b5d6be6f7cdfe31139fba4f90220651091b83570843d4fe8afe02d81417194908b0f6af6f8f3b8f1ad020592409f01] PUSHDATA(71)[3044022036eff4f54b8bf3f834f7bb6e417a04a6a696047f5c75a896c6f9b624ad87680a02200bf2115b64b3b15647178b69151d4588d8a4ade16a4d66e375d0e1265c79fad601] PUSHDATA1[5221025ab78e076801b45ccb2172bce562103cce1714edbeb02ce6123ce1235eb08c762102d1b74577050b696d5886a7afa61d099ea7ab0a3797766f9819dbd72526b0ce512103facf04db5d9bee657151e30c21e839489c326a277891ebcf75b736ec1e17fc1f53ae] 0.0005 BTC 01-12 17:49:20.670 2507-2507/com.cryptoapp.app I/System.out: outpoint:c33858b433ef445db35a84daa4da772895df7f03af4b31f21cfa199ea1c017d9:0 hash160:6d49586d7529626aaab49812bcd7839aee7e5800 01-12 17:49:20.670 2507-2507/com.cryptoapp.app I/System.out: out DUP HASH160 PUSHDATA(20)[5a566f4eda18e818b8d5ca04ee7c5fa3cfbf0e00] EQUALVERIFY CHECKSIG 0,0005 BTC 01-12 17:49:20,670 2507-2507/com.cryptoapp.app I/System.out: комиссия 0,7 байт BTC, 000 BTC. 01-12 17:49:20.670 2507-2507/com.cryptoapp.app I/System.out: prps НЕИЗВЕСТНО

Ответы (1)

Пара комментариев по результатам проверки опубликованных вами данных о транзакциях.

1) Я проверил UTXO, с которого вы тратите, это UTXO.

  • 9e7562d19165077d566af47bfbc18283629ed6799da8862660dfb037c353de11
  • Индекс 0

Тем не менее, ваша транзакция в настоящее время ссылается на следующий UTXO:

  • c33858b433ef445db35a84daa4da772895df7f03af4b31f21cfa199ea1c017d9
  • Индекс 0

Что не является подтвержденной транзакцией в основной сети.

2) Ваш входной скрипт кажется правильно сформированным, чтобы использовать вывод P2SH (Multisig):

  • zero
  • [3044022022b97b9372d35acaea70f3735dee290f5697cab7b5d6be6f7cdfe31139fba4f90220651091b83570843d4fe8afe02d81417194908b0f6af6f8f3b8f1ad020592409f01]
  • [3044022036eff4f54b8bf3f834f7bb6e417a04a6a696047f5c75a896c6f9b624ad87680a02200bf2115b64b3b15647178b69151d4588d8a4ade16a4d66e375d0e1265c79fad601]
  • [2 [025ab78e076801b45ccb2172bce562103cce1714edbeb02ce6123ce1235eb08c76] [02d1b74577050b696d5886a7afa61d099ea7ab0a3797766f9819dbd72526b0ce51] [03facf04db5d9bee657151e30c21e839489c326a277891ebcf75b736ec1e17fc1f] 3 checkmultisig]

Последним элементом является встроенный скрипт, который должен хэшировать до 20-битного дайджеста в вашем UTXO, который вы тратите: он действительно правильно хэширует 160 до 6d49586d7529626aaab49812bcd7839aee7e5800.

Для справки, выходной сценарий P2SH (Multisig) вашего UTXO: "hash160 [6d49586d7529626aaab49812bcd7839aee7e5800] equal"обратите внимание, что хэши одинаковы, так что это хорошо.

3) Вы не включили комиссию в свою транзакцию. Сумма вывода 50000 сатоши идентична сумме UTXO. Чтобы эта транзакция была принята мемпулом, должна быть минимальная комиссия.

Надеюсь, это поможет.

Спасибо за ваш комментарий. Это проверяет. Если бы это было не так, это выдало бы ошибку.
Сценарий сценария = ScriptBuilder.createRedeemScript(2, ключи); и сценарий сценария = ScriptBuilder.createMultiSigOutputScript(2, ключи); это то же самое, за исключением того, что createRedeemScript помещает ключи в лексикографическом порядке, но возвращает ту же функцию
Можете ли вы опубликовать оба необработанных tx здесь, было бы легче помочь в отладке.
Ах хорошо. Так что вам все равно нужно подтвердить первую передачу перед передачей второй.
Так что я немного смущен. Я думал, что первый tx был сценарием вывода, который создает шаблон для UTXO в качестве контекста для второй транзакции (и проверки). Так вы говорите, что я должен транслировать то, что я создал сценарий мультиподписи, а затем также транслировать расходы?
Да. В вашем скрипте расходов нечего тратить: вы генерируете новые ключи в начале своего скрипта, а это означает, что в блокчейне нет выходных данных с мультиподписью, которые вы можете потратить с этими ключами. Только после того, как этот tx с выводом multisig будет добыт, его можно будет потратить. Тем не менее, ваш первый multisig tx также потребует ввода, иначе мы будем создавать Биткойн из воздуха.
О, я понимаю путаницу. Эти ключи ECKeys на самом деле являются шаблоном реальных ключей, которые я использую. Здесь уже есть UTXO по моему реальному адресу: blockchain.com/btc/address/3BesSajTyegQaBeyJXes6kyav3srZC3p7D . Поэтому я пытаюсь получить этот вывод и потратить его с теми же ключами/скриптом, которые я использовал для создания этого P2SH-адреса. Я просто не хотел выставлять их здесь. Извините за путаницу. Я постараюсь изменить это, чтобы быть менее двусмысленным
Итак, вы не упомянули оболочку P2SH выше. Если вы тратите мультиподпись с оболочкой P2SH, вы не воссоздаете оболочку P2SH в выходном шаблоне выше, а только необработанную мультиподпись, а также не сценарий погашения P2SH во входных данных о расходах.
Хорошо. Спасибо. Я попытался использовать скрипт P2SHredeemscript в своих расходах, но он выдает ошибку «ненулевой nulldummy» с использованием bitcoinj 0.14.7. Спасибо за этот совет. Я подумал, что мне нужно добавить код OP_0 на вершину стека, но это, похоже, не сработало само по себе. Я поиграю с ним еще немного. Пожалуйста, дайте мне знать о чем-нибудь еще, что может быть не так.
Сообщение отредактировано для уточнения, надеюсь
Также убедитесь, что вы создаете свой первый шаблон TX точно так же, как тот, который был создан. То есть он должен иметь точно такие же входы/выходы. Это связано с тем, что второй TX ссылается на этот первый TXID по TXID, который представляет собой хеш Bitcoin256 полной сериализации данных TX. Если вы пропустите входные данные или что-то еще в своей первой транзакции (по сравнению с TX, который уже подтвержден), вторая транзакция будет ссылаться на неправильный TXID.
Большой. Я ценю вашу помощь, сэр. Могу я написать вам по электронной почте для небольшого разъяснения?
В целом да, но, возможно, было бы лучше оставить обсуждение этого вопроса общедоступным на этом форуме, чтобы другие также могли его просмотреть и подтвердить. Вы всегда можете пересмотреть свой вопрос или опубликовать переформулированный, и я буду рад помочь, чем смогу.
Привет, я перенес обе свои функции ввода и вывода, чтобы они соответствовали формату P2SH исходного UTXO (обновленный пост для показа). Однако я все еще получаю тот же тихий сбой, хотя все, кажется, совпадает. Теперь я не уверен, в чем может быть проблема, кроме того, что она не транслируется в одноранговую сеть.
Можете ли вы опубликовать необработанные TX?
Привет. Я отредактировал свой пост, чтобы включить необработанный tx в шестнадцатеричном формате и то, как он отображается в моей консоли.
ах. хорошо. После использования декодера транзакций blockcypher live.blockcypher.com/btc/decodetx и ввода моей необработанной шестнадцатеричной транзакции из приведенного выше поста... я думаю, что скомпилировал неверную транзакцию. Хм
Я отредактировал ответ выше, чтобы указать на несколько наблюдений, сделанных при проверке вашей опубликованной транзакции.
Да. Спасибо. Я пытался изменить этот минус уже большую часть дня. Я понятия не имею, почему он ссылается на этот идентификатор транзакции.
Большое спасибо. Я исправил проблему, написав в своем собственном минусе, потому что я понятия не имею, почему библиотека без всякой причины изменила мой txid. Я напишу отчет об ошибке
Потрясающий! Не могли бы вы отметить ответ (отметить), если он помог вам решить ваш вопрос? Очень признателен.
Я бы с удовольствием, но у меня недостаточно представителей, чтобы пометить ответ как принятый. Я не знаю, почему они добавляют этот лимит, но как только я наберу достаточно повторений, я буду рад
Не беспокойтесь, просто приятно иметь. Пока вы получили нужный вам ответ и можете продолжать свой проект, все довольны.
Сэр, я только что увидел, что вы были инструктором по обучению биткойнов.io. Нет причин публиковать это, я просто подумал, что это круто, так как у меня есть этот сайт в закладках
Ура, Стивен, рад, что вы работаете над биткойнами :)
@Stephen: Я думаю, здесь есть недоразумение. Вы не можете проголосовать за сообщение, пока у вас не будет репутации, но вы всегда можете пометить ответы на свой вопрос как наиболее полезный ответ. Я думаю, вы, возможно, пытались нажать «стрелку вверх», чтобы проголосовать за сообщение. Вместо этого попробуйте нажать «галочку»!