Build a Mini Blockchain in Go: Transaction Design, Mempool, and Block Validation
This tutorial walks through extending a Go mini‑blockchain with transaction structures, hashing, signatures, a mempool, block verification, proof‑of‑work consensus, mining rewards, and a balance‑query example, providing complete source code for each step.
1. Transaction Design
Define a transaction struct with fields for a unique hash (ID), sender address (From), receiver address (To), amount, and a signature. The hash is computed with SHA‑256 over the concatenated sender, receiver and amount. The Sign method uses an ECDSA private key to generate a signature and stores it in the transaction.
type Transaction struct {
ID []byte
From string
To string
Amount float64
Signature []byte
}
func HashTransaction(tx Transaction) []byte {
data := tx.From + "|" + tx.To + "|" + strconv.FormatFloat(tx.Amount, 'f', -1, 64)
h := sha256.Sum256([]byte(data))
return h[:]
}
func (tx *Transaction) Sign(privKey *ecdsa.PrivateKey) error {
tx.ID = HashTransaction(*tx)
r, s, err := ecdsa.Sign(rand.Reader, privKey, tx.ID)
if err != nil {
return err
}
tx.Signature = append(r.Bytes(), s.Bytes()...)
return nil
}2. Mempool
A simple in‑memory pool stores pending transactions. Mining nodes retrieve transactions from this pool when constructing a new block.
type TxPool struct {
Transactions []*Transaction
}
func (p *TxPool) AddTransaction(tx *Transaction) {
p.Transactions = append(p.Transactions, tx)
}3. Block Structure and Transaction Verification
The block structure is extended to include a slice of transaction IDs (or full transactions). When a block is added, each transaction is verified for a valid signature and basic business rules such as sufficient balance.
type Block struct {
Index int `json:"index"`
Timestamp int64 `json:"timestamp"`
Transactions []string `json:"transactions"` // transaction IDs
PrevHash string `json:"prev_hash"`
Nonce int64 `json:"nonce"`
Hash string `json:"hash"`
}Verification extracts the sender’s public key from the From field (assumed to be a hex‑encoded elliptic‑curve point), decodes the signature, recomputes the transaction hash and calls ecdsa.VerifyASN1.
func VerifyTransaction(tx Transaction) bool {
pubBytes, err := hex.DecodeString(tx.From)
if err != nil {
return false
}
x, y := elliptic.Unmarshal(elliptic.P256(), pubBytes)
if x == nil {
return false
}
pub := ecdsa.PublicKey{Curve: elliptic.P256(), X: x, Y: y}
sigBytes, err := hex.DecodeString(tx.Signature)
if err != nil {
return false
}
h := HashTransaction(tx)
return ecdsa.VerifyASN1(&pub, h, sigBytes)
}4. Consensus (Proof‑of‑Work)
Nodes use a PoW algorithm with a difficulty target defined by a required prefix of zero bits. The longest valid chain is accepted as the canonical chain.
func AddBlock(b Block) bool {
chainMutex.Lock()
defer chainMutex.Unlock()
last := blockchain[len(blockchain)-1]
if b.PrevHash != last.Hash {
return false
}
if CalculateHash(b) != b.Hash {
return false
}
if !strings.HasPrefix(b.Hash, strings.Repeat("0", difficulty)) {
return false
}
blockchain = append(blockchain, b)
return true
}5. Mining Reward (Coinbase Transaction)
A special transaction with no inputs creates new coins for the miner. It is identified by a Txid of "0" and a Vout of –1.
func CoinbaseTx(coinbaseData, to string, amount int) UTXOTx {
inputs := []TxInput{{
Txid: "0",
Vout: -1,
Signature: coinbaseData,
PubKey: "coinbase",
}}
outputs := []TxOutput{{
Address: to,
Amount: amount,
}}
return UTXOTx{Inputs: inputs, Outputs: outputs}
}6. Balance Query Example
Iterate over all blocks and their transactions, subtracting amounts sent from the address and adding amounts received.
func (bc *Blockchain) GetBalance(address string) float64 {
var balance float64
for _, block := range bc.Blocks {
for _, tx := range block.Transactions {
if tx.From == address {
balance -= tx.Amount
}
if tx.To == address {
balance += tx.Amount
}
}
}
return balance
}7. Summary of Implemented Features
Transaction struct with hashing and ECDSA signing.
In‑memory mempool for pending transactions.
Block format extended to store transaction IDs and verification logic.
Proof‑of‑Work consensus with longest‑chain rule.
Coinbase transaction for mining rewards.
Simple balance calculation based on transaction history.
Source code repositories (for reference):
https://github.com/louis-xie-programmer/mini_chain
https://gitee.com/louis_xie/mini_chain
Code Wrench
Focuses on code debugging, performance optimization, and real-world engineering, sharing efficient development tips and pitfall guides. We break down technical challenges in a down-to-earth style, helping you craft handy tools so every line of code becomes a problem‑solving weapon. 🔧💻
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
