TIL 30 - Golang으로 블록체인 만들기(트랜잭션 구축하기) 11

프동프동·2023년 2월 10일
0

TIL

목록 보기
30/46
post-thumbnail

트랜잭션 구축

비트코인은 UTXO를 이용하여 트랜잭션을 만든다.

Tx

  • TxIn[] : 거래를 실행하기 이전에 내 주머니에 있는 돈
  • TxOut[] : 거래가 끝났을 때 각각의 사람들이 갖고있는 액수
Tx
	TxIn[5천원(프동프동)]
	TxOut[0(프동프동), 5천원(A User)]
  • 만약 5천원을 주고싶은데 1만원 지폐로 가지고 있을 경우
TX
	TxIn[1만원(프동프동)]
	TxOut[5천원(A User)/5천원(프동프동)]
  • 채굴자(코인베이스의 거래)가 코인을 딱 채굴했을 시 상태
    • 채굴자가 코인을 채굴했을 시 Input값은 블록체인이다.
    • Output 값은 채굴자다.
Tx
	TxIn[$10(blockchain)]
	TXOut[$10(miner)]

코인베이스에서 채굴자에게 코인을 주도록 만들고 트랜잭션에 기록하기

  • 시나리오
    • 블록 생성 시(채굴 시)
      • 프동프동이란 사람이 COINBASE로 부터 채굴한 코인을 받는다

        Tx 
        	TxIn(소유자 : COINBASE, 가진 코인의 수: 50)
        	TxOut(소유자 : 프동프동, 가진 코인의 수 : 50
  • 소스 코드
    • blockchain/block.go
      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
      }
    • transaction/transaction.go
      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
                }
              ]
            }
          ]
        }
      ]

보유한 자산 조회하기

  • 트랜잭션에 포함된 owner로 자산 조회하기
  • RESTful하게 가져오기
  • 소스 코드
    • main.go
      
      // 쿼리에 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))
      }
    • blockchain/chain.go
      // 블록의 트랜잭션 출력값을 모두 가져오는 함수
      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
      }
  • 실행 결과
    • 쿼리로 total을 줬을 때
      • Method : GET

      • URL : http://localhost:4000/balance/fdongfdong?total=true

      • 기능 : 해당하는 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

      • URL : http://localhost:4000/balance/fdongfdong

      • 기능 : 각각의 트랜잭션 출력값을 가져온다.

        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
          }
        ]
profile
좋은 개발자가 되고싶은

0개의 댓글