Use public key in transactions

This commit is contained in:
Ivan Kuznetsov 2017-09-08 11:31:34 +07:00
parent cb1776224e
commit 92be537fcd
3 changed files with 53 additions and 27 deletions

View File

@ -61,7 +61,7 @@ func (bc *Blockchain) MineBlock(transactions []*Transaction) {
} }
// FindUnspentTransactions returns a list of transactions containing unspent outputs // FindUnspentTransactions returns a list of transactions containing unspent outputs
func (bc *Blockchain) FindUnspentTransactions(address string) []Transaction { func (bc *Blockchain) FindUnspentTransactions(pubKeyHash []byte) []Transaction {
var unspentTXs []Transaction var unspentTXs []Transaction
spentTXOs := make(map[string][]int) spentTXOs := make(map[string][]int)
bci := bc.Iterator() bci := bc.Iterator()
@ -83,14 +83,14 @@ func (bc *Blockchain) FindUnspentTransactions(address string) []Transaction {
} }
} }
if out.CanBeUnlockedWith(address) { if out.Unlock(pubKeyHash) {
unspentTXs = append(unspentTXs, *tx) unspentTXs = append(unspentTXs, *tx)
} }
} }
if tx.IsCoinbase() == false { if tx.IsCoinbase() == false {
for _, in := range tx.Vin { for _, in := range tx.Vin {
if in.CanUnlockOutputWith(address) { if in.UnlocksOutputWith(pubKeyHash) {
inTxID := hex.EncodeToString(in.Txid) inTxID := hex.EncodeToString(in.Txid)
spentTXOs[inTxID] = append(spentTXOs[inTxID], in.Vout) spentTXOs[inTxID] = append(spentTXOs[inTxID], in.Vout)
} }
@ -107,13 +107,13 @@ func (bc *Blockchain) FindUnspentTransactions(address string) []Transaction {
} }
// FindUTXO finds and returns all unspent transaction outputs // FindUTXO finds and returns all unspent transaction outputs
func (bc *Blockchain) FindUTXO(address string) []TXOutput { func (bc *Blockchain) FindUTXO(pubKeyHash []byte) []TXOutput {
var UTXOs []TXOutput var UTXOs []TXOutput
unspentTransactions := bc.FindUnspentTransactions(address) unspentTransactions := bc.FindUnspentTransactions(pubKeyHash)
for _, tx := range unspentTransactions { for _, tx := range unspentTransactions {
for _, out := range tx.Vout { for _, out := range tx.Vout {
if out.CanBeUnlockedWith(address) { if out.Unlock(pubKeyHash) {
UTXOs = append(UTXOs, out) UTXOs = append(UTXOs, out)
} }
} }
@ -123,9 +123,9 @@ func (bc *Blockchain) FindUTXO(address string) []TXOutput {
} }
// FindSpendableOutputs finds and returns unspent outputs to reference in inputs // FindSpendableOutputs finds and returns unspent outputs to reference in inputs
func (bc *Blockchain) FindSpendableOutputs(address string, amount int) (int, map[string][]int) { func (bc *Blockchain) FindSpendableOutputs(pubKeyHash []byte, amount int) (int, map[string][]int) {
unspentOutputs := make(map[string][]int) unspentOutputs := make(map[string][]int)
unspentTXs := bc.FindUnspentTransactions(address) unspentTXs := bc.FindUnspentTransactions(pubKeyHash)
accumulated := 0 accumulated := 0
Work: Work:
@ -133,7 +133,7 @@ Work:
txID := hex.EncodeToString(tx.ID) txID := hex.EncodeToString(tx.ID)
for outIdx, out := range tx.Vout { for outIdx, out := range tx.Vout {
if out.CanBeUnlockedWith(address) && accumulated < amount { if out.Unlock(pubKeyHash) && accumulated < amount {
accumulated += out.Value accumulated += out.Value
unspentOutputs[txID] = append(unspentOutputs[txID], outIdx) unspentOutputs[txID] = append(unspentOutputs[txID], outIdx)

4
cli.go
View File

@ -30,7 +30,9 @@ func (cli *CLI) getBalance(address string) {
defer bc.db.Close() defer bc.db.Close()
balance := 0 balance := 0
UTXOs := bc.FindUTXO(address) pubKeyHash := Base58Decode([]byte(address))
pubKeyHash = pubKeyHash[1 : len(pubKeyHash)-4]
UTXOs := bc.FindUTXO(pubKeyHash)
for _, out := range UTXOs { for _, out := range UTXOs {
balance += out.Value balance += out.Value

View File

@ -3,6 +3,7 @@ package main
import ( import (
"bytes" "bytes"
"crypto/sha256" "crypto/sha256"
"encoding/gob" "encoding/gob"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
@ -34,13 +35,13 @@ func (tx Transaction) String() string {
lines = append(lines, fmt.Sprintf(" Input %d:", i)) lines = append(lines, fmt.Sprintf(" Input %d:", i))
lines = append(lines, fmt.Sprintf(" TXID: %x", input.Txid)) lines = append(lines, fmt.Sprintf(" TXID: %x", input.Txid))
lines = append(lines, fmt.Sprintf(" Out: %d", input.Vout)) lines = append(lines, fmt.Sprintf(" Out: %d", input.Vout))
lines = append(lines, fmt.Sprintf(" Script: %s", input.ScriptSig)) lines = append(lines, fmt.Sprintf(" Script: %x", input.ScriptSig))
} }
for i, output := range tx.Vout { for i, output := range tx.Vout {
lines = append(lines, fmt.Sprintf(" Output %d:", i)) lines = append(lines, fmt.Sprintf(" Output %d:", i))
lines = append(lines, fmt.Sprintf(" Value: %d", output.Value)) lines = append(lines, fmt.Sprintf(" Value: %d", output.Value))
lines = append(lines, fmt.Sprintf(" Script: %s", output.ScriptPubKey)) lines = append(lines, fmt.Sprintf(" Script: %x", output.ScriptPubKey))
} }
return strings.Join(lines, "\n") return strings.Join(lines, "\n")
@ -64,23 +65,40 @@ func (tx *Transaction) SetID() {
type TXInput struct { type TXInput struct {
Txid []byte Txid []byte
Vout int Vout int
ScriptSig string ScriptSig []byte
} }
// TXOutput represents a transaction output // TXOutput represents a transaction output
type TXOutput struct { type TXOutput struct {
Value int Value int
ScriptPubKey string ScriptPubKey []byte
} }
// CanUnlockOutputWith checks whether the address initiated the transaction // UnlocksOutputWith checks whether the address initiated the transaction
func (in *TXInput) CanUnlockOutputWith(unlockingData string) bool { func (in *TXInput) UnlocksOutputWith(pubKeyHash []byte) bool {
return in.ScriptSig == unlockingData lockingHash := HashPubKey(in.ScriptSig)
return bytes.Compare(lockingHash, pubKeyHash) == 0
} }
// CanBeUnlockedWith checks if the output can be unlocked with the provided data // Lock signs the output
func (out *TXOutput) CanBeUnlockedWith(unlockingData string) bool { func (out *TXOutput) Lock(address []byte) {
return out.ScriptPubKey == unlockingData pubKeyHash := Base58Decode(address)
pubKeyHash = pubKeyHash[1 : len(pubKeyHash)-4]
out.ScriptPubKey = pubKeyHash
}
// Unlock checks if the output can be used by the owner of the pubkey
func (out *TXOutput) Unlock(pubKeyHash []byte) bool {
return bytes.Compare(out.ScriptPubKey, pubKeyHash) == 0
}
// NewTXOutput create a new TXOutput
func NewTXOutput(value int, address string) *TXOutput {
txo := &TXOutput{value, nil}
txo.Lock([]byte(address))
return txo
} }
// NewCoinbaseTX creates a new coinbase transaction // NewCoinbaseTX creates a new coinbase transaction
@ -89,9 +107,9 @@ func NewCoinbaseTX(to, data string) *Transaction {
data = fmt.Sprintf("Reward to '%s'", to) data = fmt.Sprintf("Reward to '%s'", to)
} }
txin := TXInput{[]byte{}, -1, data} txin := TXInput{[]byte{}, -1, []byte(data)}
txout := TXOutput{subsidy, to} txout := NewTXOutput(subsidy, to)
tx := Transaction{nil, []TXInput{txin}, []TXOutput{txout}} tx := Transaction{nil, []TXInput{txin}, []TXOutput{*txout}}
tx.SetID() tx.SetID()
return &tx return &tx
@ -102,7 +120,13 @@ func NewUTXOTransaction(from, to string, amount int, bc *Blockchain) *Transactio
var inputs []TXInput var inputs []TXInput
var outputs []TXOutput var outputs []TXOutput
acc, validOutputs := bc.FindSpendableOutputs(from, amount) wallets, err := NewWallets()
if err != nil {
log.Panic(err)
}
wallet := wallets.GetWallet(from)
pubKeyHash := HashPubKey(wallet.PublicKey)
acc, validOutputs := bc.FindSpendableOutputs(pubKeyHash, amount)
if acc < amount { if acc < amount {
log.Panic("ERROR: Not enough funds") log.Panic("ERROR: Not enough funds")
@ -116,15 +140,15 @@ func NewUTXOTransaction(from, to string, amount int, bc *Blockchain) *Transactio
} }
for _, out := range outs { for _, out := range outs {
input := TXInput{txID, out, from} input := TXInput{txID, out, wallet.PublicKey}
inputs = append(inputs, input) inputs = append(inputs, input)
} }
} }
// Build a list of outputs // Build a list of outputs
outputs = append(outputs, TXOutput{amount, to}) outputs = append(outputs, *NewTXOutput(amount, to))
if acc > amount { if acc > amount {
outputs = append(outputs, TXOutput{acc - amount, from}) // a change outputs = append(outputs, *NewTXOutput(acc-amount, from)) // a change
} }
tx := Transaction{nil, inputs, outputs} tx := Transaction{nil, inputs, outputs}