package blockchain import ( "bytes" "crypto/sha256" "encoding/gob" "encoding/hex" "fmt" "log" ) // Transaction represents a Bitcoin transaction type Transaction struct { ID []byte TxInput []TXInput TxOutput []TXOutput } // TXOutput is the struct of transaction output in a transaction. type TXOutput struct { Value int Address string } // TXInput is the struct of transaction input in a transaction. type TXInput struct { TxID []byte TxOutputIndex int Address string } // DefaultCoinbaseValue is the default value of coinbase transaction. const DefaultCoinbaseValue = 1000 // SetID sets ID of a transaction func (tx *Transaction) SetID() { var encoded bytes.Buffer var hash [32]byte enc := gob.NewEncoder(&encoded) err := enc.Encode(tx) if err != nil { log.Panic(err) } hash = sha256.Sum256(encoded.Bytes()) 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 { return nil } // Build a list of inputs for txid, outs := range validOutputs { txID, err := hex.DecodeString(txid) if err != nil { return nil } 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 }