(Mastering Bitcoin) 트랜잭션은 비트코인 시스템에서 가장 중요한 부분입니다. 비트코인의 나머지 기능은 거래가 생성되고, 네트워크에서 전파되고, 검증되고, 최종적으로 전체 거래원장(블록체인)에 추가되도록 설계되었습니다. 트랜잭션은 비트코인 시스템 참가자 간에 가치를 전달하기 위한 인코딩된 데이터 구조입니다. 각 거래는 복식부기 원장인 블록체인에 공개적으로 기록됩니다.
트랜잭션은 수신자가 없거나 혹은 여러 명일 수도 있습니다. 발신자도 마찬가지입니다!
블록체인에서 발신자와 수신자는 이전 장에서 설명한 것처럼 항상 ScriptPubKey로 추상화됩니다.
Bitcoin Core를 사용하는 경우 거래 탭에 다음과 같은 거래가 표시됩니다:
Transaction ID를 주목하세요. 이 경우 거래ID는 f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94입니다.
Note: 트랜잭션 ID는 "SHA256(SHA256(txbytes))"로 정의할 수 있습니다.
Note: 승인되지 않은 거래(unconfirmed)를 처리하기 위해 Transaction ID를 사용하지 마세요.
Transaction ID는 승인(confirmed)되기 전에 조작할 수 있습니다.
이를 "거래 가단성"이라고 합니다.
Blockchain.info 같은 블록 탐색기를 이용하면 트랜잭션을 확인 할 수 있습니다: https://blockchain.info/tx/f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94
그러나 개발자로서 우리는 더 쉽게 쿼리를 실행하거나 구문을 분석할 수 있는 서비스를 원합니다.
C# 개발자이자 NBitcoin 사용자인 Nicolas Dorier의 QBit Ninja가 최적의 선택일 겁니다.
블록체인을 조회하고 지갑을 추적하기 위한 오픈소스 웹 서비스 API입니다.
QBit Ninja는 Microsoft Azure Storage를 기반으로 하는 NBitcoin.Indexer에 의존하고 있습니다.
C# 개발자는 이 API의 래퍼를 직접 개발하는 대신 클라이언트 라이브러리인 NuGet client package를 사용하는 것을 추천 합니다.
http://api.qbit.ninja/transactions/f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94 에 접속하면 트랜잭션의 내용을 볼 수 있습니다.
다음 코드를 사용하면 16진수(hex) 표현의 트랜잭션을 해석할 수 있습니다:
Transaction tx = Transaction.Parse("0100000...", Network.Main);손발이 떨리기 전에 탭을 닫고, 다음 진행을 위해 QBit Ninja가 API를 쿼리하고 정보를 파싱하도록 만든 QBitNinja.Client NuGet 패키지를 설치합니다.
다음과 같이 사용합니다.
using QBitNinja.Client;
using QBitNinja.Client.Models;id를 이용해 트랜잭션을 쿼리합니다:
// Create a client
QBitNinjaClient client = new QBitNinjaClient(Network.Main);
// Parse transaction id to NBitcoin.uint256 so the client can eat it
var transactionId = uint256.Parse("f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94");
// Query the transaction
GetTransactionResponse transactionResponse = client.GetTransaction(transactionId).Result;transactionResponse의 형식은 GetTransactionResponse입니다.
QBitNinja.Client.Models 네임스페이스에 있습니다.
transactionResponse로 NBitcoin.Transaction 타입을 얻을 수 있습니다:
NBitcoin.Transaction transaction = transactionResponse.Transaction;두 클래스를 사용하여 트랜잭션 ID를 반환하는 예를 살펴 보겠습니다:
Console.WriteLine(transactionResponse.TransactionId); // f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94
Console.WriteLine(transaction.GetHash()); // f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94GetTransactionResponse에는 트랜잭션에 사용되는 입력 값 및 scriptPubKey와 같은 트랜잭션에 대한 추가 정보가 있습니다.
현재 관련 부분은 입력(inputs) 과 출력(outputs) 입니다.
우리 트랜잭션에는 하나의 출력만 있음을 알 수 있습니다. 13.19683492 비트코인은 해당 ScriptPubKey로 전송됩니다.
List<ICoin> receivedCoins = transactionResponse.ReceivedCoins;
foreach (var coin in receivedCoins)
{
Money amount = (Money) coin.Amount;
Console.WriteLine(amount.ToDecimal(MoneyUnit.BTC));
var paymentScript = coin.TxOut.ScriptPubKey;
Console.WriteLine(paymentScript); // It's the ScriptPubKey
var address = paymentScript.GetDestinationAddress(Network.Main);
Console.WriteLine(address); // 1HfbwN6Lvma9eDsv7mdwp529tgiyfNr7jc
Console.WriteLine();
}QBitNinja의 GetTransactionResponse 클래스를 사용하여 RECEIVED COINS에 대한 정보를 작성했습니다.
Exercise: QBitNinja의 GetTransactionResponse 클래스를 사용하여 SPENT COINS에 대한 동일한 정보를 작성해보세요!
NBitcoin의 Transaction 클래스를 사용하여 RECEIVED COINS에 대해 동일한 정보를 얻는 방법을 살펴보겠습니다.
var outputs = transaction.Outputs;
foreach (TxOut output in outputs)
{
Money amount = output.Value;
Console.WriteLine(amount.ToDecimal(MoneyUnit.BTC));
var paymentScript = output.ScriptPubKey;
Console.WriteLine(paymentScript); // It's the ScriptPubKey
var address = paymentScript.GetDestinationAddress(Network.Main);
Console.WriteLine(address);
Console.WriteLine();
}이제 inputs을 살펴보겠습니다.
그것을 들여다 보면 이전 출력이 참조된 것을 알 수 있습니다.
각 입력들은 거래에 자금을 사용하기 위해 어떤 출력을 사용하고 있는지를 보여줍니다.
var inputs = transaction.Inputs;
foreach (TxIn input in inputs)
{
OutPoint previousOutpoint = input.PrevOut;
Console.WriteLine(previousOutpoint.Hash); // hash of prev tx
Console.WriteLine(previousOutpoint.N); // idx of out from prev tx, that has been spent in the current tx
Console.WriteLine();
}TxOut, Output 및 out 용어는 동의어입니다.
OutPoint와 혼동하지 말아야 합니다, 나중에 좀 더 자세히 설명하겠습니다.
요약하자면, TxOut은 비트코인의 양과 ScriptPubKey를 나타냅니다. (수신측)
그림처럼 현재 트랜잭션의 첫 번째 ScriptPubKey에서 21 비트코인으로 txout을 생성 해 보겠습니다:
Money twentyOneBtc = new Money(21, MoneyUnit.BTC);
var scriptPubKey = transaction.Outputs[0].ScriptPubKey;
TxOut txOut = transaction.Outputs.CreateNewTxOut(twentyOneBtc, scriptPubKey);모든 TxOut 은 블록체인 수준에서 이를 포함하는 트랜잭션의 ID와 내부 인덱스에 의해 고유하게 처리됩니다. 이러한 참조를 Outpoint라고 합니다.
예를 들어, 거래에서 13.19683492 BTC가 있는 TxOut의 Outpoint는 (f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94, 0)입니다.
OutPoint firstOutPoint = receivedCoins[0].Outpoint;
Console.WriteLine(firstOutPoint.Hash); // f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94
Console.WriteLine(firstOutPoint.N); // 0이제 트랜잭션의 입력(일명 TxIn)을 자세히 살펴 보겠습니다:
TxIn은 TxOut의 Outpoint, 혹은 소비 될 ScriptSig로 구성됩니다(ScriptSig를 "소유권 증명(Proof of Ownership)"으로 볼 수 있음).
우리 거래에는 실제로 9개의 입력이 있습니다.
Console.WriteLine(transaction.Inputs.Count); // 9이전 outpoint의 트랜잭션 ID를 사용하여 해당 트랜잭션과 관련된 정보를 검토할 수 있습니다.
OutPoint firstPreviousOutPoint = transaction.Inputs[0].PrevOut;
var firstPreviousTransaction = client.GetTransaction(firstPreviousOutPoint.Hash).Result.Transaction;
Console.WriteLine(firstPreviousTransaction.IsCoinBase); // False우리는 채굴자가 새로 채굴한 코인을 포함하는 coinbase transaction에 도달 할 때까지 이러한 방식으로 트랜잭션 ID를 계속 추적할 수 있습니다.
Exercise: 코인베이스 거래를 찾을 때까지 해당 거래와 그 조상의 첫 번째 input을 따라가보세요.
Hint: 많은 단계가 있으므로 1~2분 정도 걸릴 수 있지만 인내심을 가지세요!
네, 맞습니다. 가장 효율적인 방법은 아니지만 좋은 연습입니다.
이 예시에서 출력은 총 13.19683492 BTC입니다.
Money spentAmount = Money.Zero;
var spentCoins = transactionResponse.SpentCoins;
foreach (var spentCoin in spentCoins)
{
spentAmount = (Money)spentCoin.Amount.Add(spentAmount);
}
Console.WriteLine(spentAmount.ToDecimal(MoneyUnit.BTC)); // 13.19703492이 거래에서는 13.19703492 BTC가 수신되었습니다.
Exercise: 지출 금액으로 한 것 처럼 총 수령 금액을 가져옵니다.
이는 0.0002 BTC (또는 13.19703492 - 13.19683492)가 계산되지 않음을 의미합니다!
입력과 출력의 차이를 거래 수수료(Transaction Fees) 또는 채굴 수수료(Miner’s Fees)라고 합니다.
이것은 채굴자가 수집한 거래를 주어진 블록에 포함시킨 금액입니다.
var fee = transaction.GetFee(spentCoins.ToArray());
Console.WriteLine(fee);coinbase transaction은 총 output이 전체 input보다 큰 유일한 트랜잭션입니다.
이것은 코인 생성을 위한 효과적인 방법입니다.
따라서 정의에 따라 코인베이스 거래에는 수수료가 없습니다.
코인베이스 트랜잭션은 모든 블록의 첫 번째 트랜잭션입니다.
합의 규칙은 코인베이스 거래에서 산출물 가치의 합계가 채굴 보상(보조금과 블록의 거래 수수료 합계)을 초과하지 않도록 강제합니다.





