Transaction.go

package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"time"
)

// Configurations and Constants
const (
	TimestampErrorLimit = 300 // μ˜ˆμ‹œ κ°’, μ‹€μ œ κ°’μœΌλ‘œ λ³€κ²½
	ResultFail          = "FAIL"
)

// Mocked configuration structure
var Config = struct {
	Database bool
}{
	Database: true, // μ‹€μ œ 섀정에 맞게 λ³€κ²½
}

// Mocked utility functions and structures for demonstration purposes
func Utime() int64 {
	return time.Now().Unix()
}

func SignatureValidity(data int64, publicKey, signature string) bool {
	// μ‹€μ œ μ„œλͺ… μœ νš¨μ„± 검사 둜직 κ΅¬ν˜„
	return true
}

func HashValidity(cid string) bool {
	// μ‹€μ œ ν•΄μ‹œ μœ νš¨μ„± 검사 둜직 κ΅¬ν˜„
	return true
}

func AddressValidity(address string) bool {
	// μ‹€μ œ μ£Όμ†Œ μœ νš¨μ„± 검사 둜직 κ΅¬ν˜„
	return true
}

func TimeHashValidity(timehash string) bool {
	// μ‹€μ œ μ‹œκ°„ ν•΄μ‹œ μœ νš¨μ„± 검사 둜직 κ΅¬ν˜„
	return true
}

// TransactionHandler handles the transactions.
type TransactionHandler struct{}

func (t *TransactionHandler) Fail(w http.ResponseWriter, result, errMsg string) {
	http.Error(w, fmt.Sprintf("%s: %s", result, errMsg), http.StatusBadRequest)
}

func (t *TransactionHandler) Main(w http.ResponseWriter, req *http.Request) {
	if !Config.Database {
		t.Fail(w, ResultFail, "The database usage setting is set to false.")
		return
	}

	now := Utime()
	timestampStr := req.FormValue("timestamp")
	timestamp, err := strconv.ParseInt(timestampStr, 10, 64)
	if err != nil {
		t.Fail(w, ResultFail, "Invalid timestamp.")
		return
	}
	publicKey := req.FormValue("public_key")
	signature := req.FormValue("signature")

	timeValidity := abs(now-timestamp) < TimestampErrorLimit
	signatureValidity := SignatureValidity(timestamp, publicKey, signature)

	if !timeValidity || !signatureValidity {
		t.Fail(w, ResultFail, "Invalid request.")
		return
	}

	data := req.FormValue("data")
	switch data {
	case "get":
		response := t.GetTransaction(req)
		json.NewEncoder(w).Encode(response)
	case "list":
		fallthrough
	default:
		response := t.ListTransaction(req, false)
		json.NewEncoder(w).Encode(response)
	case "fullList":
		response := t.ListTransaction(req, true)
		json.NewEncoder(w).Encode(response)
	}
}

func (t *TransactionHandler) ListTransaction(req *http.Request, full bool) []map[string]interface{} {
	pageStr := req.FormValue("page")
	page, _ := strconv.Atoi(pageStr)
	countStr := req.FormValue("count")
	count, _ := strconv.Atoi(countStr)

	cid := req.FormValue("cid")
	typ := req.FormValue("type")
	address := req.FormValue("address")
	from := req.FormValue("from")
	to := req.FormValue("to")
	timehash := req.FormValue("timehash")

	query := map[string]string{}

	if HashValidity(cid) {
		query["cid"] = cid
	}
	if match, _ := regexp.MatchString(`^[A-Za-z_0-9]+$`, typ); match {
		query["type"] = typ // μ‹€μ œλ‘œλŠ” SQL μΈμ μ…˜ λ°©μ§€λ₯Ό μœ„ν•΄ proper escaping ν•„μš”
	}
	if AddressValidity(address) {
		query["address"] = address
	}
	if AddressValidity(from) {
		query["from"] = from
	}
	if AddressValidity(to) {
		query["to"] = to
	}
	if TimeHashValidity(timehash) {
		query["timehash"] = timehash
	}

	chainDB := ChainDB{}
	return chainDB.ListData(page, count, query, full)
}

func (t *TransactionHandler) GetTransaction(req *http.Request) map[string]interface{} {
	target := req.FormValue("target")
	if target == "" {
		target = "05df2656734c9e326b71a0d256e39c01054f89f83027c7179fd9fe942a0d6270875c2d16f41732"
	}

	mainChain := MainChainInstance()
	return mainChain.Transaction(target)
}

// ChainDB is a mocked structure for demonstration purposes
type ChainDB struct{}

func (db *ChainDB) ListData(page, count int, query map[string]string, full bool) []map[string]interface{} {
	// μ‹€μ œ λ°μ΄ν„°λ² μ΄μŠ€ 쿼리 둜직 κ΅¬ν˜„
	return []map[string]interface{}{
		{"example_key": "example_value"},
	}
}

// MainChain is a mocked structure for demonstration purposes
type MainChain struct{}

func MainChainInstance() *MainChain {
	return &MainChain{}
}

func (mc *MainChain) Transaction(target string) map[string]interface{} {
	// μ‹€μ œ νŠΈλžœμž­μ…˜ 쑰회 둜직 κ΅¬ν˜„
	return map[string]interface{}{
		"transaction_key": "transaction_value",
	}
}

func abs(x int64) int64 {
	if x < 0 {
		return -x
	}
	return x
}

func main() {
	http.HandleFunc("/transaction", func(w http.ResponseWriter, req *http.Request) {
		handler := &TransactionHandler{}
		handler.Main(w, req)
	})

	http.ListenAndServe(":8080", nil)
}

μ£Όμš” ꡬ성 μš”μ†Œμ™€ ν•¨μˆ˜

ν•„μš”ν•œ νŒ¨ν‚€μ§€ 및 μƒμˆ˜

  1. νŒ¨ν‚€μ§€ μž„ν¬νŠΈ:

    • encoding/json: JSON 데이터λ₯Ό μ²˜λ¦¬ν•©λ‹ˆλ‹€.

    • fmt: 포맷된 λ¬Έμžμ—΄μ„ μ²˜λ¦¬ν•©λ‹ˆλ‹€.

    • net/http: HTTP μ„œλ²„μ™€ ν΄λΌμ΄μ–ΈνŠΈλ₯Ό μ²˜λ¦¬ν•©λ‹ˆλ‹€.

    • strconv: λ¬Έμžμ—΄μ„ 숫자둜 λ³€ν™˜ν•˜λŠ” κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€.

    • time: μ‹œκ°„ κ΄€λ ¨ κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€.

  2. μƒμˆ˜ μ •μ˜:

λͺ¨μ˜ ꡬ성 및 ν•¨μˆ˜

이 μ˜ˆμ œμ—μ„œλŠ” μ‹€μ œ κ΅¬ν˜„ λŒ€μ‹  λͺ¨μ˜(mocked) ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. μ΄λŸ¬ν•œ λͺ¨μ˜ ν•¨μˆ˜λŠ” μ‹€μ œ μ‹œμŠ€ν…œμ—μ„œ κ΅¬ν˜„λ  ν•¨μˆ˜μ™€ μœ μ‚¬ν•˜κ²Œ λ™μž‘ν•©λ‹ˆλ‹€.

TransactionHandler ꡬ쑰체와 κ΄€λ ¨ ν•¨μˆ˜

이 뢀뢄은 HTTP μš”μ²­μ„ μ²˜λ¦¬ν•˜λŠ” 핡심 λ‘œμ§μž…λ‹ˆλ‹€.

  • Fail ν•¨μˆ˜: 이 ν•¨μˆ˜λŠ” μš”μ²­μ΄ μ‹€νŒ¨ν–ˆμ„ λ•Œ ν΄λΌμ΄μ–ΈνŠΈμ— μ‹€νŒ¨ λ©”μ‹œμ§€λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.

    • w: 응닡을 μž‘μ„±ν•˜λŠ” 데 μ‚¬μš©λ˜λŠ” http.ResponseWriter κ°μ²΄μž…λ‹ˆλ‹€.

    • result: κ²°κ³Ό λ¬Έμžμ—΄μž…λ‹ˆλ‹€.

    • errMsg: 였λ₯˜ λ©”μ‹œμ§€μž…λ‹ˆλ‹€.

  • Main ν•¨μˆ˜: 이 ν•¨μˆ˜λŠ” /transaction 경둜둜 λ“€μ–΄μ˜€λŠ” μš”μ²­μ„ μ²˜λ¦¬ν•©λ‹ˆλ‹€.

    • λ°μ΄ν„°λ² μ΄μŠ€ 섀정이 true인지 ν™•μΈν•©λ‹ˆλ‹€. false인 경우 μ‹€νŒ¨ 응닡을 λ°˜ν™˜ν•©λ‹ˆλ‹€.

    • ν˜„μž¬ μ‹œκ°„μ„ now λ³€μˆ˜μ— μ €μž₯ν•©λ‹ˆλ‹€.

    • μš”μ²­μ—μ„œ timestamp, public_key, signature 값을 μ½μŠ΅λ‹ˆλ‹€.

    • timestamp 값을 숫자둜 λ³€ν™˜ν•©λ‹ˆλ‹€.

    • ν˜„μž¬ μ‹œκ°„κ³Ό νƒ€μž„μŠ€νƒ¬ν”„μ˜ 차이가 ν—ˆμš© 였차 λ²”μœ„ 내에 μžˆλŠ”μ§€(timeValidity) ν™•μΈν•˜κ³ , μ„œλͺ…이 μœ νš¨ν•œμ§€(signatureValidity) ν™•μΈν•©λ‹ˆλ‹€.

    • μœ νš¨ν•˜μ§€ μ•Šμ€ 경우 μ‹€νŒ¨ 응닡을 λ°˜ν™˜ν•©λ‹ˆλ‹€.

    • μš”μ²­μ˜ data 값에 따라 νŠΈλžœμž­μ…˜ 데이터λ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•©λ‹ˆλ‹€.

  • ListTransaction ν•¨μˆ˜: 이 ν•¨μˆ˜λŠ” μš”μ²­λœ 쑰건에 따라 νŠΈλžœμž­μ…˜ λͺ©λ‘μ„ λ°˜ν™˜ν•©λ‹ˆλ‹€.

    • μš”μ²­μ—μ„œ page, count, cid, type, address, from, to, timehash 값을 μ½μŠ΅λ‹ˆλ‹€.

    • 각 값을 μœ νš¨μ„± 검사 ν•¨μˆ˜λ‘œ ν™•μΈν•˜κ³ , μœ νš¨ν•œ 경우 query 맡에 μΆ”κ°€ν•©λ‹ˆλ‹€.

    • ChainDB의 ListData λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ νŠΈλžœμž­μ…˜ λͺ©λ‘μ„ λ°˜ν™˜ν•©λ‹ˆλ‹€.

  • GetTransaction ν•¨μˆ˜: 이 ν•¨μˆ˜λŠ” νŠΉμ • νŠΈλžœμž­μ…˜μ„ μ‘°νšŒν•˜μ—¬ λ°˜ν™˜ν•©λ‹ˆλ‹€.

    • μš”μ²­μ—μ„œ target 값을 μ½μŠ΅λ‹ˆλ‹€. 값이 μ—†μœΌλ©΄ κΈ°λ³Έ 값을 μ‚¬μš©ν•©λ‹ˆλ‹€.

    • MainChain μΈμŠ€ν„΄μŠ€λ₯Ό μ‚¬μš©ν•˜μ—¬ target에 ν•΄λ‹Ήν•˜λŠ” νŠΈλžœμž­μ…˜μ„ μ‘°νšŒν•˜μ—¬ λ°˜ν™˜ν•©λ‹ˆλ‹€.

λͺ¨μ˜ λ°μ΄ν„°λ² μ΄μŠ€ 및 메인 체인 ꡬ쑰체

  • ChainDB: νŠΈλžœμž­μ…˜ λͺ©λ‘μ„ λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜κ°€ ν¬ν•¨λœ λͺ¨μ˜ λ°μ΄ν„°λ² μ΄μŠ€ κ΅¬μ‘°μ²΄μž…λ‹ˆλ‹€.

  • MainChain: νŠΉμ • νŠΈλžœμž­μ…˜μ„ μ‘°νšŒν•˜λŠ” ν•¨μˆ˜κ°€ ν¬ν•¨λœ λͺ¨μ˜ 메인 체인 κ΅¬μ‘°μ²΄μž…λ‹ˆλ‹€.

보쑰 ν•¨μˆ˜

  • abs ν•¨μˆ˜: μ£Όμ–΄μ§„ 숫자의 μ ˆλŒ€κ°’μ„ λ°˜ν™˜ν•©λ‹ˆλ‹€.

main ν•¨μˆ˜

  • main ν•¨μˆ˜: HTTP μ„œλ²„λ₯Ό μ„€μ •ν•˜κ³  μ‹œμž‘ν•˜λŠ” ν•¨μˆ˜μž…λ‹ˆλ‹€.

    • /transaction 경둜둜 λ“€μ–΄μ˜€λŠ” μš”μ²­μ„ TransactionHandler ꡬ쑰체의 Main λ©”μ„œλ“œλ‘œ μ²˜λ¦¬ν•˜λ„λ‘ μ„€μ •ν•©λ‹ˆλ‹€.

    • 포트 8080μ—μ„œ HTTP μ„œλ²„λ₯Ό μ‹œμž‘ν•©λ‹ˆλ‹€.

μš”μ•½

이 μ½”λ“œλŠ” HTTP μ„œλ²„λ₯Ό μ„€μ •ν•˜μ—¬ /transaction κ²½λ‘œμ—μ„œ λ“€μ–΄μ˜€λŠ” μš”μ²­μ„ μ²˜λ¦¬ν•©λ‹ˆλ‹€. μš”μ²­ νŒŒλΌλ―Έν„°λ₯Ό 읽고, μœ νš¨μ„±μ„ κ²€μ‚¬ν•œ ν›„, νŠΈλžœμž­μ…˜ 데이터λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. 성곡적인 처리 ν›„μ—λŠ” νŠΈλžœμž­μ…˜ 데이터λ₯Ό λ°˜ν™˜ν•˜κ³ , μ‹€νŒ¨ν•˜λ©΄ 였λ₯˜ λ©”μ‹œμ§€λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. 각 ν•¨μˆ˜μ™€ λ©”μ„œλ“œλŠ” νŠΉμ • 역할을 μˆ˜ν–‰ν•˜λ©°, μ „μ²΄μ μœΌλ‘œ ν˜‘λ ₯ν•˜μ—¬ μš”μ²­μ„ μ²˜λ¦¬ν•˜κ³  응닡을 λ°˜ν™˜ν•©λ‹ˆλ‹€.

Last updated