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
|
// 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
4
cli.go
|
@ -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
|
||||||
|
|
|
@ -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}
|
||||||
|
|
Loading…
Reference in New Issue