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
func (bc *Blockchain) FindUnspentTransactions(address string) []Transaction {
func (bc *Blockchain) FindUnspentTransactions(pubKeyHash []byte) []Transaction {
var unspentTXs []Transaction
spentTXOs := make(map[string][]int)
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)
}
}
if tx.IsCoinbase() == false {
for _, in := range tx.Vin {
if in.CanUnlockOutputWith(address) {
if in.UnlocksOutputWith(pubKeyHash) {
inTxID := hex.EncodeToString(in.Txid)
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
func (bc *Blockchain) FindUTXO(address string) []TXOutput {
func (bc *Blockchain) FindUTXO(pubKeyHash []byte) []TXOutput {
var UTXOs []TXOutput
unspentTransactions := bc.FindUnspentTransactions(address)
unspentTransactions := bc.FindUnspentTransactions(pubKeyHash)
for _, tx := range unspentTransactions {
for _, out := range tx.Vout {
if out.CanBeUnlockedWith(address) {
if out.Unlock(pubKeyHash) {
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
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)
unspentTXs := bc.FindUnspentTransactions(address)
unspentTXs := bc.FindUnspentTransactions(pubKeyHash)
accumulated := 0
Work:
@ -133,7 +133,7 @@ Work:
txID := hex.EncodeToString(tx.ID)
for outIdx, out := range tx.Vout {
if out.CanBeUnlockedWith(address) && accumulated < amount {
if out.Unlock(pubKeyHash) && accumulated < amount {
accumulated += out.Value
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()
balance := 0
UTXOs := bc.FindUTXO(address)
pubKeyHash := Base58Decode([]byte(address))
pubKeyHash = pubKeyHash[1 : len(pubKeyHash)-4]
UTXOs := bc.FindUTXO(pubKeyHash)
for _, out := range UTXOs {
balance += out.Value

View File

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