Skip to content

Latest commit

ย 

History

History
139 lines (106 loc) ยท 6.43 KB

File metadata and controls

139 lines (106 loc) ยท 6.43 KB

Web API/ Block Explorer {#web-api}

์ผ๋ฐ˜์ ์œผ๋กœ ๋ธ”๋ก ํƒ์ƒ‰๊ธฐ(block explorers)๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์›น API๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ข€๋” ๋น ๋ฅด๊ฒŒ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ฑ…์—์„œ ์ด๋ฏธ QBitNinja๋ฅผ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ ๋” ๋งŽ์ด ์‚ฌ์šฉ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋ธ”๋กํƒ์ƒ‰๊ธฐ๋Š” ์ฒด์ธ์˜ ๋ธ”๋ก, ํŠธ๋žœ์ ์…˜ ๋ฐ ์ฃผ์†Œ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋Š” ์ž์ฒด ํ˜ธ์ŠคํŒ… ๋˜๋Š” ํƒ€์‚ฌ ํ˜ธ์ŠคํŒ… ์†”๋ฃจ์…˜์ž…๋‹ˆ๋‹ค.

Explorer

๋ธ”๋ก ํƒ์ƒ‰๊ธฐ๋Š” ๋น„ํŠธ ์ฝ”์ธ ๋…ธ๋“œ์— ์—ฐ๊ฒฐํ•˜๊ณ  ๋ธ”๋ก ์ฒด์ธ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ธ๋ฑ์‹ฑํ•˜๊ณ  ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฌ์šด API๋ฅผ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์†”๋ฃจ์…˜์—๋Š” QBitNinja, Blockcypher, Smartbit, Electrum server, Insight, NBXplorer๋“ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์žฅ์ :

  • Bitcoin Core RPC๋ณด๋‹ค ๋” ์ข‹์€ API,
  • ๋” ๋งŽ์€ ๋ถ€ํ•˜(load)๋ฅผ ์ฒ˜๋ฆฌ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋งŽ์€ ์ˆ˜์˜ ์ง€๊ฐ‘์„ ์ง€์›ํ•˜๊ณ  ๋™์ ์œผ๋กœ ์ถ”๊ฐ€ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋น ๋ฅธ ํด๋ผ์ด์–ธํŠธ-์„œ๋ฒ„ ์•„ํ‚คํ…์ฒ˜

๋‹จ์ :

  • ํƒ€์‚ฌ์—์„œ ํ˜ธ์ŠคํŒ… ๋˜๋Š” ๋ฌธ์ œ์žˆ๋Š” ํฌํฌ(fork)๊ฐ€ ๋ฐœ๊ฒฌ๋œ ๊ฒฝ์šฐ ํฌํฌ(fork) ์„ ํƒ๊ถŒ์ด ์—†์Šต๋‹ˆ๋‹ค.
  • ๋•Œ๋กœ๋Š”, ๊ทธ๋“ค์˜ ์„œ๋น„์Šค๊ฐ€ ์ „์ฒด ์ง€๊ฐ‘์— ํ•„์š”ํ•œ ๋ชจ๋“  ๊ฒƒ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ์— ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฐœ์ธ์ •๋ณด: ์„œ๋ฒ„๋Š” ํด๋ผ์ด์–ธํŠธ์— ๋Œ€ํ•œ ๋ชจ๋“  ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ž์ฒด ํ˜ธ์ŠคํŒ… ์œ ํ˜•์—๋Š” ์ ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์„œ๋กœ ๋‹ค๋ฅธ ๋ธ”๋ก ํƒ์ƒ‰๊ธฐ๋Š” ๋‹ค๋ฅธ API์™€ ๊ธฐ๋Šฅ์„ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋Œ€๋ถ€๋ถ„์˜ ๋ธ”๋ก ํƒ์ƒ‰๊ธฐ๋Š” HTTP ์›น API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ˜๋ฉด Electrum์€ the Stratum ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋ธ”๋ก ํƒ์ƒ‰๊ธฐ๋Š” ์ง€๊ฐ‘์˜ ๊ฐœ์ธ ํ‚ค๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

QBitNinja์—์„œ๋Š” ํ•ญ์ƒ ์ฃผ์†Œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ์ง€๊ฐ‘์ธ ๊ฒฝ์šฐ ์ถ”์ ํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ๋™์ผํ•œ ์ง€๊ฐ‘์— ์†ํ•œ ๋ชจ๋“  ์ฃผ์†Œ๋ฅผ ํด๋งํ•˜์—ฌ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๊ฐ์ง€ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ Electrum ๋˜๋Š”NBXplorer ๋ฐ SmartBit์€ ์›น์†Œ์ผ“(websockets) ๋˜๋Š” ๋กฑํด๋ง(long polling)์„ ํ†ตํ•ด ์•Œ๋ฆผ์„ ๋…ธ์ถœํ•˜๋ฏ€๋กœ ์ง€๊ฐ‘์˜ ๋ชจ๋“  ์ฃผ์†Œ๋ฅผ ํด๋ง ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. Insight๊ฐ€ ์ž˜ ์œ ์ง€๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Blockcypher,QBitNinja ๋ฐ Smartbit๋Š” ํƒ€์‚ฌ์—์„œ ํ˜ธ์ŠคํŒ…๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฐฉ์‹์œผ๋กœ ์ง€๊ฐ‘์„ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐ ๊ด€์‹ฌ์ด ์žˆ๋‹ค๋ฉด nopara73์˜ CodeProject ๊ธฐ์‚ฌ๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค: Build your own Bitcoin wallet with QBitNinja in C#

NBxplorer๋Š” ๋งค์šฐ ๊ฐ„๋‹จํ•œ API๋ฅผ ๊ฐ–๋„๋ก ๋งŒ๋“ค์–ด์กŒ์œผ๋ฉฐ, ์ž์ฒด ํ˜ธ์ŠคํŒ…์ด ๊ฐ€๋Šฅํ•˜๋ฉฐ, ์ง€๊ฐ‘์— ํ•„์š”ํ•œ ๊ฒƒ๋งŒ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค. QBitNinja์™€๋Š” ๋‹ฌ๋ฆฌ ํ’€๋…ธ๋“œ(full node)๊ฐ€ ์žˆ์–ด์•ผ ํ•˜์ง€๋งŒ, ์›น์†Œ์ผ“ ์•Œ๋ฆผ์„ ์ œ๊ณตํ•˜๊ณ , ์ง€๊ฐ‘ ์ž”์•ก์„ ์‰ฝ๊ฒŒ ์กฐํšŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

NBXplorer๋Š” ๋˜ํ•œ ๋‹จ์ผ ์„œ๋ฒ„์—์„œ ๋‹ค์ค‘ ์•”ํ˜ธํ™” ํ†ตํ™”์ž…๋‹ˆ๋‹ค. 2018 ๋…„ 10 ์›” ํ˜„์žฌ ๋น„ํŠธ ์ฝ”์ธ, ๋ผ์ดํŠธ ์ฝ”์ธ, BCash, BGold, Dash, Dogecoin, Dystem, Feathercoin, Groestlcoin, Monacoin, Polis, UFO, Viacoin ๋ฐ Zclassic๋ฅผ ์ง€์› ํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ, 'NBitcoin'๊ณผ ์›ํ™œํ•˜๊ฒŒ ํ†ตํ•ฉ๋ฉ๋‹ˆ๋‹ค.

NBXplorer๋ฅผ ์„ค์ •ํ•˜๋ ค๋ฉด ๊ธฐ๋ณธ ๋งค๊ฐœ ๋ณ€์ˆ˜๊ฐ€ ์žˆ๋Š” ์™„์ „ํžˆ ๋™๊ธฐํ™” ๋œ bitcoind ๋…ธ๋“œ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ๊ธฐ๋ณธ ๋งค๊ฐœ ๋ณ€์ˆ˜๋กœ NBXplorer๋ฅผ ๋ณต์ œํ•˜๊ณ  ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

NBXplorer.Client nuget package๋ฅผ ์ฐธ์กฐํ•œ ๋‹ค์Œ NBXplorer์— ์‚ฌ์šฉ์ž ์ง€๊ฐ‘์„ ์ถ”์ ํ•˜๋„๋ก ์•Œ๋ ค์•ผํ•ฉ๋‹ˆ๋‹ค:

var network = new NBXplorerNetworkProvider(NetworkType.Mainnet).GetBTC();
var userExtKey = new ExtKey();
var userDerivationScheme = network.DerivationStrategyFactory.CreateDirectDerivationStrategy(userExtKey.Neuter(), new DerivationStrategyOptions()
{
	// Use non-segwit
	Legacy = true
});
ExplorerClient client = new ExplorerClient(network);
client.Track(userDerivationScheme);

Testnet ๋˜๋Š” Regtest๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด NetworkType.Mainnet ๋ฌธ์žฅ์„ ๋ณ€๊ฒฝํ•˜์‹ญ์‹œ์˜ค.

์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ์ƒˆ ์ฃผ์†Œ๋ฅผ ์›ํ•˜๋Š” ๊ฒฝ์šฐ:

Console.WriteLine(client.GetUnused(userDerivationScheme, DerivationFeature.Deposit).Address);

๊ทธ๋Ÿฐ ๋‹ค์Œ ์‚ฌ์šฉ์ž์˜ UTXO๋ฅผ ์ฟผ๋ฆฌํ•˜๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

var utxos = client.GetUTXOs(userDerivationScheme, null, false);

ํ•ด๋‹น UTXO๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด:

var coins = utxos.GetUnspentCoins();
var keys = utxos.GetKeys(userExtKey);
TransactionBuilder builder = Network.Main.CreateTransaction();
builder.AddCoins(coins);
builder.AddKeys(keys);
builder.Send(new Key(), Money.Coins(0.5m));
builder.SetChange(changeAddress.ScriptPubKey);

// Set the fee rate
var fallbackFeeRate = new FeeRate(Money.Satoshis(100), 1);
var feeRate = tester.Client.GetFeeRate(1, fallbackFeeRate).FeeRate;
builder.SendEstimatedFees(feeRate);
/////

var tx = builder.BuildTransaction(true);
Console.WriteLine(client.Broadcast(tx));

์ด ์†”๋ฃจ์…˜์˜ ๋ฌธ์ œ์ ์€ ๋™์‹œ์— ๋‘๋ฒˆ ํ˜ธ์ถœํ•˜๋ฉด, ๋™์ผํ•œ ์ฝ”์ธ์„ ์†Œ๋น„ํ•˜๋Š” ๋‘ ๊ฐœ์˜ ํŠธ๋žœ์žญ์…˜์„ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…ํ•˜๋ฉด, ํŠธ๋žœ์žญ์…˜ ์ค‘ ํ•˜๋‚˜๊ฐ€ ์‚ญ์ œ๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€ํ•˜๋ ค๋ฉด ๋™์ผํ•œ ๋™์ „์„ ๋‘ ๋ฒˆ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋„๋กํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๊ฐ„๋‹จํžˆ ์žฌ ์‹œ๋„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค:

while(true)
{    
    var coins = utxos.GetUnspentCoins();
    var keys = utxos.GetKeys(userExtKey);
    TransactionBuilder builder = Network.Main.CreateTransactionBuilder();
    builder.AddCoins(coins);
    builder.AddKeys(keys);
    builder.Send(new Key(), Money.Coins(0.5m));
    builder.SetChange(changeAddress.ScriptPubKey);

    // Set the fee rate
    var fallbackFeeRate = new FeeRate(Money.Satoshis(100), 1);
    var feeRate = tester.Client.GetFeeRate(1, fallbackFeeRate).FeeRate;
    builder.SendEstimatedFees(feeRate);
    /////

    var tx = builder.BuildTransaction(true);
    var result = client.Broadcast(tx);
    if(result.Success)
    {
        Console.WriteLine("Success!");
        break;
    }
    else if(result.RPCCode.HasValue && result.RPCCode.Value == RPCErrorCode.RPC_TRANSACTION_REJECTED)
    {
        Console.WriteLine("We probably got a conflict, let's try again!");
        continue;
    }
    else
    {
        Console.WriteLine($"Something is really wrong {result.RPCCode} {result.RPCCodeMessage} {result.RPCMessage}");
        // Do something!!!
    }
}

๋˜ ๋‹ค๋ฅธ ์ผ๋ฐ˜์ ์ธ ๋ฐฉ๋ฒ•์€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ์ด๋ฏธ ์‚ฌ์šฉ ๋œ ์•„์›ƒํฌ์ธํŠธ(outpoint)์˜ ์ „์ฒด ๋ชฉ๋ก์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.