본문으로 바로가기

이전 포스트에서 설명한 raw transaction 생성하기의 내용을 기반으로 실제 transaction을 Bitcoin testnet으로 전송해보도록 하겠습니다.

본 내용은 하기 Tutorial을 참고로 하였습니다.


http://aaronjaramillo.org/libbitcoin-broadcasting-a-transaction-to-the-network


먼저 이전 포스팅에서 설명한것처럼 비트코인 테스트넷에서 지갑을 만들고 연상기호 단어를 사용하여 키와 주소를 복구한후 비트코인을 전송할경우 정상적으로 전송이 되지않습니다. 이 문제에 대해서 위 블로그의 Tutorial을 연재하고 있는 "Aaron Jaramillo"에게 문의를 하였는데 아주 친절히 문제점에 대해서 설명을 해주었습니다. 먼저 현재 Tutorial에서 설명하고 있는 HD_Wallet 클래스는 키생성 기능만 있기 때문에 BIP44 연상기호 단어열을 통한 키 복구기능을 지원하지 않습니다. 따라서 이전 포스팅에서와 같이 Testnet에서 지갑을 만들고 연상기호 단여열을 통해서 키를 생성하여 사용하면 정상적인 전송을 할수가 없습니다. 따라서 이전 포스팅을 참고로 해서 하기의 연상기호 단어열을 사용해서 Child key를 유도하여 그 주소로 비트코인을 전송하여 UTXO를 만들고, 그것을 거래의 Input으로 사용하면 되겠습니다 이번 포스팅에서는 Aaron Jaramillo가 이전에 제가 테스트넷 지갑에서 생성한 연상기호 단어열을 사용하여 유도된 2개의 child 키를 보내주었고, 그 주소로 비트코인을 전송하여 UTXO를 만들고 그것을 알려주었기 때문에 그것을 전송에 사용하도록 하겠습니다.


Child key 1 Address : mi91N62dqcKKtPMG9fXdbTgVSD6kyEAb6E

Child key 2 Address : mydQGTzXibaQNDSqTJu7x5YxdQVRred3nu

UTXO Hash : 063d24e69dc052bf79d481d537d92a8fab00b54c8ba7158130be8a0880ac899b


위와같이 각각 2개의 Child index에 해당하는 주소를 사용하여 전송에 사용하도록 하겠습니다.


먼저 이전에 작성한 HD_Wallet_Testnet.cpp 코드는 그대로 사용이 가능합니다.

그리고 rawTX.cpp는 다음과 같이 변경을 하도록 하겠습니다.


하기에 작성한 코드는 다음의 github에서 다운로드 받을수 있습니다.


https://github.com/ihpark92/Libbitcoin_Tutorial/BitcoinNetwork


프롬프트를 통해 사용자 입력을 받지않고, 코드에 하드코딩하여 동작확인을 하기위해 다음과 같이 입력을 받는 함수를 작성합니다.


std::string getInput(int preset)
{
if(preset == 1)
{
return "assume code hotel produce genius owner park pluck snake rough solid soap"; //Mnemonic
} else if (preset == 2)
{
// Index of child key
//return "1"; // mi91N62dqcKKtPMG9fXdbTgVSD6kyEAb6E
return "2"; // mydQGTzXibaQNDSqTJu7x5YxdQVRred3nu
}else if (preset == 3)
{
return "mi91N62dqcKKtPMG9fXdbTgVSD6kyEAb6E";
//return "mydQGTzXibaQNDSqTJu7x5YxdQVRred3nu"; // index 2
}else if (preset == 4)
{
return "0.49"; //Amount of Bitcoin to Spend
} else if (preset == 5)
{
return "063d24e69dc052bf79d481d537d92a8fab00b54c8ba7158130be8a0880ac899b";
}else if (preset == 6)
{
return "0"; //Output index of UTXO
}else if (preset == 7)
{
return "My first raw transaction";
}
}


1번은 연상기호 단어열을 통해 개인키와 공개키를 생성하기 위해 연상기호 단어열을 입력해줍니다.

2번에서  사용하기 위한 Child key index 를 선택합니다. (1 or 2)

3번에서 위에서 설명한것처럼 각 인덱스에 해당하는 키의 주소를 반환하고, 여기서 반환된 주소로 비트코인을 전송하게 됩니다.

4번은 전송하고자 하는 비트코인의 갯수를 지정합니다.

5번은 Transaction의 Input에 사용하기 위한 UTXO의 hash 값을 명시합니다.

6번은 UTXO의 인덱스 번호입니다.

7번에서 Transaction의 Label을 지정합니다.


그리고 이전에 작성한 rawTX.cpp 코드에 다음과 같이 Testnet에 작성한 transaction을 전송하는 코드를 추가합니다.


client::connection_type connection = {};
connection.retries = 3;
connection.timeout_seconds = 8;
connection.server = config::endpoint("tcp://testnet.libbitcoin.net:19091");
client::obelisk_client client(connection);
if(!client.connect(connection))
{
std::cout << "Fail" << std::endl;
} else {
std::cout << "Connection Succeeded" << std::endl;
}
static const auto on_done = [](const code& ec) {
std::cout << "Success: " << ec.message() << std::endl;
};
static const auto on_error2 = [](const code& ec) {
std::cout << "Error Code: " << ec.message() << std::endl;
};
client.transaction_pool_broadcast(on_error2, on_done, tx);
client.wait();


다음과 같이 빌드를 합니다.


$ g++ -std=c++11 -o ./rawTX rawTX.cpp HD_Wallet_Testnet.cpp $(pkg-config --cflags libbitcoin --libs libbitcoin libbitcoin-client)
$


다음과 같이 정상적으로 testnet에 전송되었음을 확인할수 있습니다.



그럼 실제 해당거래가 testnet에 전송이 되었는지 테스트넷에서 확인해보겠습니다.


비트코인을 전송한 주소인 mi91N62dqcKKtPMG9fXdbTgVSD6kyEAb6E 로 검색해보면 다음과같이 거래가 되었음을 확인할수 있습니다.

하기와같이 Child key index 2번 주소(mydQGTzXibaQNDSqTJu7x5YxdQVRred3nu) 에서 Child key index 1번 주소(mi91N62dqcKKtPMG9fXdbTgVSD6kyEAb6E ) 로 0.49 비트코인이 전송이 되었습니다.



그럼 이번에는 해당 거래의 Transaction Hash 값으로 확인을 해보겠습니다.

다음과 같이 거래는 테스트넷의 1291200 블록에 포함이 되었습니다.

입력/출력 스크립트는 다음과 같고, 위에서 지정한 Label 값도(My first raw transaction) 확인 가능합니다.

이 Transaction hash 값은 향후에 다른 거래의 Input UTXO로 사용할수 있습니다.