|
|
|
@ -4,6 +4,8 @@ import ( |
|
|
|
|
"bytes" |
|
|
|
|
"crypto/sha256" |
|
|
|
|
"encoding/gob" |
|
|
|
|
"encoding/hex" |
|
|
|
|
"fmt" |
|
|
|
|
"log" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
@ -14,19 +16,24 @@ type Transaction struct { |
|
|
|
|
txOutput []TXOutput |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TXOutput is the struct of transaction output in a transaction.
|
|
|
|
|
type TXOutput struct { |
|
|
|
|
address string |
|
|
|
|
value int |
|
|
|
|
address string |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TXInput is the struct of transaction input in a transaction.
|
|
|
|
|
type TXInput struct { |
|
|
|
|
txId []byte |
|
|
|
|
txID []byte |
|
|
|
|
txOutputIndex int |
|
|
|
|
address string |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// defaultCoinbaseValue is the default value of coinbase transaction.
|
|
|
|
|
const defaultCoinbaseValue = 10 |
|
|
|
|
|
|
|
|
|
// SetID sets ID of a transaction
|
|
|
|
|
func (tx *Transaction) SetId() { |
|
|
|
|
func (tx *Transaction) SetID() { |
|
|
|
|
var encoded bytes.Buffer |
|
|
|
|
var hash [32]byte |
|
|
|
|
|
|
|
|
@ -36,5 +43,55 @@ func (tx *Transaction) SetId() { |
|
|
|
|
log.Panic(err) |
|
|
|
|
} |
|
|
|
|
hash = sha256.Sum256(encoded.Bytes()) |
|
|
|
|
tx.ID = hash[:] |
|
|
|
|
tx.id = hash[:] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// NewCoinbaseTX creates a new coinbase transaction
|
|
|
|
|
func NewCoinbaseTX(to, data string) *Transaction { |
|
|
|
|
if data == "" { |
|
|
|
|
data = fmt.Sprintf("Reward to '%s'", to) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
txin := TXInput{[]byte{}, -1, data} |
|
|
|
|
txout := TXOutput{defaultCoinbaseValue, to} |
|
|
|
|
tx := Transaction{nil, []TXInput{txin}, []TXOutput{txout}} |
|
|
|
|
tx.SetID() |
|
|
|
|
|
|
|
|
|
return &tx |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// NewUTXOTransaction creates a new transaction
|
|
|
|
|
func NewUTXOTransaction(from, to string, amount int, bc *Blockchain) *Transaction { |
|
|
|
|
var inputs []TXInput |
|
|
|
|
var outputs []TXOutput |
|
|
|
|
|
|
|
|
|
acc, validOutputs := bc.FindSpendableOutputs(from, amount) |
|
|
|
|
|
|
|
|
|
if acc < amount { |
|
|
|
|
log.Panic("ERROR: Not enough funds") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Build a list of inputs
|
|
|
|
|
for txid, outs := range validOutputs { |
|
|
|
|
txID, err := hex.DecodeString(txid) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Panic(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for _, out := range outs { |
|
|
|
|
input := TXInput{txID, out, from} |
|
|
|
|
inputs = append(inputs, input) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Build a list of outputs
|
|
|
|
|
outputs = append(outputs, TXOutput{amount, to}) |
|
|
|
|
if acc > amount { |
|
|
|
|
outputs = append(outputs, TXOutput{acc - amount, from}) // a change
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
tx := Transaction{nil, inputs, outputs} |
|
|
|
|
tx.SetID() |
|
|
|
|
|
|
|
|
|
return &tx |
|
|
|
|
} |
|
|
|
|