Use public key in transactions
This commit is contained in:
parent
cb1776224e
commit
92be537fcd
|
@ -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
4
cli.go
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
|
Loading…
Reference in New Issue