비트코인은 UTXO를 이용하여 트랜잭션을 만든다.
Tx
Tx
TxIn[5천원(프동프동)]
TxOut[0원(프동프동), 5천원(A User)]
TX
TxIn[1만원(프동프동)]
TxOut[5천원(A User)/5천원(프동프동)]
Tx
TxIn[$10(blockchain)]
TXOut[$10(miner)]
프동프동이란 사람이 COINBASE로 부터 채굴한 코인을 받는다
Tx
TxIn(소유자 : COINBASE, 가진 코인의 수: 50개)
TxOut(소유자 : 프동프동, 가진 코인의 수 : 50개
func createBlock(prevHash string, height int) *Block {
block := &Block{
Hash: "",
PrevHash: prevHash,
Height: height,
Difficulty: Blockchain().difficulty(),
Nonce: 0,
// 블록 생성 시 채굴자의 이름을 가지고 트랜잭션을 만들고 블록에 포함시킨다.
Transactions: []*Tx{makeCoinbaseTx("fdongfdong")},
}
block.mine()
block.persist()
return block
}
package blockchain
import (
"coin/exam36/utils"
"time"
)
const (
minerReward int = 50
)
type Tx struct {
Id string `json:"id"`
Timestamp int `json:"timestamp"`
TxIns []*TxIn `json:"txins"`
TxOuts []*TxOut `json:"txouts"`
}
func (t *Tx) getId() {
t.Id = utils.Hash(t)
}
type TxIn struct {
Owner string `json:"owner"`
Amount int `json:"amount"`
}
type TxOut struct {
Owner string `json:"owner"`
Amount int `json:"amount"`
}
// 코인베이스에서 채굴자에게 코인을 주기 위해(거래) 트랜잭션을 만든다.
func makeCoinbaseTx(address string) *Tx {
txIns := []*TxIn{
{"COINBASE", minerReward},
}
txOuts := []*TxOut{
{address, minerReward},
}
tx := Tx{
Id: "",
Timestamp: int(time.Now().Unix()),
TxIns: txIns,
TxOuts: txOuts,
}
tx.getId()
return &tx
}
HTTP/1.1 200 OK
Content-Type: application/json
Date: Sat, 31 Dec 2022 05:42:10 GMT
Content-Length: 342
Connection: close
[
{
"hash": "007870047badd28511c43d3b4d8108fd9e346bc89113636ecfabf396dda01541",
"height": 1,
"defficulty": 2,
"nonce": 226,
"timestamp": 1672465330,
"Transactions": [
{
"id": "bebd0536f46ded4f0e2c053c7e002dafb0fd1cc68233f73ae41850dd19b39ed8",
"timestamp": 1672465330,
"txins": [
{
"owner": "COINBASE",
"amount": 50
}
],
"txouts": [
{
"owner": "fdongfdong",
"amount": 50
}
]
}
]
}
]
// 쿼리에 total 값이 true이면 해당하는 address의 자산을 모두 합쳐서 Client에게 보내준다.
func balance(rw http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
address := vars["address"]
total := r.URL.Query().Get("total")
switch total {
case "true":
amount := blockchain.Blockchain().BalanceByAddress(address)
json.NewEncoder(rw).Encode(balanceResponse{address, amount})
default:
utils.HandleErr(json.NewEncoder(rw).Encode(blockchain.Blockchain().TxOutsByAddress(address)))
}
}
func Start(aPort int) {
router := mux.NewRouter()
router.HandleFunc("/balance/{address}", balance).Methods("GET")
fmt.Printf("Listening on http://localhost%s\n", port)
log.Fatal(http.ListenAndServe(port, router))
}
// 블록의 트랜잭션 출력값을 모두 가져오는 함수
func (b *blockchain) txOuts() []*TxOut {
var txOuts []*TxOut
// 모든 블록을 가져온다.
blocks := b.Blocks()
for _, block := range blocks {
// 모든 블록의 TxOuts을 가져온다.
for _, tx := range block.Transactions {
txOuts = append(txOuts, tx.TxOuts...)
}
}
return txOuts
}
// 블록의 트랜잭션 출력값 리스트에서 address에 해당하는 값들만 찾아오는 함수
func (b *blockchain) TxOutsByAddress(address string) []*TxOut {
var ownedTxOuts []*TxOut
txOuts := b.txOuts()
for _, txOut := range txOuts {
if txOut.Owner == address {
ownedTxOuts = append(ownedTxOuts, txOut)
}
}
return ownedTxOuts
}
// 해당하는 address의 자산을 모두 합쳐서 반환하는 함수
func (b *blockchain) BalanceByAddress(address string) int {
txOuts := b.TxOutsByAddress(address)
var amount int
for _, txOut := range txOuts {
amount += txOut.Amount
}
return amount
}
Method : GET
기능 : 해당하는 address에 모든 자산을 합쳐서 가져온다.
HTTP/1.1 200 OK
Content-Type: application/json
Date: Sat, 31 Dec 2022 09:08:43 GMT
Content-Length: 39
Connection: close
{
"address": "fdongfdong",
"balance": 100
}
Method : GET
기능 : 각각의 트랜잭션 출력값을 가져온다.
HTTP/1.1 200 OK
Content-Type: application/json
Date: Sat, 31 Dec 2022 09:08:53 GMT
Content-Length: 72
Connection: close
[
{
"owner": "fdongfdong",
"amount": 50
},
{
"owner": "fdongfdong",
"amount": 50
}
]