PSBT : Partially Signed Bitcoin Transaction
Partially Signed Bitcoin Transaction (PSBT) 기능은 v0.17.0 에서부터 지원되기 시작하였고, 이후 v0.20.0까지 계속 업그레이드 된 기능이다. 이는 기존의 MultiSig 기능을 보다 향상시킨 기능으로서 BIP-174에 메카니즘이 자세히 서술되어 있다. PSBT는 MultiSig를 비롯한 여러가지 다양한 다중서명 시나리오를 지원하고 있다.
2-of-2 PSBT (다중서명 소비)
MultiSig P2SH 주소에 담긴 코인을 소비하는 방법은 (1) createrawtransaction을 만들어 순차적으로 서명하는 기존의 방법과 (2) PSBT를 사용하는 방법이 있다. 기존의 MultiSig 서명은 복수 개의 키들이 있을 때, MultiSig를 만들 때 사용했던 public key들의 순서대로 한명씩 서명하면서 다음 사람에게 서명된 Hex String을 전달해야 했다. PSBT에서는 이렇게 순차적으로 처리하는 대신 순서에 상관없이 병렬로 서명할 수 있고, 나중에 이를 병합(Combine)하여 다중서명을 완성할 수 있다.
아래는 2-of-2 시나리오에서 PSBT를 사용하는 예이다. 입력으로 2-of-2 서명을 수행한 P2SH UTXO를 가정하고, 생성된 PSBT를 2개의 월렛에서 각각 서명하게 된다. 특히, 여기서 서명을 할 때, PSBT 트랜잭션 Payload를 순차적으로 전달할 필요가 없으며, 처음 PSBT 트랜잭션(psbt)을 각각 월렛1과 월렛2에서 그대로 사용하여 서명하고, 나중에 이를 병합해서 사용한다.
// P2SH: 2N7AiQQ4fKD7DvnRNTd13aT7ybFvgjtqCLF $ txid="e286d399151be8a2faa7c136acfff418fba3c2512518a09db39d085ff3415aa7" $ vout=0 $ recipient=$(bitcoin-cli -rpcwallet="" getnewaddress) // createpsbt 명령: PSBT 트랜잭션 생성 $ psbt=$(bitcoin-cli -named createpsbt inputs='''[{"txid":"'$txid'", "vout":'$vout'}]''' outputs='''{"'$recipient'": 0.0019}''') // [월렛1]에서 PSBT 트랜잭션 서명 (서명 순서 무관하고 동시 병렬 처리 가능) $ psbt1=$(bitcoin-cli -rpcwallet="" walletprocesspsbt $psbt | jq -r '.psbt') //{ // "psbt": "cHNidP8BAFICAAAAAadaQfNfCJ2znaAYJVHCo/sY9P+sNsGn+qLoGxWZ04biAAAAAAD/////ATDmAgAAAAAAFgAU3c5jKFLZix5fkfYbSfjxnebiBvgAAAAAAAEAcgIAAAABqanm/G18G7hm/W0CFddW+XF+vAagTDnpyMof9j24L+IBAAAAAP7///8CQA0DAAAAAAAXqRSYt2bFjhDSNeyNsprBT9fj8lSpKIdZmBUAAAAAABYAFHzidnhplic9pJQ9IcYETLpeLxhoEV8hACICAx6RZM4mq5ThPnowTBdvXaBGxXL3827fNuWJA1XWaaDhRzBEAiAhm0nDLQ5hB5gOv4niLeIZR2ggC4+A2M57vwkd/x+CAgIgYPAOzRA0V+dA+fcXeZDxEFxpBfD8ZVlr3/Bp9JWK0wIBAQRHUiEDHpFkziarlOE+ejBMF29doEbFcvfzbt825YkDVdZpoOEhArrIrXqdys9KzK3krcEAVjpWp2rluW7e9VTkh3jZNyxJUq4iBgK6yK16ncrPSsyt5K3BAFY6Vqdq5blu3vVU5Id42TcsSQSt7TAcIgYDHpFkziarlOE+ejBMF29doEbFcvfzbt825YkDVdZpoOEQnRRW7wAAAIAAAACAKwAAgAAiAgKXtxhAHtScAoJTmUPEF0BGiZR/KcunJbzkUbzcaJRpyhCdFFbvAAAAgAAAAIAsAACAAA==", // "complete": false //} // 서명이 수행되면, partial_signatures 안에 public key와 signature가 표시됨 $ bitcoin-cli decodepsbt $psbt1 ... 일부 ... "partial_signatures": { "031e9164ce26ab94e13e7a304c176f5da046c572f7f36edf36e5890355d669a0e1": "30440220219b49c32d0e6107980ebf89e22de2194768200b8f80d8ce7bbf091dff1f8202022060f00ecd103457e740f9f7177990f1105c6905f0fc65596bdff069f4958ad30201" }, // [월렛2]에서 PSBT 트랜잭션 서명 (병렬 처리 가능) // 주의: walletpassphrase로 먼저 월렛을 Open 할 것. // Open 되지 않은 경우, 에러 없이 서명만 되지 않음. $ psbt2=$(bitcoin-cli -rpcwallet="test2" walletprocesspsbt $psbt | jq -r '.psbt') //{ // "psbt": "cHNidP8BAFICAAAAAadaQfNfCJ2znaAYJVHCo/sY9P+sNsGn+qLoGxWZ04biAAAAAAD/////ATDmAgAAAAAAFgAU3c5jKFLZix5fkfYbSfjxnebiBvgAAAAAAAEAcgIAAAABqanm/G18G7hm/W0CFddW+XF+vAagTDnpyMof9j24L+IBAAAAAP7///8CQA0DAAAAAAAXqRSYt2bFjhDSNeyNsprBT9fj8lSpKIdZmBUAAAAAABYAFHzidnhplic9pJQ9IcYETLpeLxhoEV8hAAEER1IhAx6RZM4mq5ThPnowTBdvXaBGxXL3827fNuWJA1XWaaDhIQK6yK16ncrPSsyt5K3BAFY6Vqdq5blu3vVU5Id42TcsSVKuIgYCusitep3Kz0rMreStwQBWOlanauW5bt71VOSHeNk3LEkQ3gk7LQAAAIAAAACABQAAgCIGAx6RZM4mq5ThPnowTBdvXaBGxXL3827fNuWJA1XWaaDhBHw4MXIAAA==", // "complete": false //} // 서명이 수행되면, partial_signatures 안에 2번째 서명 표시됨 $ bitcoin-cli decodepsbt $psbt2 ... 일부 ... "partial_signatures": { "02bac8ad7a9dcacf4accade4adc100563a56a76ae5b96edef554e48778d9372c49": "304402205851976f710595904423057757a6f742cd84dd4df6c5903cb8c7c1a96d2f0ce2022041afa4fe06942dd61c9452e239d51f2639d82c0b67cbbdf2428a352ae92bbd9701" }, // combinepsbt 명령을 복수 개의 서명들을 하나로 합친다 $ psbtall=$(bitcoin-cli combinepsbt '''["'${psbt1}'","'${psbt2}'"]''') // analyzepsbt 명령으로 finalizer 가능한 지 체크 $ bitcoin-cli analyzepsbt $psbtall { "inputs": [ { "has_utxo": true, "is_final": false, "next": "finalizer" } ], "estimated_vsize": 299, "estimated_feerate": 0.00033444, "fee": 0.00010000, "next": "finalizer" } // finalizepsbt 명령으로 finalize 수행 $ finaltx=$(bitcoin-cli finalizepsbt $psbtall | jq -r '.hex') // Send Transaction $ bitcoin-cli sendrawtransaction $finaltx
PSBT 사용
PSBT는 여러 가지 시나리오에서 사용될 수 있다. 먼저 위에서와 같이 MultiSig를 소비(spend)하는데 사용될 수 있다. 예를 들어 어떤 책을 5명의 공동저자가 작성했다면, 하나의 P2SH 주소를 만들고 저자 수입을 보내게 하고, 나중에 5명의 주소로 각각의 지분만큼을 보내는 하나의 트랜잭션을 만들어 이를 5명이 확인하면서 서명할 수 있을 것이다.
또 다른 시나리오로서, 여러 개의 Input 트랜잭션(UTXO)들을 하나의 주소로 송금하는 경우, 먼저 PSBT 트랜잭션을 만들고, 이를 여러 명이 서명하도록 할 수 있다. 즉, 한명씩 송금하는 대신 모두의 UTXO를 묶어 하나의 트랜잭션을 만들고, 이를 다중서명하는 방식이다. 위의 P2SH 다중서명은 하나의 P2SH를 소비할 때, P2SH 자체가 복수 개의 서명을 요구하는 반면, 이 경우는 P2SH 대신 여러 개의 UTXO들을 직접 사용하는 경우로 볼 수 있다.
비슷한 시나리오로서 CoinJoin 이 있는데, 이는 여러 명이 코인을 보내는 것을 하나의 트랜잭션을 묶는 방식이다. 예를 들어 3명이 각각 다른 사람들에 코인을 보낼 때 (예를 들어 3개의 UTXO를 3개의 수신주소로 보낸다고 가정), 트랜잭션 Input과 Output을 각각 나열하고 3명의 서명을 받아 이를 마지막 한 사람이 취합하여 Send 하는 방식이다. 아래는 이러한 방식의 PSBT 생성을 표현한 것이다.
$ bitcoin-cli -named createpsbt inputs='''[ { "txid": "'$utxo_txid_1'", "vout": '$utxo_vout_1' }, { "txid": "'$utxo_txid_2'", "vout": '$utxo_vout_2' }, { "txid": "'$utxo_txid_3'", "vout": '$utxo_vout_3' } ]''' outputs='''{ "'$split1'": 1,"'$split2'": 2,"'$split3'": 3 }'''
PSBT가 활용되는 시나리오로서 빼놓을 수 없는 것은 하드웨어 월렛이다. 이 시나리오는 Desktop이나 모바일의 월렛에서 트랜잭션을 만들고, 이를 하드웨어 월렛에서 서명하도록 하고, 그 서명을 받아 Desktop/모바일 월렛에서 트랜잭션을 보내게 된다.